Example #1
0
        public async Task <InquiryResponse <T> > SendAsync <T>(InquiryCommand <T> inquiry,
                                                               CancellationToken cancellationToken = default)
        {
            CommandTask?commandTask = null;

            // As we're using a bounded queue with limited capacity we can avoid the overhead
            // of creating a command task until there is space
            while (await _commandChannel.Writer.WaitToWriteAsync(cancellationToken).ConfigureAwait(false))
            {
                commandTask ??= new CommandTask(inquiry, cancellationToken);
                if (_commandChannel.Writer.TryWrite(commandTask))
                {
                    // We are queued
                    return((InquiryResponse <T>) await commandTask.TaskCompletionSource.Task.ConfigureAwait(false));
                }
            }

            // Failed to get writer at all
            return((InquiryResponse <T>)inquiry.UnknownResponse);
        }
Example #2
0
        public SCSIStatusCodeName Inquiry(InquiryCommand command, LUNStructure lun, out byte[] response)
        {
            if (lun >= m_disks.Count)
            {
                response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidLUNSenseData());
                return(SCSIStatusCodeName.CheckCondition);
            }

            if (!command.EVPD)
            {
                if ((int)command.PageCode == 0)
                {
                    StandardInquiryData inquiryData = new StandardInquiryData();
                    inquiryData.PeripheralDeviceType  = 0; // Direct access block device
                    inquiryData.VendorIdentification  = "TalAloni";
                    inquiryData.ProductIdentification = "iSCSI Disk " + ((ushort)lun).ToString();
                    inquiryData.ProductRevisionLevel  = "1.00";
                    inquiryData.DriveSerialNumber     = 0;
                    inquiryData.CmdQue  = true;
                    inquiryData.Version = 5; // Microsoft iSCSI Target report version 5
                    if (this is ISCSITarget)
                    {
                        inquiryData.VersionDescriptors.Add(0x0960); // iSCSI
                    }
                    response = inquiryData.GetBytes();
                }
                else
                {
                    ISCSIServer.Log("[Inquiry] Invalid request");
                    response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData());
                    return(SCSIStatusCodeName.CheckCondition);
                }
            }
            else
            {
                ISCSIServer.Log("[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");
                    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));
                    if (this is ISCSITarget)
                    {
                        // ISCSI identifier is needed for WinPE to pick up the disk during boot (after iPXE's sanhook)
                        page.IdentificationDescriptorList.Add(IdentificationDescriptor.GetSCSINameStringIdentifier(((ISCSITarget)this).TargetName));
                    }
                    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:
                {
                    response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidFieldInCDBSenseData());
                    ISCSIServer.Log("[Inquiry] Unsupported VPD Page request (0x{0})", command.PageCode.ToString("X"));
                    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);
        }