// get relevant values from PDU/CDB
BasicHeaderSegment bhs = pdu.getBasicHeaderSegment();
SCSICommandParser parser = (SCSICommandParser) bhs.getParser();
final int initiatorTaskTag = bhs.getInitiatorTaskTag();
WriteCdb cdb;
final ScsiOperationCode scsiOpCode = ScsiOperationCode.valueOf(parser.getCDB().get(0));
if (scsiOpCode == ScsiOperationCode.WRITE_10)
cdb = new Write10Cdb(parser.getCDB());
else if (scsiOpCode == ScsiOperationCode.WRITE_6)
cdb = new Write6Cdb(parser.getCDB());
else {
// anything else wouldn't be good (programmer error)
// close connection
throw new InternetSCSIException("wrong SCSI Operation Code " + scsiOpCode + " in WriteStage");
}
final int transferLength = cdb.getTransferLength();
final long logicalBlockAddress = cdb.getLogicalBlockAddress();
// transform to from block units to byte units
final int transferLengthInBytes = transferLength * VIRTUAL_BLOCK_SIZE;
long storageIndex = logicalBlockAddress * VIRTUAL_BLOCK_SIZE;
// check if requested blocks are out of bounds
// (might add FPSKSD to the CDB's list to be detected in the next step)
checkOverAndUnderflow(cdb);
if (cdb.getIllegalFieldPointers() != null) {
/*
* CDB is invalid, inform initiator by closing the connection. Sending an error status SCSI Response PDU
* will not work reliably, since the initiator may not be expecting a response so soon. Also, if the
* WriteStage is simply left early (without closing the connection), the initiator may send additional
* unsolicited Data-Out PDUs, which the jSCSI Target is currently unable to ignore or process properly.
*/
LOGGER.debug("illegal field in Write CDB");
LOGGER.debug("CDB:\n" + Debug.byteBufferToString(parser.getCDB()));
// Not necessarily close the connection
// create and send error PDU and leave stage
final ProtocolDataUnit responsePdu = createFixedFormatErrorPdu(cdb.getIllegalFieldPointers(),// senseKeySpecificData
initiatorTaskTag, parser.getExpectedDataTransferLength());
connection.sendPdu(responsePdu);
return;
}