📎 AI Summary:
The thread discusses a user experiencing access violations when iterating through SCSI HDDs using DeviceIoControl with IOCTL_SCSI_MINIPORT. After troubleshooting, the user discovers that combining input and output buffers into a single buffer size and passing the same buffer for both in and out parameters resolves the issue, allowing effective retrieval of firmware slot information. The overall sentiment is one of problem-solving and sharing a specific buffer management solution to address null or unpredictable iteration results.

ExylonFiber

Well-Known Member
Joined
Apr 25, 2020
Messages
26
Thread Author #1
I am getting an access violation when iterating through SCSI HDD's. I'm sure I'm doing something that needs a minor tweak to get it to work properly. Anyone have any ideas on why I'm getting an access violation every time?

Code:
HANDLE handle = CreateFile("\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);


    PUCHAR inBuffer[sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK)];
    PUCHAR outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK) + sizeof(STORAGE_FIRMWARE_SLOT_INFO)];
    DWORD outBufferLength = sizeof(outBuffer);
    DWORD inBufferLength = sizeof(inBuffer);
    BOOL    result;
    ULONG   returnedLength;
    ULONG   firmwareInfoOffset;


    memset(&inBuffer, 0, sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK));


    PSRB_IO_CONTROL         srbControl;
    std::cout << "srbControl size: " << sizeof(SRB_IO_CONTROL) << "\n";
    PFIRMWARE_REQUEST_BLOCK firmwareRequest;
    PSTORAGE_FIRMWARE_INFO  firmwareInfo; //Define Structure for Firmware Info


    srbControl = (PSRB_IO_CONTROL)inBuffer;
    firmwareRequest = (PFIRMWARE_REQUEST_BLOCK)(srbControl + 1);


  
    //The STORAGE_FIRMWARE_INFO is located after SRB_IO_CONTROL and FIRMWARE_REQUEST_BLOCK
    
    firmwareInfoOffset = ((sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK) - 1) / sizeof(PVOID) + 1) * sizeof(PVOID);


    //
    // Setup the SRB control with the firmware ioctl control info
    //
    srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
    srbControl->ControlCode = IOCTL_SCSI_MINIPORT_FIRMWARE;
    RtlMoveMemory(srbControl->Signature, IOCTL_MINIPORT_SIGNATURE_FIRMWARE, 8);
    srbControl->Timeout = 30;
    srbControl->Length = inBufferLength - sizeof(SRB_IO_CONTROL);


    //
    // Set firmware request fields for FIRMWARE_FUNCTION_GET_INFO. This request is to the controller so
    // FIRMWARE_REQUEST_FLAG_CONTROLLER is set in the flags
    //
    firmwareRequest->Version = FIRMWARE_REQUEST_BLOCK_STRUCTURE_VERSION;
    firmwareRequest->Size = sizeof(FIRMWARE_REQUEST_BLOCK);
    firmwareRequest->Function = FIRMWARE_FUNCTION_GET_INFO;
    firmwareRequest->Flags = FIRMWARE_REQUEST_FLAG_CONTROLLER;
    firmwareRequest->DataBufferOffset = firmwareInfoOffset;
    firmwareRequest->DataBufferLength = inBufferLength - firmwareInfoOffset;


    //
    // Send the request to get the device firmware info
    //


    result = DeviceIoControl(handle,
        IOCTL_SCSI_MINIPORT,
        inBuffer,
        inBufferLength,
        outBuffer,
        outBufferLength,
        &returnedLength,
        NULL
    );
    std::cout << "Returned Length: " << returnedLength << "\n";
    std::cout << "result: " << result << "\n";


    //
    // Format and display the firmware info
    //


    if (result != 0) {
        if (!result) {
            _tprintf(_T("\t Get Firmware Information Failed: 0x%X\n"), GetLastError());
        }
        else {
            UCHAR   i;
            TCHAR   revision[16] = { 0 };


            firmwareInfo = (PSTORAGE_FIRMWARE_INFO)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);


            _tprintf(_T("\t ----Firmware Information----\n"));
            _tprintf(_T("\t Support upgrade command: %s\n"), firmwareInfo->UpgradeSupport ? _T("Yes") : _T("No"));
            _tprintf(_T("\t Slot Count: %d\n"), firmwareInfo->SlotCount);
            _tprintf(_T("\t FWVersion: ")); std::cout << firmwareInfo->Version << "\n";
            _tprintf(_T("\t Current Active Slot: %d\n"), firmwareInfo->ActiveSlot);


            if (firmwareInfo->PendingActivateSlot == STORAGE_FIRMWARE_INFO_INVALID_SLOT) {
                _tprintf(_T("\t Pending Active Slot: %s\n\n"), _T("No"));
            }
            else {
                _tprintf(_T("\t Pending Active Slot: %d\n\n"), firmwareInfo->PendingActivateSlot);
            }


            for (i = 0; i < firmwareInfo->SlotCount; i++) {
                RtlCopyMemory(revision, &firmwareInfo->Slot[i].Revision.AsUlonglong, 8);


                _tprintf(_T("\t\t Slot Number: %d\n"), firmwareInfo->Slot[i].SlotNumber);
                _tprintf(_T("\t\t Slot Read Only: %s\n"), firmwareInfo->Slot[i].ReadOnly ? _T("Yes") : _T("No"));
                _tprintf(_T("\t\t Revision: %s\n"), revision);
                _tprintf(_T("\n"));
            }
        }


        _tprintf(_T("\n"));
    }
    CloseHandle(handle);
 

Solution
I figured it out! By setting ONE BUFFER big enough for BOTH IN and OUT operations of the IOCTL_SCSI_MINIPORT as listed below:

Code:
PUCHAR Buffer[sizeof(FIRMWARE_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(STORAGE_FIRMWARE_INFO)];

And setting the DeviceIoControl Function to use the same buffer for both in and out:

Code:
result = DeviceIoControl(hDevice,
        IOCTL_SCSI_MINIPORT,
        Buffer,
        BufferLength,
        Buffer,
        BufferLength,
        &returnedLength,
        NULL
    );

It effectively found only the active slot I specified (0 for the first SSD, 1 for the second SSD)

ExylonFiber

Well-Known Member
Joined
Apr 25, 2020
Messages
26
Thread Author #2
Here is the output:
An image from 'Access Violation When Iterating Through SCSI Slots'. The images show a read-only slot configuration and an access violation error in an NVMe firmware updater.



And the error:
An image from 'Access Violation When Iterating Through SCSI Slots'. The images show a read-only slot configuration and an access violation error in an NVMe firmware updater.
 

Last edited by a moderator:

ExylonFiber

Well-Known Member
Joined
Apr 25, 2020
Messages
26
Thread Author #3
It would seem that the for-loop is not counting slots incrementally and just doing it in a random order. Particularly strange.
 

ExylonFiber

Well-Known Member
Joined
Apr 25, 2020
Messages
26
Thread Author #4
I figured it out! By setting ONE BUFFER big enough for BOTH IN and OUT operations of the IOCTL_SCSI_MINIPORT as listed below:

Code:
PUCHAR Buffer[sizeof(FIRMWARE_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(STORAGE_FIRMWARE_INFO)];

And setting the DeviceIoControl Function to use the same buffer for both in and out:

Code:
result = DeviceIoControl(hDevice,
        IOCTL_SCSI_MINIPORT,
        Buffer,
        BufferLength,
        Buffer,
        BufferLength,
        &returnedLength,
        NULL
    );

It effectively found only the active slot I specified (0 for the first SSD, 1 for the second SSD)
 

Solution