public SCSIStatusCodeName ModeSense6(ModeSense6CommandDescriptorBlock command, LUNStructure lun, out byte[] response) { Log(Severity.Verbose, "ModeSense6: Page code: 0x{0}, Sub page code: 0x{1}", command.PageCode.ToString("X"), command.SubpageCode.ToString("X")); byte[] pageData; switch ((ModePageCodeName)command.PageCode) { case ModePageCodeName.CachingParametersPage: { CachingParametersPage page = new CachingParametersPage(); page.RCD = true; pageData = page.GetBytes(); break; } case ModePageCodeName.ControlModePage: { ControlModePage page = new ControlModePage(); pageData = page.GetBytes(); break; } case ModePageCodeName.PowerConditionModePage: { if (command.SubpageCode == 0x00) { PowerConditionModePage page = new PowerConditionModePage(); pageData = page.GetBytes(); break; } else if (command.SubpageCode == 0x01) { PowerConsumptionModePage page = new PowerConsumptionModePage(); pageData = page.GetBytes(); break; } else { Log(Severity.Error, "ModeSense6: Power condition subpage 0x{0} is not implemented", command.SubpageCode.ToString("x")); response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData()); return(SCSIStatusCodeName.CheckCondition); } } case ModePageCodeName.InformationalExceptionsControlModePage: { InformationalExceptionsControlModePage page = new InformationalExceptionsControlModePage(); pageData = page.GetBytes(); break; } case ModePageCodeName.ReturnAllPages: { CachingParametersPage page1 = new CachingParametersPage(); page1.RCD = true; InformationalExceptionsControlModePage page2 = new InformationalExceptionsControlModePage(); pageData = new byte[page1.Length + page2.Length]; Array.Copy(page1.GetBytes(), pageData, page1.Length); Array.Copy(page2.GetBytes(), 0, pageData, page1.Length, page2.Length); break; } case ModePageCodeName.VendorSpecificPage: { // Windows 2000 will request this page, we immitate Microsoft iSCSI Target by sending back an empty page VendorSpecificPage page = new VendorSpecificPage(); pageData = page.GetBytes(); break; } default: { Log(Severity.Error, "ModeSense6: ModeSense6 page 0x{0} is not implemented", command.PageCode.ToString("x")); response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData()); return(SCSIStatusCodeName.CheckCondition); } } ModeParameterHeader6 header = new ModeParameterHeader6(); header.WP = m_disks[lun].IsReadOnly; // Write protected, even when set to true, Windows does not always prevent the disk from being written to. header.DPOFUA = true; // Microsoft iSCSI Target support this byte[] descriptorBytes = new byte[0]; if (!command.DBD) { ShortLBAModeParameterBlockDescriptor descriptor = new ShortLBAModeParameterBlockDescriptor(); descriptor.LogicalBlockLength = (uint)m_disks[lun].BytesPerSector; descriptorBytes = descriptor.GetBytes(); } header.BlockDescriptorLength = (byte)descriptorBytes.Length; header.ModeDataLength += (byte)(descriptorBytes.Length + pageData.Length); response = new byte[1 + header.ModeDataLength]; Array.Copy(header.GetBytes(), 0, response, 0, header.Length); Array.Copy(descriptorBytes, 0, response, header.Length, descriptorBytes.Length); Array.Copy(pageData, 0, response, header.Length + descriptorBytes.Length, pageData.Length); // we must not return more bytes than ModeSense6Command.AllocationLength if (response.Length > command.AllocationLength) { response = ByteReader.ReadBytes(response, 0, command.AllocationLength); } return(SCSIStatusCodeName.Good); }
public SCSIStatusCodeName Inquiry(InquiryCommand command, LUNStructure lun, out byte[] response) { if (!command.EVPD) { if ((int)command.PageCode == 0) { StandardInquiryData inquiryData = new StandardInquiryData(); inquiryData.PeripheralDeviceType = 0; // Direct access block device inquiryData.VendorIdentification = "TalAloni"; inquiryData.ProductIdentification = "SCSI Disk " + ((ushort)lun).ToString(); inquiryData.ProductRevisionLevel = "1.00"; inquiryData.DriveSerialNumber = 0; inquiryData.CmdQue = true; inquiryData.Version = 5; // SPC-3 NotifyStandardInquiry(this, new StandardInquiryEventArgs(lun, inquiryData)); response = inquiryData.GetBytes(); } else { Log(Severity.Warning, "Initiator error: Invalid Inquiry request"); response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData()); return(SCSIStatusCodeName.CheckCondition); } } else { Log(Severity.Verbose, "Inquiry: Page code: 0x{0}", command.PageCode.ToString("X")); switch (command.PageCode) { case VitalProductDataPageName.SupportedVPDPages: { SupportedVitaLProductDataPages page = new SupportedVitaLProductDataPages(); page.SupportedPageList.Add((byte)VitalProductDataPageName.SupportedVPDPages); page.SupportedPageList.Add((byte)VitalProductDataPageName.UnitSerialNumber); page.SupportedPageList.Add((byte)VitalProductDataPageName.DeviceIdentification); response = page.GetBytes(); break; } case VitalProductDataPageName.UnitSerialNumber: { UnitSerialNumberVPDPage page = new UnitSerialNumberVPDPage(); // Older products that only support the Product Serial Number parameter will have a page length of 08h, while newer products that support both parameters (Vendor Unique field from the StandardInquiryData) will have a page length of 14h // Microsoft iSCSI Target uses values such as "34E5A6FC-3ACC-452D-AEDA-6EE2EFF20FB4" ulong serialNumber = 0; page.ProductSerialNumber = serialNumber.ToString("00000000"); NotifyUnitSerialNumberInquiry(this, new UnitSerialNumberInquiryEventArgs(lun, page)); response = page.GetBytes(); break; } case VitalProductDataPageName.DeviceIdentification: { DeviceIdentificationVPDPage page = new DeviceIdentificationVPDPage(); // NAA identifier is needed to prevent 0xF4 BSOD during Windows setup page.IdentificationDescriptorList.Add(IdentificationDescriptor.GetNAAExtendedIdentifier(5, lun)); NotifyDeviceIdentificationInquiry(this, new DeviceIdentificationInquiryEventArgs(lun, page)); response = page.GetBytes(); break; } case VitalProductDataPageName.BlockLimits: { /* Provide only when requeste explicitly */ BlockLimitsVPDPage page = new BlockLimitsVPDPage(); page.OptimalTransferLengthGranularity = 128; page.MaximumTransferLength = (uint)DiskAccessLibrary.Settings.MaximumTransferSizeLBA; page.OptimalTransferLength = 128; response = page.GetBytes(); break; } case VitalProductDataPageName.BlockDeviceCharacteristics: { /* Provide only when requeste explicitly */ BlockDeviceCharacteristicsVPDPage page = new BlockDeviceCharacteristicsVPDPage(); page.MediumRotationRate = 0; // Not reported response = page.GetBytes(); break; } default: { Log(Severity.Error, "Inquiry: Unsupported VPD Page request (0x{0})", command.PageCode.ToString("X")); response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData()); return(SCSIStatusCodeName.CheckCondition); } } } // we must not return more bytes than InquiryCommand.AllocationLength if (response.Length > command.AllocationLength) { response = ByteReader.ReadBytes(response, 0, command.AllocationLength); } return(SCSIStatusCodeName.Good); }