private SCSIStatusCodeName ReportLUNs(out byte[] response) { uint bytesReturned; uint outBufferLength = 4096; IntPtr outBuffer = Marshal.AllocHGlobal((int)outBufferLength); SCSIStatusCodeName status; if (!DeviceIoControl(m_handle, IOCTL_SCSI_GET_INQUIRY_DATA, IntPtr.Zero, 0, outBuffer, outBufferLength, out bytesReturned, IntPtr.Zero)) { Win32Error lastError = (Win32Error)Marshal.GetLastWin32Error(); Log(Severity.Error, "DeviceIoControl/IOCTL_SCSI_GET_INQUIRY_DATA error: {0}, Device path: {1}", lastError, m_path); response = VirtualSCSITarget.FormatSenseData(SenseDataParameter.GetIllegalRequestUnsupportedCommandCodeSenseData()); status = SCSIStatusCodeName.CheckCondition; } else { List <SCSI_INQUIRY_DATA> devices = SCSI_ADAPTER_BUS_INFO.GetInquiryDataForAllDevices(outBuffer); ReportLUNsParameter parameter = new ReportLUNsParameter(); foreach (SCSI_INQUIRY_DATA device in devices) { // If the device has been claimed by a class driver then passthrough IOCTLs must go through the class driver if (!device.DeviceClaimed) { PeripheralDeviceType deviceType = (PeripheralDeviceType)(device.InquiryData[0] & 0x1F); if (deviceType == PeripheralDeviceType.DirectAccessBlockDevice | deviceType == PeripheralDeviceType.SequentialAccessDevice | deviceType == PeripheralDeviceType.CDRomDevice) { byte?associatedLUN = m_logicalUnitManager.FindAssociatedLUN(device.PathId, device.TargetId, device.Lun); if (!associatedLUN.HasValue) { associatedLUN = m_logicalUnitManager.FindUnusedLUN(); LogicalUnit logicalUnit = new LogicalUnit(); logicalUnit.AssociatedLun = associatedLUN.Value; logicalUnit.PathId = device.PathId; logicalUnit.TargetId = device.TargetId; logicalUnit.TargetLun = device.Lun; logicalUnit.DeviceType = deviceType; m_logicalUnitManager.AddLogicalUnit(logicalUnit); Log(Severity.Verbose, "Assigned virtual LUN {0} to device PathId: {1}, TargetId: {2}, LUN: {3}", associatedLUN.Value, device.PathId, device.TargetId, device.Lun); } if (!associatedLUN.HasValue) { throw new NotImplementedException("The maximum number of LUNs supported has been reached"); } parameter.LUNList.Add(associatedLUN.Value); } } } response = parameter.GetBytes(); Log(Severity.Verbose, "DeviceIoControl/IOCTL_SCSI_GET_INQUIRY_DATA reported {0} usable devices", parameter.LUNList.Count); status = SCSIStatusCodeName.Good; } Marshal.FreeHGlobal(outBuffer); return(status); }
public static SCSI_ADAPTER_BUS_INFO FromIntPtr(IntPtr ptr) { SCSI_ADAPTER_BUS_INFO busInfo = new SCSI_ADAPTER_BUS_INFO(); byte numberOfBuses = Marshal.ReadByte(ptr); ptr = new IntPtr(ptr.ToInt64() + 4); busInfo.NumberOfBuses = numberOfBuses; busInfo.BusData = new SCSI_BUS_DATA[numberOfBuses]; for (int index = 0; index < numberOfBuses; index++) { busInfo.BusData[index] = (SCSI_BUS_DATA)Marshal.PtrToStructure(ptr, typeof(SCSI_BUS_DATA)); ptr = new IntPtr(ptr.ToInt64() + Marshal.SizeOf(typeof(SCSI_BUS_DATA))); } return(busInfo); }
public static List <SCSI_INQUIRY_DATA> GetInquiryDataForAllDevices(IntPtr busInfoPtr) { SCSI_ADAPTER_BUS_INFO busInfo = FromIntPtr(busInfoPtr); List <SCSI_INQUIRY_DATA> devices = new List <SCSI_INQUIRY_DATA>(); foreach (SCSI_BUS_DATA busData in busInfo.BusData) { byte numberOfLuns = busData.NumberOfLogicalUnits; uint inquiryDataOffset = busData.InquiryDataOffset; for (int lunIndex = 0; lunIndex < numberOfLuns; lunIndex++) { IntPtr inquiryDataPtr = new IntPtr(busInfoPtr.ToInt64() + inquiryDataOffset); SCSI_INQUIRY_DATA inquiryData = SCSI_INQUIRY_DATA.FromIntPtr(inquiryDataPtr); devices.Add(inquiryData); inquiryDataOffset = inquiryData.NextInquiryDataOffset; } } return(devices); }