package org.jscsi.target.connection.stage.fullfeature; import java.io.IOException; import java.security.DigestException; import org.jscsi.exception.InternetSCSIException; import org.jscsi.parser.BasicHeaderSegment; import org.jscsi.parser.ProtocolDataUnit; import org.jscsi.parser.scsi.SCSICommandParser; import org.jscsi.target.connection.phase.TargetFullFeaturePhase; import org.jscsi.target.scsi.cdb.ModeSense6Cdb; import org.jscsi.target.scsi.modeSense.CachingModePage; import org.jscsi.target.scsi.modeSense.HeaderType; import org.jscsi.target.scsi.modeSense.InformationExceptionsControlModePage; import org.jscsi.target.scsi.modeSense.ModePage; import org.jscsi.target.scsi.modeSense.ModePageCode; import org.jscsi.target.scsi.modeSense.ModeParameterList; import org.jscsi.target.scsi.modeSense.ModeParameterListBuilder; import org.jscsi.target.scsi.modeSense.ShortLogicalBlockDescriptor; import org.jscsi.target.settings.SettingsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A stage for processing <code>MODE SENSE (6)</code> SCSI commands. * * @author Andreas Ergenzinger */ public final class ModeSenseStage extends TargetFullFeatureStage { private static final Logger LOGGER = LoggerFactory.getLogger(ModeSenseStage.class); public ModeSenseStage(TargetFullFeaturePhase targetFullFeaturePhase) { super(targetFullFeaturePhase); } @Override public void execute(final ProtocolDataUnit pdu) throws IOException, InterruptedException, InternetSCSIException, DigestException, SettingsException { final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); final SCSICommandParser parser = (SCSICommandParser)bhs.getParser(); final ModeSense6Cdb cdb = new ModeSense6Cdb(parser.getCDB()); if (LOGGER.isDebugEnabled()) { LOGGER.debug(Boolean.toString(cdb.getDisableBlockDescriptors())); LOGGER.debug(cdb.getPageControl().toString()); LOGGER.debug(Integer.toString(cdb.getPageCode())); LOGGER.debug(Integer.toString(cdb.getSubpageCode())); LOGGER.debug("cdb.getAllocationLength() = " + cdb.getAllocationLength()); // LOGGER.debug(cdb.getModePage()); } // final PageControl pageControl = cdb.getPageControl();//see 8 lines // below final ModePageCode modePageCode = cdb.getModePage(); // ModeParameterList and ModeParameterListBuilder common to // all supported ModePage requests ModePage[] modePages = null; if (modePageCode == ModePageCode.INFORMATIONAL_EXCEPTIONS_CONTROL_MODE_PAGE) { // TODO this should to be made dynamic wrt. cdb.getPageControl(); modePages = new ModePage[] { getInformationExceptionsControlModePage() }; } else if (modePageCode == ModePageCode.CACHING_MODE_PAGE) { modePages = new ModePage[] { getCachingModePage() }; } else if (modePageCode == ModePageCode.RETURN_ALL_MODE_PAGES_ONLY) { modePages = new ModePage[] { getInformationExceptionsControlModePage(), getCachingModePage() }; }// else modeParameterList stays null // create and send response PDU if (modePages != null) { // create ModeParameterList final ModeParameterListBuilder builder = new ModeParameterListBuilder(HeaderType.MODE_PARAMETER_HEADER_6); builder.setLogicalBlockDescriptors(new ShortLogicalBlockDescriptor(session.getStorageModule() .getSizeInBlocks(),// numberOfLogicalBlocks session.getStorageModule().getBlockSize()));// logicalBlockLength builder.setModePages(modePages); ModeParameterList modeParameterList = ModeParameterList.build(builder, session); // send response sendResponse(bhs.getInitiatorTaskTag(),// initiatorTaskTag, parser.getExpectedDataTransferLength(),// expectedDataTransferLength, modeParameterList);// responseData } else { /* * The initiator has requested a mode sense page which the jSCSI * Target cannot provide. * * This could be answered with an Illegal field in CDB message but, * there is no good way to identify the exact field at fault. */ throw new InternetSCSIException(); } } private static final InformationExceptionsControlModePage getInformationExceptionsControlModePage() { return new InformationExceptionsControlModePage(false,// parametersSaveable false,// performance false,// enableBackgroundFunction false,// enableWarning true,// disableExceptionControl false,// test false,// logErrors 0x0,// methodOfReportingInformationalExceptionConditions 0,// intervalTimer 0);// reportCount } private static final CachingModePage getCachingModePage() { return new CachingModePage(false,// parametersSaveable false,// initiatorControl true,// abortPrefetch false,// cachingAnalysisPermitted false,// discontinuity true,// sizeEnable false,// writebackCacheEnable false,// multiplicationFactor true,// readCacheDisable 0x0,// demandReadRetentionPriority 0x0,// writeRetentionPriority 0,// disablePrefetchTransferLength 0,// minimumPrefetch 65535,// maximumPrefetch 65535,// maximumPrefetchCeiling true,// forceSequentialWrite false,// logicalBlockCacheSegmentSize false,// disableReadAhead false,// nonVolatileCacheDisabled 20,// numberOfCacheSegments 0);// cacheSegmentSize } public boolean canHandle(final ProtocolDataUnit pdu) { final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); final SCSICommandParser parser = (SCSICommandParser)bhs.getParser(); final ModeSense6Cdb cdb = new ModeSense6Cdb(parser.getCDB()); final ModePageCode modePageCode = cdb.getModePage(); if (modePageCode == ModePageCode.INFORMATIONAL_EXCEPTIONS_CONTROL_MODE_PAGE) { return true; } else if (modePageCode == ModePageCode.CACHING_MODE_PAGE) { return true; } else if (modePageCode == ModePageCode.RETURN_ALL_MODE_PAGES_ONLY) { return true; } else { return false; } } }