/** {@inheritDoc} */ public final void execute() throws InternetSCSIException { final ProtocolDataUnit protocolDataUnit = protocolDataUnitFactory.create( false, true, OperationCode.SCSI_COMMAND, connection.getSetting(OperationalTextKey.HEADER_DIGEST), connection.getSetting(OperationalTextKey.DATA_DIGEST)); final SCSICommandParser scsi = (SCSICommandParser) protocolDataUnit.getBasicHeaderSegment().getParser(); scsi.setReadExpectedFlag(false); scsi.setWriteExpectedFlag(true); scsi.setTaskAttributes(taskAttributes); scsi.setExpectedDataTransferLength(expectedDataTransferLength); final int maxRecvDataSegmentLength = connection.getSettingAsInt(OperationalTextKey.MAX_RECV_DATA_SEGMENT_LENGTH); scsi.setCommandDescriptorBlock( SCSICommandDescriptorBlockParser.createWriteMessage(logicalBlockAddress, transferLength)); final IDataSegment dataSegment = DataSegmentFactory.create( buffer, bufferPosition, expectedDataTransferLength, DataSegmentFormat.BINARY, maxRecvDataSegmentLength); final IDataSegmentIterator iterator = dataSegment.iterator(); int bufferOffset = 0; if (connection.getSettingAsBoolean(OperationalTextKey.IMMEDIATE_DATA)) { final int min = Math.min( maxRecvDataSegmentLength, connection.getSettingAsInt(OperationalTextKey.FIRST_BURST_LENGTH)); protocolDataUnit.setDataSegment(iterator.next(min)); bufferOffset += min; } connection.send(protocolDataUnit); if (!connection.getSettingAsBoolean(OperationalTextKey.INITIAL_R2T) && iterator.hasNext()) { connection.nextState( new WriteFirstBurstState(connection, iterator, 0xFFFFFFFF, 0, bufferOffset)); } else { connection.nextState(new WriteSecondResponseState(connection, iterator, 0, bufferOffset)); } super.stateFollowing = true; // return true; }
@Override public void execute(ProtocolDataUnit pdu) throws IOException, InterruptedException, InternetSCSIException, DigestException, IllegalArgumentException, SettingsException { LOGGER.debug("Entering LOPN Stage"); BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); initiatorTaskTag = bhs.getInitiatorTaskTag(); String keyValuePairProposal = receivePduSequence(pdu); // negotiate parameters, leave if unsuccessful final Vector<String> requestKeyValuePairs = TextParameter.tokenizeKeyValuePairs(keyValuePairProposal); final Vector<String> responseKeyValuePairs = new Vector<String>(); if (!negotiator.negotiate( stageNumber, connection.isLeadingConnection(), ((TargetLoginPhase) targetPhase).getFirstPduAndSetToFalse(), requestKeyValuePairs, responseKeyValuePairs)) { // negotiation failure, no exception sendRejectPdu(LoginStatus.INITIATOR_ERROR); // nextStageNumber = null;//no change return; } // print request and response key value pairs if debugging if (LOGGER.isDebugEnabled()) { final StringBuilder sb = new StringBuilder(); sb.append("request: "); for (String s : requestKeyValuePairs) { sb.append("\n "); sb.append(s); } sb.append("\nresponse: "); for (String s : responseKeyValuePairs) { sb.append("\n "); sb.append(s); } LOGGER.debug(sb.toString()); } // make sure that initiator wants to proceed to FFP, leave if it does // not if (requestedNextStageNumber != LoginStage.FULL_FEATURE_PHASE) { sendRejectPdu(LoginStatus.INITIATOR_ERROR); throw new InternetSCSIException(); } // concatenate key-value pairs to null char-separated string final String keyValuePairReply = TextParameter.concatenateKeyValuePairs(responseKeyValuePairs); // send reply, finish negotiation, and return successfully sendPduSequence(keyValuePairReply, LoginStage.FULL_FEATURE_PHASE); negotiator.finishNegotiation(true); nextStageNumber = LoginStage.FULL_FEATURE_PHASE; }
@Override public void execute(ProtocolDataUnit pdu) throws IOException, InterruptedException, InternetSCSIException, DigestException, SettingsException { LOGGER.debug("Initiator has sent FORMAT UNIT command."); final BasicHeaderSegment bhs = pdu.getBasicHeaderSegment(); final SCSICommandParser parser = (SCSICommandParser) bhs.getParser(); ProtocolDataUnit responsePdu = null; // the response PDU // get command details in CDB final FormatUnitCDB cdb = new FormatUnitCDB(parser.getCDB()); final FieldPointerSenseKeySpecificData[] illegalFieldPointers = cdb.getIllegalFieldPointers(); if (illegalFieldPointers != null) { // an illegal request has been made FixedFormatSenseData senseData = new FixedFormatSenseData( false, // valid ErrorType.CURRENT, // error type false, // file mark false, // end of medium false, // incorrect length indicator SenseKey.ILLEGAL_REQUEST, // sense key new FourByteInformation(), // information new FourByteInformation(), // command specific information AdditionalSenseCodeAndQualifier.INVALID_FIELD_IN_CDB, // additional // sense // code // and // qualifier (byte) 0, // field replaceable unit code illegalFieldPointers[0], // sense key specific data, only // report first problem new AdditionalSenseBytes()); // additional sense bytes responsePdu = TargetPduFactory.createSCSIResponsePdu( false, // bidirectionalReadResidualOverflow false, // bidirectionalReadResidualUnderflow false, // residualOverflow false, // residualUnderflow, SCSIResponseParser.ServiceResponse.COMMAND_COMPLETED_AT_TARGET, // response, SCSIStatus.CHECK_CONDITION, // status, bhs.getInitiatorTaskTag(), // initiatorTaskTag, 0, // snackTag 0, // expectedDataSequenceNumber 0, // bidirectionalReadResidualCount 0, // residualCount new ScsiResponseDataSegment( senseData, parser.getExpectedDataTransferLength())); // data // segment } else { // PDU is okay // carry out command /* * If we were nice, we would have to get (we would actually have to save it first) the number of blocks and * the block length requested by the initiator in the last MODE SENSE command and then change the logical * block layout accordingly. However, since the target is not required by the SCSI standard to make those * changes ("The degree that the medium is altered by this command is vendor specific."), doing nothing is * okay. */ responsePdu = createScsiResponsePdu( SCSIStatus.GOOD, // status bhs.getInitiatorTaskTag(), // initiatorTaskTag, parser.getExpectedDataTransferLength(), // expectedDataTransferLength, 0); // responseDataSize } // send response connection.sendPdu(responsePdu); }