VOID
ImScsiStopAdapter(
                  __in pHW_HBA_EXT pHBAExt         // Adapter device-object extension from port driver.
                  )
{
    SRB_IMSCSI_REMOVE_DEVICE rem_data = { 0 };

    KdPrint2(("PhDskMnt::ImScsiStopAdapter:  pHBAExt = 0x%p\n", pHBAExt));

    // Remove all devices, using "wildcard" device number.
    rem_data.DeviceNumber.LongNumber = IMSCSI_ALL_DEVICES;

    ImScsiRemoveDevice(pHBAExt, &rem_data);

    KdPrint2(("PhDskMnt::ImScsiStopAdapter End.\n"));

    return;
}                                                     // End ImScsiStopAdapter().
VOID
ImScsiStopAdapter(
__in pHW_HBA_EXT pHBAExt,         // Adapter device-object extension from port driver.
__inout __deref PKIRQL LowestAssumedIrql
)
{
    DEVICE_NUMBER rem_data;

    KdPrint2(("PhDskMnt::ImScsiStopAdapter:  pHBAExt = 0x%p\n", pHBAExt));

    // Remove all devices, using "wildcard" device number.
    rem_data.LongNumber = IMSCSI_ALL_DEVICES;

    ImScsiRemoveDevice(pHBAExt, &rem_data, LowestAssumedIrql);

    KdPrint2(("PhDskMnt::ImScsiStopAdapter End.\n"));

    return;
}                                                     // End ImScsiStopAdapter().
VOID
ScsiIoControl(
__in pHW_HBA_EXT          pHBAExt,    // Adapter device-object extension from port driver.
__in PSCSI_REQUEST_BLOCK  pSrb,
__in PUCHAR               pResult,
__inout __deref PKIRQL         LowestAssumedIrql
)
{
    PSRB_IO_CONTROL  srb_io_control = (PSRB_IO_CONTROL)pSrb->DataBuffer;

    *pResult = ResultDone;

    if (pSrb->DataTransferLength < sizeof(SRB_IO_CONTROL)
        || ((srb_io_control->HeaderLength != sizeof(SRB_IO_CONTROL)) |
        (srb_io_control->HeaderLength + srb_io_control->Length > pSrb->DataTransferLength)))
    {
        KdPrint2(("PhDskMnt::ScsiIoControl: Malformed MiniportIOCtl detected.\n",
            sizeof(srb_io_control->Signature),
            srb_io_control->Signature));

        ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST);
        goto Done;
    }

    if (memcmp(srb_io_control->Signature, IMSCSI_FUNCTION_SIGNATURE,
        sizeof(IMSCSI_FUNCTION_SIGNATURE) - 1))
    {
        KdPrint2(("PhDskMnt::ScsiIoControl: MiniportIOCtl sig '%.*s' not supported\n",
            sizeof(srb_io_control->Signature),
            srb_io_control->Signature));

        ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST);
        goto Done;
    }

    KdPrint2(("PhDskMnt::ScsiIoControl: Miniport IOCtl ControlCode = %#x\n",
        srb_io_control->ControlCode));

    switch (srb_io_control->ControlCode)
    {
    case SMP_IMSCSI_CHECK:
    {
        KdPrint2(("PhDskMnt::ScsiIoControl: Request to complete SRBs.\n"));
        srb_io_control->ReturnCode = STATUS_SUCCESS;
        ScsiSetSuccess(pSrb, 0);

        break;
    }

    case SMP_IMSCSI_CREATE_DEVICE:
    {
        PSRB_IMSCSI_CREATE_DATA srb_buffer = (PSRB_IMSCSI_CREATE_DATA)pSrb->DataBuffer;

        if ((srb_buffer->SrbIoControl.HeaderLength + srb_buffer->SrbIoControl.Length <
            FIELD_OFFSET(SRB_IMSCSI_CREATE_DATA, Fields.FileName))
            || (srb_buffer->Fields.FileNameLength +
            (ULONG)FIELD_OFFSET(SRB_IMSCSI_CREATE_DATA, Fields.FileName) >
            pSrb->DataTransferLength))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_CREATE_DEVICE request.\n"));

            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        ImScsiCreateDevice(pHBAExt, pSrb, pResult, LowestAssumedIrql);

        break;
    }

    case SMP_IMSCSI_REMOVE_DEVICE:
    {
        PSRB_IMSCSI_REMOVE_DEVICE srb_buffer = (PSRB_IMSCSI_REMOVE_DEVICE)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request to remove device.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_REMOVE_DEVICE request.\n"));

            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        srb_io_control->ReturnCode = ImScsiRemoveDevice(pHBAExt, &srb_buffer->DeviceNumber, LowestAssumedIrql);

        ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

        break;
    }

    case SMP_IMSCSI_QUERY_VERSION:
    {
        PSRB_IMSCSI_QUERY_VERSION srb_buffer = (PSRB_IMSCSI_QUERY_VERSION)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request for driver version.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            srb_io_control->ReturnCode = IMSCSI_DRIVER_VERSION;
            srb_io_control->Length = 0;

            ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

            break;
        }

        srb_io_control->ReturnCode = IMSCSI_DRIVER_VERSION;
        srb_io_control->Length = sizeof(*srb_buffer) - sizeof(srb_buffer->SrbIoControl);
        srb_buffer->SubVersion = PHDSKMNT_VERSION_ULONG;

        ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

        break;
    }

    case SMP_IMSCSI_QUERY_DEVICE:
    {
        PSRB_IMSCSI_CREATE_DATA srb_buffer = (PSRB_IMSCSI_CREATE_DATA)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_QUERY_DEVICE.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_QUERY_DEVICE request.\n"));

            pSrb->DataTransferLength = 0;
            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        srb_io_control->ReturnCode = ImScsiQueryDevice(pHBAExt, srb_buffer, &pSrb->DataTransferLength, LowestAssumedIrql);

        ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

        break;
    }

    case SMP_IMSCSI_QUERY_ADAPTER:
    {
        PSRB_IMSCSI_QUERY_ADAPTER srb_buffer = (PSRB_IMSCSI_QUERY_ADAPTER)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_QUERY_ADAPTER.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_QUERY_ADAPTER request.\n"));

            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        srb_io_control->ReturnCode = ImScsiQueryAdapter(pHBAExt, srb_buffer, pSrb->DataTransferLength, LowestAssumedIrql);

        ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

        break;
    }

    case SMP_IMSCSI_SET_DEVICE_FLAGS:
    {
        PSRB_IMSCSI_SET_DEVICE_FLAGS srb_buffer = (PSRB_IMSCSI_SET_DEVICE_FLAGS)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_SET_DEVICE_FLAGS.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_SET_DEVICE_FLAGS request.\n"));

            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        srb_io_control->ReturnCode = ImScsiSetFlagsDevice(pHBAExt, srb_buffer, LowestAssumedIrql);

        ScsiSetSuccess(pSrb, pSrb->DataTransferLength);

        break;
    }

    case SMP_IMSCSI_EXTEND_DEVICE:
    {
        PSRB_IMSCSI_EXTEND_DEVICE srb_buffer = (PSRB_IMSCSI_EXTEND_DEVICE)pSrb->DataBuffer;

        KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_EXTEND_DEVICE.\n"));

        if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer))
        {
            KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_EXTEND_DEVICE request.\n"));

            ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN);
            goto Done;
        }

        ImScsiExtendDevice(pHBAExt, pSrb, pResult, LowestAssumedIrql, srb_buffer);

        break;
    }

    default:

        DbgPrint("PhDskMnt::ScsiExecute: Unknown IOControl code=0x%X\n", srb_io_control->ControlCode);

        ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST);
        break;

    } // end switch

Done:
    KdPrint2(("PhDskMnt::ScsiIoControl: End: *Result=%i\n", (INT)*pResult));

    return;
}