Sample Code

Windows Driver Samples/ Super Floppy (sfloppy) Storage Class Driver/ C++/ src/ floppy.c/

/*++

Copyright (C) Microsoft Corporation, 1991 - 1999

Module Name:

    floppy.c

Abstract:

    SCSI floppy class driver

Author:

    Jeff Havens (jhavens)

Environment:

    kernel mode only

Notes:

Revision History:
02/28/96    georgioc    Merged this code with code developed by compaq in
                        parallel with microsoft, for 120MB floppy support.

01/17/96    georgioc    Made code PNP aware (uses the new \storage\classpnp/scsiport)

--*/

#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union

#include <stddef.h>
#include <ntddk.h>
#include <winerror.h>
#include <scsi.h>
#include <classpnp.h>
#include <initguid.h>
#include <ntddstor.h>

#include <ntstrsafe.h>
#include <intsafe.h>

#define MODE_DATA_SIZE      192
#define SCSI_FLOPPY_TIMEOUT  20
#define SFLOPPY_SRB_LIST_SIZE 4
//
// Define all possible drive/media combinations, given drives listed above
// and media types in ntdddisk.h.
//
// These values are used to index the DriveMediaConstants table.
//

#define NUMBER_OF_DRIVE_TYPES              7
#define DRIVE_TYPE_120M                    4    //120MB Floptical
#define DRIVE_TYPE_NONE                    NUMBER_OF_DRIVE_TYPES

//
// This array describes all media types we support.
// It should be arranged in the increasing order of density
//
// For a given drive, we list all the mediatypes that will
// work with that drive. For instance, a 120MB drive will
// take 720KB media, 1.44MB media, and 120MB media.
//
// Note that, DriveMediaConstants given below is grouped
// as drive and media combination
//
typedef enum _DRIVE_MEDIA_TYPE {
    Drive360Media160,                      // 5.25"  360k  drive;  160k   media
    Drive360Media180,                      // 5.25"  360k  drive;  180k   media
    Drive360Media320,                      // 5.25"  360k  drive;  320k   media
    Drive360Media32X,                      // 5.25"  360k  drive;  320k 1k secs
    Drive360Media360,                      // 5.25"  360k  drive;  360k   media
    Drive720Media720,                      // 3.5"   720k  drive;  720k   media
    Drive120Media160,                      // 5.25" 1.2Mb  drive;  160k   media
    Drive120Media180,                      // 5.25" 1.2Mb  drive;  180k   media
    Drive120Media320,                      // 5.25" 1.2Mb  drive;  320k   media
    Drive120Media32X,                      // 5.25" 1.2Mb  drive;  320k 1k secs
    Drive120Media360,                      // 5.25" 1.2Mb  drive;  360k   media
    Drive120Media120,                      // 5.25" 1.2Mb  drive; 1.2Mb   media
    Drive144Media720,                      // 3.5"  1.44Mb drive;  720k   media
    Drive144Media144,                      // 3.5"  1.44Mb drive; 1.44Mb  media
    Drive288Media720,                      // 3.5"  2.88Mb drive;  720k   media
    Drive288Media144,                      // 3.5"  2.88Mb drive; 1.44Mb  media
    Drive288Media288,                      // 3.5"  2.88Mb drive; 2.88Mb  media
    Drive2080Media720,                     // 3.5"  20.8Mb drive;  720k   media
    Drive2080Media144,                     // 3.5"  20.8Mb drive; 1.44Mb  media
    Drive2080Media2080,                    // 3.5"  20.8Mb drive; 20.8Mb  media
    Drive32MMedia32M,                      // 3.5"  32Mb drive; 32MB    media
    Drive120MMedia720,                     // 3.5"  120Mb drive; 720k  media
    Drive120MMedia144,                     // 3.5"  120Mb drive; 1.44Mb  media
    Drive120MMedia120M,                    // 3.5"  120Mb drive; 120Mb  media
    Drive240MMedia144M,                    // 3.5"  240Mb drive; 1.44Mb  media
    Drive240MMedia120M,                    // 3.5"  240Mb drive; 120Mb  media
    Drive240MMedia240M                     // 3.5"  240Mb drive; 240Mb  media
} DRIVE_MEDIA_TYPE;

//
// When we want to determine the media type in a drive, we will first
// guess that the media with highest possible density is in the drive,
// and keep trying lower densities until we can successfully read from
// the drive.
//
// These values are used to select a DRIVE_MEDIA_TYPE value.
//
// The following table defines ranges that apply to the DRIVE_MEDIA_TYPE
// enumerated values when trying media types for a particular drive type.
// Note that for this to work, the DRIVE_MEDIA_TYPE values must be sorted
// by ascending densities within drive types.  Also, for maximum track
// size to be determined properly, the drive types must be in ascending
// order.
//

typedef struct _DRIVE_MEDIA_LIMITS {
    DRIVE_MEDIA_TYPE HighestDriveMediaType;
    DRIVE_MEDIA_TYPE LowestDriveMediaType;
} DRIVE_MEDIA_LIMITS, *PDRIVE_MEDIA_LIMITS;

#if 0
DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {

    { Drive360Media360, Drive360Media160 }, // DRIVE_TYPE_0360
    { Drive120Media120, Drive120Media160 }, // DRIVE_TYPE_1200
    { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
    { Drive144Media144, Drive144Media720 }, // DRIVE_TYPE_1440
    { Drive288Media288, Drive288Media720 }, // DRIVE_TYPE_2880
    { Drive2080Media2080, Drive2080Media720 }
};
#else
DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {

    { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
    { Drive144Media144,  Drive144Media720}, // DRIVE_TYPE_1440
    { Drive288Media288,  Drive288Media720}, // DRIVE_TYPE_2880
    { Drive2080Media2080, Drive2080Media720 },
    { Drive32MMedia32M, Drive32MMedia32M }, // DRIVE_TYPE_32M
    { Drive120MMedia120M, Drive120MMedia720 }, // DRIVE_TYPE_120M
    { Drive240MMedia240M, Drive240MMedia144M } // DRIVE_TYPE_240M
};

#endif
//
// For each drive/media combination, define important constants.
//

typedef struct _DRIVE_MEDIA_CONSTANTS {
    MEDIA_TYPE MediaType;
    USHORT     BytesPerSector;
    UCHAR      SectorsPerTrack;
    USHORT     MaximumTrack;
    UCHAR      NumberOfHeads;
} DRIVE_MEDIA_CONSTANTS, *PDRIVE_MEDIA_CONSTANTS;

//
// Magic value to add to the SectorLengthCode to use it as a shift value
// to determine the sector size.
//

#define SECTORLENGTHCODE_TO_BYTESHIFT      7

//
// The following values were gleaned from many different sources, which
// often disagreed with each other.  Where numbers were in conflict, I
// chose the more conservative or most-often-selected value.
//

DRIVE_MEDIA_CONSTANTS DriveMediaConstants[] =
    {

    { F5_160_512,   0x200, 0x08, 0x27, 0x1 },
    { F5_180_512,   0x200, 0x09, 0x27, 0x1 },
    { F5_320_1024,  0x400, 0x04, 0x27, 0x2 },
    { F5_320_512,   0x200, 0x08, 0x27, 0x2 },
    { F5_360_512,   0x200, 0x09, 0x27, 0x2 },

    { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },

    { F5_160_512,   0x200, 0x08, 0x27, 0x1 },
    { F5_180_512,   0x200, 0x09, 0x27, 0x1 },
    { F5_320_1024,  0x400, 0x04, 0x27, 0x2 },
    { F5_320_512,   0x200, 0x08, 0x27, 0x2 },
    { F5_360_512,   0x200, 0x09, 0x27, 0x2 },
    { F5_1Pt2_512,  0x200, 0x0f, 0x4f, 0x2 },

    { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
    { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },

    { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
    { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
    { F3_2Pt88_512, 0x200, 0x24, 0x4f, 0x2 },

    { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
    { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
    { F3_20Pt8_512, 0x200, 0x1b, 0xfa, 0x6 },

    { F3_32M_512,   0x200, 0x20, 0x3ff,0x2},

    { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
    { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
    { F3_120M_512,  0x200, 0x20, 0x3c2,0x8 },

    { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
    { F3_120M_512,  0x200, 0x20, 0x3c2,0x8 },
    { F3_240M_512,  0x200, 0x38, 0x105,0x20}
};


#define NUMBER_OF_DRIVE_MEDIA_COMBINATIONS sizeof(DriveMediaConstants)/sizeof(DRIVE_MEDIA_CONSTANTS)

//
// floppy device data
//

typedef struct _DISK_DATA {
    ULONG DriveType;
    BOOLEAN IsDMF;
    // BOOLEAN EnableDMF;
    UNICODE_STRING FloppyInterfaceString;
} DISK_DATA, *PDISK_DATA;

//
// The FloppyCapacities and FloppyGeometries arrays are used by the
// USBFlopGetMediaTypes() and USBFlopFormatTracks() routines.

// The FloppyCapacities and FloppyGeometries arrays must be kept in 1:1 sync,
// i.e. each FloppyGeometries[i] must correspond to each FloppyCapacities[i].

// Also, the arrays must be kept in sorted ascending order so that they
// are returned in sorted ascending order by IOCTL_DISK_GET_MEDIA_TYPES.
//

typedef struct _FORMATTED_CAPACITY
{
    ULONG       NumberOfBlocks;

    ULONG       BlockLength;

    BOOLEAN     CanFormat;      // return for IOCTL_DISK_GET_MEDIA_TYPES ?

} FORMATTED_CAPACITY, *PFORMATTED_CAPACITY;


FORMATTED_CAPACITY FloppyCapacities[] =
{
    // Blocks  BlockLen CanFormat H   T  B/S S/T
    {0x000500, 0x0200,  TRUE}, // 2  80  512   8   640 KB  F5_640_512
    {0x0005A0, 0x0200,  TRUE}, // 2  80  512   9   720 KB  F3_720_512
    {0x000960, 0x0200,  TRUE}, // 2  80  512  15  1.20 MB  F3_1Pt2_512   (Toshiba)
    {0x0004D0, 0x0400,  TRUE}, // 2  77 1024   8  1.23 MB  F3_1Pt23_1024 (NEC)
    {0x000B40, 0x0200,  TRUE}, // 2  80  512  18  1.44 MB  F3_1Pt44_512
    {0x000D20, 0x0200, FALSE}, // 2  80  512  21  1.70 MB  DMF
    {0x010000, 0x0200,  TRUE},  // 2  1024 512  32   32 MB    F3_32M_512
    {0x03C300, 0x0200,  TRUE}, // 8 963  512  32   120 MB  F3_120M_512
    {0x0600A4, 0x0200,  TRUE}, // 13 890  512  34   200 MB  F3_200Mb_512 (HiFD)
    {0x072A00, 0x0200,  TRUE}  // 32 262  512  56   240 MB  F3_240M_512
};

DISK_GEOMETRY FloppyGeometries[] =
{
    // Cyl      MediaType       Trk/Cyl Sec/Trk Bytes/Sec
    {{80,0},    F3_640_512,     2,      8,      512},
    {{80,0},    F3_720_512,     2,      9,      512},
    {{80,0},    F3_1Pt2_512,    2,      15,     512},
    {{77,0},    F3_1Pt23_1024,  2,      8,      1024},
    {{80,0},    F3_1Pt44_512,   2,      18,     512},
    {{80,0},    F3_1Pt44_512,   2,      21,     512},   // DMF -> F3_1Pt44_512
    {{1024,0},  F3_32M_512,     2,      32,     512},
    {{963,0},   F3_120M_512,    8,      32,     512},
    {{890,0},   F3_200Mb_512,   13,     34,     512},
    {{262,0},   F3_240M_512,    32,     56,     512}
};

#define FLOPPY_CAPACITIES (sizeof(FloppyCapacities)/sizeof(FloppyCapacities[0]))

C_ASSERT((sizeof(FloppyGeometries)/sizeof(FloppyGeometries[0])) == FLOPPY_CAPACITIES);

//
// The following structures are used by USBFlopFormatTracks()
//

#pragma pack (push, 1)

typedef struct _CDB12FORMAT
{
    UCHAR   OperationCode;
    UCHAR   DefectListFormat : 3;
    UCHAR   CmpList : 1;
    UCHAR   FmtData : 1;
    UCHAR   LogicalUnitNumber : 3;
    UCHAR   TrackNumber;
    UCHAR   InterleaveMsb;
    UCHAR   InterleaveLsb;
    UCHAR   Reserved1[2];
    UCHAR   ParameterListLengthMsb;
    UCHAR   ParameterListLengthLsb;
    UCHAR   Reserved2[3];
} CDB12FORMAT, *PCDB12FORMAT;


typedef struct _DEFECT_LIST_HEADER
{
    UCHAR   Reserved1;
    UCHAR   Side : 1;
    UCHAR   Immediate : 1;
    UCHAR   Reserved2 : 2;
    UCHAR   SingleTrack : 1;
    UCHAR   DisableCert : 1;
    UCHAR   Reserved3 : 1;
    UCHAR   FormatOptionsValid : 1;
    UCHAR   DefectListLengthMsb;
    UCHAR   DefectListLengthLsb;
} DEFECT_LIST_HEADER, *PDEFECT_LIST_HEADER;

typedef struct _FORMAT_UNIT_PARAMETER_LIST
{
    DEFECT_LIST_HEADER DefectListHeader;
    FORMATTED_CAPACITY_DESCRIPTOR FormatDescriptor;
} FORMAT_UNIT_PARAMETER_LIST, *PFORMAT_UNIT_PARAMETER_LIST;

#pragma pack (pop)

DRIVER_INITIALIZE DriverEntry;

DRIVER_UNLOAD     ScsiFlopUnload;

DRIVER_ADD_DEVICE ScsiFlopAddDevice;

NTSTATUS
ScsiFlopInitDevice(
    IN PDEVICE_OBJECT Fdo
    );

NTSTATUS
ScsiFlopStartDevice(
    IN PDEVICE_OBJECT Fdo
    );

NTSTATUS
ScsiFlopRemoveDevice(
    IN PDEVICE_OBJECT Fdo,
    IN UCHAR Type
    );

NTSTATUS
ScsiFlopStopDevice(
    IN PDEVICE_OBJECT Fdo,
    IN UCHAR Type
    );

BOOLEAN
FindScsiFlops(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath,
    IN PCLASS_INIT_DATA InitializationData,
    IN PDEVICE_OBJECT PortDeviceObject,
    IN ULONG PortNumber
    );

NTSTATUS
ScsiFlopReadWriteVerification(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
ScsiFlopDeviceControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

BOOLEAN
IsFloppyDevice(
    PDEVICE_OBJECT DeviceObject
    );

NTSTATUS
CreateFlopDeviceObject(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PortDeviceObject,
    IN ULONG DeviceCount
    );

NTSTATUS
DetermineMediaType(
    PDEVICE_OBJECT DeviceObject
    );

ULONG
DetermineDriveType(
    PDEVICE_OBJECT DeviceObject
    );

BOOLEAN
FlCheckFormatParameters(
    IN PDEVICE_OBJECT DeviceObject,
    IN PFORMAT_PARAMETERS FormatParameters
    );

NTSTATUS
FormatMedia(
    PDEVICE_OBJECT DeviceObject,
    MEDIA_TYPE MediaType
    );

NTSTATUS
FlopticalFormatMedia(
    PDEVICE_OBJECT DeviceObject,
    PFORMAT_PARAMETERS Format
    );

VOID
ScsiFlopProcessError(
    PDEVICE_OBJECT DeviceObject,
    PSCSI_REQUEST_BLOCK Srb,
    NTSTATUS *Status,
    BOOLEAN *Retry
    );

NTSTATUS
USBFlopGetMediaTypes(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    );

NTSTATUS
USBFlopFormatTracks(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)

#pragma alloc_text(PAGE, ScsiFlopUnload)
#pragma alloc_text(PAGE, ScsiFlopAddDevice)
#pragma alloc_text(PAGE, CreateFlopDeviceObject)
#pragma alloc_text(PAGE, ScsiFlopStartDevice)
#pragma alloc_text(PAGE, ScsiFlopRemoveDevice)
#pragma alloc_text(PAGE, IsFloppyDevice)
#pragma alloc_text(PAGE, DetermineMediaType)
#pragma alloc_text(PAGE, DetermineDriveType)
#pragma alloc_text(PAGE, FlCheckFormatParameters)
#pragma alloc_text(PAGE, FormatMedia)
#pragma alloc_text(PAGE, FlopticalFormatMedia)
#pragma alloc_text(PAGE, USBFlopGetMediaTypes)
#pragma alloc_text(PAGE, USBFlopFormatTracks)

#endif


NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    This is the system initialization routine for installable drivers.
    It calls the SCSI class driver initialization routine.

Arguments:

    DriverObject - Pointer to driver object created by system.

Return Value:

    NTSTATUS

--*/

{
    CLASS_INIT_DATA InitializationData;

    //
    // Zero InitData
    //

    RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));

    //
    // Set sizes
    //

    InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
    InitializationData.FdoData.DeviceExtensionSize =
        sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(DISK_DATA);

    InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
    InitializationData.FdoData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE;

    //
    // Set entry points
    //

    InitializationData.FdoData.ClassInitDevice = ScsiFlopInitDevice;
    InitializationData.FdoData.ClassStartDevice = ScsiFlopStartDevice;
    InitializationData.FdoData.ClassStopDevice = ScsiFlopStopDevice;
    InitializationData.FdoData.ClassRemoveDevice = ScsiFlopRemoveDevice;

    InitializationData.FdoData.ClassReadWriteVerification = ScsiFlopReadWriteVerification;
    InitializationData.FdoData.ClassDeviceControl = ScsiFlopDeviceControl;

    InitializationData.FdoData.ClassShutdownFlush = NULL;
    InitializationData.FdoData.ClassCreateClose = NULL;
    InitializationData.FdoData.ClassError = ScsiFlopProcessError;
    InitializationData.ClassStartIo = NULL;

    InitializationData.ClassAddDevice = ScsiFlopAddDevice;
    InitializationData.ClassUnload = ScsiFlopUnload;
    //
    // Call the class init routine
    //

    return ClassInitialize( DriverObject, RegistryPath, &InitializationData);


} // end DriverEntry()

VOID
ScsiFlopUnload(
    IN PDRIVER_OBJECT DriverObject
    )
{
    PAGED_CODE();
    UNREFERENCED_PARAMETER(DriverObject);
    return;
}

//
// AddDevice operation is performed in CreateFlopDeviceObject function which
// is called by ScsiFlopAddDevice (The AddDevice routine for sfloppy.sys).
// DO_DEVICE_INITIALIZING flag is cleard upon successfully processing AddDevice
// operation in CreateFlopDeviceObject. But PREFAST is currently unable to
// detect that DO_DEVICE_INITIALIZING is indeed cleard in CreateFlopDeviceObject
// and it raises Warning 28152 (The return from an AddDevice-like function
// unexpectedly did not clear DO_DEVICE_INITIALIZING). Suppress that warning
// using #pragma.
//
#pragma warning(push)
#pragma warning(disable:28152)

NTSTATUS
ScsiFlopAddDevice (
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT Pdo
    )
/*++

Routine Description:

    This routine creates and initializes a new FDO for the corresponding
    PDO.  It may perform property queries on the FDO but cannot do any
    media access operations.

Arguments:

    DriverObject - Scsiscan class driver object.

    Pdo - the physical device object we are being added to

Return Value:

    status

--*/
{
    NTSTATUS status;
    ULONG floppyCount = IoGetConfigurationInformation()->FloppyCount;

    PAGED_CODE();

    //
    // Get the number of disks already initialized.
    //

    status = CreateFlopDeviceObject(DriverObject, Pdo, floppyCount);

    if (NT_SUCCESS(status)) {

        //
        // Increment system floppy device count.
        //

        IoGetConfigurationInformation()->FloppyCount++;
    }

    return status;
}

NTSTATUS
CreateFlopDeviceObject(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT Pdo,
    IN ULONG DeviceCount
    )

/*++

Routine Description:

    This routine creates an object for the device and then calls the
    SCSI port driver for media capacity and sector size.

Arguments:

    DriverObject - Pointer to driver object created by system.
    PortDeviceObject - to connect to SCSI port driver.
    DeviceCount - Number of previously installed Floppys.
    AdapterDescriptor - Pointer to structure returned by SCSI port
                        driver describing adapter capabilites (and limitations).
    DeviceDescriptor - Pointer to configuration information for this device.

Return Value:

--*/
{
    NTSTATUS        status;
    PDEVICE_OBJECT  deviceObject = NULL;
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
    PDISK_DATA  diskData;

    PAGED_CODE();

    DebugPrint((3,"CreateFlopDeviceObject: Enter routine\n"));

    //
    // Try to claim the device.
    //

    status = ClassClaimDevice(Pdo,FALSE);

    if (!NT_SUCCESS(status)) {
        return(status);
    }

    DeviceCount--;

    do {
        UCHAR name[256];

        //
        // Create device object for this device.
        //

        DeviceCount++;

        status = RtlStringCbPrintfA((PCCHAR) name,
                                    sizeof(name)/sizeof(UCHAR),
                                    "\\Device\\Floppy%u",
                                    DeviceCount);
        if (NT_SUCCESS(status)) {

            status = ClassCreateDeviceObject(DriverObject,
                                             (PCCHAR) name,
                                             Pdo,
                                             TRUE,
                                             &deviceObject);
        }
    } while ((status == STATUS_OBJECT_NAME_COLLISION) ||
             (status == STATUS_OBJECT_NAME_EXISTS));

    if (!NT_SUCCESS(status)) {
        DebugPrint((1,"CreateFlopDeviceObjects: Can not create device\n"));
        goto CreateFlopDeviceObjectExit;
    }

    //
    // Indicate that IRPs should include MDLs.
    //

    deviceObject->Flags |= DO_DIRECT_IO;

    fdoExtension = deviceObject->DeviceExtension;

    //
    // Back pointer to device object.
    //

    fdoExtension->CommonExtension.DeviceObject = deviceObject;

    //
    // This is the physical device.
    //

    fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;

    //
    // Reset the drive type.
    //

    diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
    diskData->DriveType = DRIVE_TYPE_NONE;
    diskData->IsDMF = FALSE;
    // diskData->EnableDMF = TRUE;

    //
    // Initialize lock count to zero. The lock count is used to
    // disable the ejection mechanism when media is mounted.
    //

    fdoExtension->LockCount = 0;

    //
    // Save system floppy number
    //

    fdoExtension->DeviceNumber = DeviceCount;

    //
    // Set the alignment requirements for the device based on the
    // host adapter requirements
    //

    if (Pdo->AlignmentRequirement > deviceObject->AlignmentRequirement) {
        deviceObject->AlignmentRequirement = Pdo->AlignmentRequirement;
    }

    //
    // Clear the SrbFlags and disable synchronous transfers
    //

    fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;

    //
    // Finally, attach to the PDO
    //

    fdoExtension->LowerPdo = Pdo;

    fdoExtension->CommonExtension.LowerDeviceObject =
        IoAttachDeviceToDeviceStack(deviceObject, Pdo);

    if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {

        status = STATUS_UNSUCCESSFUL;
        goto CreateFlopDeviceObjectExit;
    }

    deviceObject->StackSize++;

    //
    // The device is initialized properly - mark it as such.
    //

    deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    return STATUS_SUCCESS;

CreateFlopDeviceObjectExit:

    if (deviceObject != NULL) {
        IoDeleteDevice(deviceObject);
    }

    return status;

} // end CreateFlopDeviceObject()
#pragma warning(pop)

NTSTATUS
ScsiFlopInitDevice(
    IN PDEVICE_OBJECT Fdo
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PDISK_DATA diskData = commonExtension->DriverData;

    PVOID senseData = NULL;
    ULONG timeOut;

    NTSTATUS status = STATUS_SUCCESS;

    //
    // Allocate request sense buffer.
    //

    senseData = ExAllocatePool(NonPagedPoolNxCacheAligned, SENSE_BUFFER_SIZE);

    if (senseData == NULL) {

        //
        // The buffer cannot be allocated.
        //

        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }

    //
    // Set the sense data pointer in the device extension.
    //

    fdoExtension->SenseData = senseData;

    //
    // Build the lookaside list for srb's for this device.
    //

    ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION)fdoExtension,
                                    SFLOPPY_SRB_LIST_SIZE);

    //
    // Register for media change notification
    //
    ClassInitializeMediaChangeDetection(fdoExtension,
                                        (PUCHAR) "SFloppy");

    //
    // Set timeout value in seconds.
    //

    timeOut = ClassQueryTimeOutRegistryValue(Fdo);
    if (timeOut) {
        fdoExtension->TimeOutValue = timeOut;
    } else {
        fdoExtension->TimeOutValue = SCSI_FLOPPY_TIMEOUT;
    }

    //
    // Floppies are not partitionable so starting offset is 0.
    //

    fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)0;

#if 0
    if (!IsFloppyDevice(Fdo) ||
        !(Fdo->Characteristics & FILE_REMOVABLE_MEDIA) ||
        (fdoExtension->DeviceDescriptor->DeviceType != DIRECT_ACCESS_DEVICE)) {

        ExFreePool(senseData);
        status = STATUS_NO_SUCH_DEVICE;
        return status;
    }
#endif

    RtlZeroMemory(&(fdoExtension->DiskGeometry),
                  sizeof(DISK_GEOMETRY));

    //
    // Determine the media type if possible. Set the current media type to
    // Unknown so that determine media type will check the media.
    //

    fdoExtension->DiskGeometry.MediaType = Unknown;

    //
    // Register interfaces for this device.
    //

    {
        UNICODE_STRING interfaceName;

        RtlInitUnicodeString(&interfaceName, NULL);

        status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
                                           (LPGUID) &GUID_DEVINTERFACE_FLOPPY,
                                           NULL,
                                           &interfaceName);

        if(NT_SUCCESS(status)) {
            diskData->FloppyInterfaceString = interfaceName;
        } else {
            RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
            DebugPrint((1, "ScsiFlopStartDevice: Unable to register device "
                           "interface for fdo %p [%08lx]\n",
                        Fdo, status));
        }
    }

    return (STATUS_SUCCESS);
}

#pragma warning(suppress:6262) // This function uses 1096 bytes of stack which exceed default value of 1024 bytes used by Code Analysis for flagging as warning
NTSTATUS ScsiFlopStartDevice(
    IN PDEVICE_OBJECT Fdo
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;

    PIRP        irp;
    IO_STATUS_BLOCK ioStatus;

    SCSI_ADDRESS    scsiAddress;

    WCHAR   ntNameBuffer[256];
    UNICODE_STRING  ntUnicodeString;

    WCHAR   arcNameBuffer[256];
    UNICODE_STRING  arcUnicodeString;

    KEVENT event;

    NTSTATUS status = STATUS_SUCCESS;

    PAGED_CODE();

    KeInitializeEvent(&event,SynchronizationEvent,FALSE);

    DetermineMediaType(Fdo); // ignore unsuccessful here

    //
    // Create device object for this device.
    //

    RtlStringCbPrintfW(ntNameBuffer,
                       sizeof(ntNameBuffer)/sizeof(WCHAR),
                       L"\\Device\\Floppy%u",
                       fdoExtension->DeviceNumber);

    //
    // Create local copy of unicode string
    //
    RtlInitUnicodeString(&ntUnicodeString,ntNameBuffer);

    //
    // Create a symbolic link from the disk name to the corresponding
    // ARC name, to be used if we're booting off the disk.  This will
    // fail if it's not system initialization time; that's fine.  The
    // ARC name looks something like \ArcName\scsi(0)Flop(0)fdisk(0).
    // In order to get the address, we need to send a IOCTL_SCSI_GET_ADDRESS...
    //

    irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
                                        Fdo,
                                        NULL,
                                        0,
                                        &scsiAddress,
                                        sizeof(scsiAddress),
                                        FALSE,
                                        &event,
                                        &ioStatus);

    if (irp == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);

    if (status == STATUS_PENDING) {
        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        status = ioStatus.Status;
    }

    //
    // IOCTL_SCSI_GET_ADDRESS might not be supported by the port driver and
    // hence may fail. But it is not a fatal error. Do not fail PnP start
    // if this IOCTL fails.
    //
    if (NT_SUCCESS(status)) {

        RtlStringCbPrintfW(arcNameBuffer,
                           sizeof(arcNameBuffer)/sizeof(WCHAR),
                           L"\\ArcName\\scsi(%u)disk(%u)fdisk(%u)",
                           scsiAddress.PortNumber,
                           scsiAddress.TargetId,
                           scsiAddress.Lun);

        RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);

        IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
    }

    status = STATUS_SUCCESS;

    //
    // Create the multi() arc name -- Create the "fake"
    // name of multi(0)disk(0)fdisk(#) to handle the case where the
    // SCSI floppy is the only floppy in the system.  If this fails
    // it doesn't matter because the previous scsi() based ArcName
    // will work.  This name is necessary for installation.
    //

    RtlStringCbPrintfW(arcNameBuffer,
                       sizeof(arcNameBuffer)/sizeof(WCHAR),
                       L"\\ArcName\\multi(%u)disk(%u)fdisk(%u)",
                       0,
                       0,
                       fdoExtension->DeviceNumber);

    RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);

    IoAssignArcName(&arcUnicodeString, &ntUnicodeString);

    //
    // Set our interface state.
    //

    {
        PDISK_DATA diskData = commonExtension->DriverData;

        if(diskData->FloppyInterfaceString.Buffer != NULL) {

            status = IoSetDeviceInterfaceState(
                        &(diskData->FloppyInterfaceString),
                        TRUE);

            if(!NT_SUCCESS(status)) {
                DebugPrint((1, "ScsiFlopStartDevice: Unable to set device "
                               "interface state to TRUE for fdo %p "
                               "[%08lx]\n",
                            Fdo, status));
            }
        }
    }

    return STATUS_SUCCESS;
}


NTSTATUS
ScsiFlopReadWriteVerification(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

Arguments:

Return Value:

    NT Status

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
    NTSTATUS status = STATUS_SUCCESS;

    //
    // Make sure that the number of bytes to transfer is a multiple of the sector size
    //
    if ((irpSp->Parameters.Read.Length & (fdoExtension->DiskGeometry.BytesPerSector - 1)) != 0)
    {
        status = STATUS_INVALID_PARAMETER;
    }

    Irp->IoStatus.Status = status;

    return status;
}


NTSTATUS
ScsiFlopDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

Arguments:

Return Value:

    Status is returned.

--*/

{
    KIRQL currentIrql;
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PSCSI_REQUEST_BLOCK srb;
    PCDB cdb;
    NTSTATUS status;
    PDISK_GEOMETRY outputBuffer;
    ULONG outputBufferLength;
    ULONG i;
    DRIVE_MEDIA_TYPE lowestDriveMediaType;
    DRIVE_MEDIA_TYPE highestDriveMediaType;
    PFORMAT_PARAMETERS formatParameters;
    PMODE_PARAMETER_HEADER modeData;
    ULONG length;

    //
    // Initialize the information field
    //
    Irp->IoStatus.Information = 0;

    srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

    if (srb == NULL) {

        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        if (IoIsErrorUserInduced(Irp->IoStatus.Status)) {

            IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
        }

        KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
        ClassReleaseRemoveLock(DeviceObject, Irp);
        ClassCompleteRequest(DeviceObject, Irp, 0);
        KeLowerIrql(currentIrql);

        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    //
    // Write zeros to Srb.
    //

    RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

    cdb = (PCDB)srb->Cdb;

    switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {


    case IOCTL_DISK_VERIFY: {

       PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
       LARGE_INTEGER byteOffset;
       ULONG         sectorOffset;
       USHORT        sectorCount;

       //
       // Validate buffer length.
       //

       if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
           sizeof(VERIFY_INFORMATION)) {

           status = STATUS_INFO_LENGTH_MISMATCH;
           break;
       }

       //
       // Perform a bounds check on the sector range
       //
       if ((verifyInfo->StartingOffset.QuadPart > fdoExtension->CommonExtension.PartitionLength.QuadPart) ||
           (verifyInfo->StartingOffset.QuadPart < 0))
       {
           status = STATUS_NONEXISTENT_SECTOR;
           break;
       }
       else
       {
           ULONGLONG bytesRemaining = fdoExtension->CommonExtension.PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;

           if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
           {
               status = STATUS_NONEXISTENT_SECTOR;
               break;
           }
       }

       //
       // Verify sectors
       //

       srb->CdbLength = 10;

       cdb->CDB10.OperationCode = SCSIOP_VERIFY;

       //
       // Add disk offset to starting sector.
       //

       byteOffset.QuadPart = fdoExtension->CommonExtension.StartingOffset.QuadPart +
                       verifyInfo->StartingOffset.QuadPart;

       //
       // Convert byte offset to sector offset.
       //

       sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);

       //
       // Convert ULONG byte count to USHORT sector count.
       //

       sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);

       //
       // Move little endian values into CDB in big endian format.
       //

       cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
       cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
       cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
       cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;

       cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
       cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;

       //
       // The verify command is used by the NT FORMAT utility and
       // requests are sent down for 5% of the volume size. The
       // request timeout value is calculated based on the number of
       // sectors verified.
       //

       srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
                             fdoExtension->TimeOutValue;

       status = ClassSendSrbAsynchronous(DeviceObject,
                                         srb,
                                         Irp,
                                         NULL,
                                         0,
                                         FALSE);
       return(status);

    }

    case IOCTL_DISK_GET_PARTITION_INFO: {

        if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {

            USBFlopGetMediaTypes(DeviceObject, NULL);

            // Don't need to propagate any error if one occurs
            //
            status = STATUS_SUCCESS;

        } else {

            status = DetermineMediaType(DeviceObject);
        }

        if (!NT_SUCCESS(status)) {
            // so will propogate error
            NOTHING;
        } else if (fdoExtension->DiskGeometry.MediaType == F3_120M_512) {
            //so that the format code will not try to partition it.
            status = STATUS_INVALID_DEVICE_REQUEST;
        } else {
           //
           // Free the Srb, since it is not needed.
           //

           ExFreePool(srb);

           //
           // Pass the request to the common device control routine.
           //

           return(ClassDeviceControl(DeviceObject, Irp));
        }
        break;
    }

    case IOCTL_DISK_GET_DRIVE_GEOMETRY: {

        DebugPrint((3,"ScsiDeviceIoControl: Get drive geometry\n"));

        if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
        {
            status = USBFlopGetMediaTypes(DeviceObject,
                                          Irp);
            break;
        }

        //
        // If there's not enough room to write the
        // data, then fail the request.
        //

        if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
            sizeof( DISK_GEOMETRY ) ) {

            status = STATUS_INVALID_PARAMETER;
            break;
        }

        status = DetermineMediaType(DeviceObject);

        if (!NT_SUCCESS(status)) {

            Irp->IoStatus.Information = 0;
            Irp->IoStatus.Status = status;

        } else {

            //
            // Copy drive geometry information from device extension.
            //

            RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
                          &(fdoExtension->DiskGeometry),
                          sizeof(DISK_GEOMETRY));

            Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
            status = STATUS_SUCCESS;

        }

        break;
    }

    case IOCTL_DISK_GET_MEDIA_TYPES: {

        if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
        {
            status = USBFlopGetMediaTypes(DeviceObject,
                                          Irp);
            break;
        }

        i = DetermineDriveType(DeviceObject);

        if (i == DRIVE_TYPE_NONE) {
            status = STATUS_UNRECOGNIZED_MEDIA;
            break;
        }

        lowestDriveMediaType = DriveMediaLimits[i].LowestDriveMediaType;
        highestDriveMediaType = DriveMediaLimits[i].HighestDriveMediaType;

        outputBufferLength =
        irpStack->Parameters.DeviceIoControl.OutputBufferLength;

        //
        // Make sure that the input buffer has enough room to return
        // at least one descriptions of a supported media type.
        //

        if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) {

            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        //
        // Assume success, although we might modify it to a buffer
        // overflow warning below (if the buffer isn't big enough
        // to hold ALL of the media descriptions).
        //

        status = STATUS_SUCCESS;

        if (outputBufferLength < ( sizeof( DISK_GEOMETRY ) *
            ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) {

            //
            // The buffer is too small for all of the descriptions;
            // calculate what CAN fit in the buffer.
            //

            status = STATUS_BUFFER_OVERFLOW;

            highestDriveMediaType = (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) +
                ( outputBufferLength /
                sizeof( DISK_GEOMETRY ) ) );
        }

        outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;

        for (i = (UCHAR)lowestDriveMediaType;i <= (UCHAR)highestDriveMediaType;i++ ) {

             outputBuffer->MediaType = DriveMediaConstants[i].MediaType;
             outputBuffer->Cylinders.LowPart =
                 DriveMediaConstants[i].MaximumTrack + 1;
             outputBuffer->Cylinders.HighPart = 0;
             outputBuffer->TracksPerCylinder =
                 DriveMediaConstants[i].NumberOfHeads;
             outputBuffer->SectorsPerTrack =
                 DriveMediaConstants[i].SectorsPerTrack;
             outputBuffer->BytesPerSector =
                 DriveMediaConstants[i].BytesPerSector;
             outputBuffer++;

             Irp->IoStatus.Information += sizeof( DISK_GEOMETRY );
        }

        break;
    }

    case IOCTL_DISK_FORMAT_TRACKS: {

        if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
        {
            status = USBFlopFormatTracks(DeviceObject,
                                         Irp);
            break;
        }

        //
        // Make sure that we got all the necessary format parameters.
        //

        if ( irpStack->Parameters.DeviceIoControl.InputBufferLength <sizeof( FORMAT_PARAMETERS ) ) {

            status = STATUS_INVALID_PARAMETER;
            break;
        }

        formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;

        //
        // Make sure the parameters we got are reasonable.
        //

        if ( !FlCheckFormatParameters(DeviceObject, formatParameters)) {

            status = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // If this request is for a 20.8 MB floppy then call a special
        // floppy format routine.
        //

        if (formatParameters->MediaType == F3_20Pt8_512) {
            status = FlopticalFormatMedia(DeviceObject,
                                          formatParameters
                                          );

            break;
        }

        //
        // All the work is done in the pass.  If this is not the first pass,
        // then complete the request and return;
        //

        if (formatParameters->StartCylinderNumber != 0 || formatParameters->StartHeadNumber != 0) {

            status = STATUS_SUCCESS;
            break;
        }

        status = FormatMedia( DeviceObject, formatParameters->MediaType);
        break;
    }

    case IOCTL_DISK_IS_WRITABLE: {

        if ((fdoExtension->DiskGeometry.MediaType) == F3_32M_512) {

            //
            // 32MB media is READ ONLY. Just return
            // STATUS_MEDIA_WRITE_PROTECTED
            //

            status = STATUS_MEDIA_WRITE_PROTECTED;

            break;
        }

        //
        // Determine if the device is writable.
        //

        modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);

        if (modeData == NULL) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        RtlZeroMemory(modeData, MODE_DATA_SIZE);

        length = ClassModeSense(DeviceObject,
                                (PCHAR) modeData,
                                MODE_DATA_SIZE,
                                MODE_SENSE_RETURN_ALL);

        if (length < sizeof(MODE_PARAMETER_HEADER)) {

            //
            // Retry the request in case of a check condition.
            //

            length = ClassModeSense(DeviceObject,
                                    (PCHAR) modeData,
                                    MODE_DATA_SIZE,
                                    MODE_SENSE_RETURN_ALL);

            if (length < sizeof(MODE_PARAMETER_HEADER)) {
                status = STATUS_IO_DEVICE_ERROR;
                ExFreePool(modeData);
                break;
            }
        }

        if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
            status = STATUS_MEDIA_WRITE_PROTECTED;
        } else {
            status = STATUS_SUCCESS;
        }

        DebugPrint((2,"IOCTL_DISK_IS_WRITABLE returns %08X\n", status));

        ExFreePool(modeData);
        break;
    }

    default: {

        DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));

        //
        // Free the Srb, since it is not needed.
        //

        ExFreePool(srb);

        //
        // Pass the request to the common device control routine.
        //

        return(ClassDeviceControl(DeviceObject, Irp));

        break;
    }

    } // end switch( ...

    //
    // Check if SL_OVERRIDE_VERIFY_VOLUME flag is set in the IRP.
    // If so, do not return STATUS_VERIFY_REQUIRED
    //
    if ((status == STATUS_VERIFY_REQUIRED) &&
        (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME))) {

        status = STATUS_IO_DEVICE_ERROR;

    }

    Irp->IoStatus.Status = status;

    if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {

        IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
    }

    KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
    ClassReleaseRemoveLock(DeviceObject, Irp);
    ClassCompleteRequest(DeviceObject, Irp, 0);
    KeLowerIrql(currentIrql);

    ExFreePool(srb);

    return status;

} // end ScsiFlopDeviceControl()

#if 0

BOOLEAN
IsFloppyDevice(
    PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

    The routine performs the necessary funcitons to deterime if the device is
    really a floppy rather than a harddisk.  This is done by a mode sense
    command.  First a check is made to see if the medimum type is set.  Second
    a check is made for the flexible parameters mode page.

Arguments:

    DeviceObject - Supplies the device object to be tested.

Return Value:

    Return TRUE if the indicated device is a floppy.

--*/
{

    PVOID modeData;
    PUCHAR pageData;
    ULONG length;

    modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);

    if (modeData == NULL) {
        return(FALSE);
    }

    RtlZeroMemory(modeData, MODE_DATA_SIZE);

    length = ClassModeSense(DeviceObject, modeData, MODE_DATA_SIZE, MODE_SENSE_RETURN_ALL);

    if (length < sizeof(MODE_PARAMETER_HEADER)) {

        //
        // Retry the request in case of a check condition.
        //

        length = ClassModeSense(DeviceObject,
                    modeData,
                    MODE_DATA_SIZE,
                    MODE_SENSE_RETURN_ALL);

        if (length < sizeof(MODE_PARAMETER_HEADER)) {

            ExFreePool(modeData);
            return(FALSE);

        }
    }

#if 0
    //
    // Some drives incorrectly report this.  In particular the SONY RMO-S350
    // when in disk mode.
    //

    if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
        && ((PMODE_PARAMETER_HEADER) modeData)->MediumType <= MODE_FD_MAXIMUM_TYPE) {

        DebugPrint((1, "ScsiFlop: MediumType value %2x, This is a floppy.\n", ((PMODE_PARAMETER_HEADER) modeData)->MediumType));
        ExFreePool(modeData);
        return(TRUE);
    }

#endif

    //
    // If the length is greater than length indiated by the mode data reset
    // the data to the mode data.
    //
    if (length > (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
        length = (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;

    }

    //
    // Look for the flexible disk mode page.
    //

    pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);

    if (pageData != NULL) {

        DebugPrint((1, "ScsiFlop: Flexible disk page found, This is a floppy.\n"));

        //
        // As a special case for the floptical driver do a magic mode sense to
        // enable the drive.
        //

        ClassModeSense(DeviceObject, modeData, 0x2a, 0x2e);

        ExFreePool(modeData);
        return(TRUE);

    }

    ExFreePool(modeData);
    return(FALSE);

}
#endif


NTSTATUS
DetermineMediaType(
    PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

    This routine determines the floppy media type based on the size of the
    device.  The geometry information is set for the device object.

Arguments:

    DeviceObject - Supplies the device object to be tested.

Return Value:

    None

--*/
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PDISK_GEOMETRY geometry;
    LONG index;
    NTSTATUS status;

    PAGED_CODE();

    geometry = &(fdoExtension->DiskGeometry);

    //
    // Issue ReadCapacity to update device extension
    // with information for current media.
    //

    status = ClassReadDriveCapacity(DeviceObject);

    if (!NT_SUCCESS(status)) {

       //
       // Set the media type to unknow and zero the geometry information.
       //

       geometry->MediaType = Unknown;

       return status;

    }

    //
    // Look at the capcity of disk to determine its type.
    //

    for (index = NUMBER_OF_DRIVE_MEDIA_COMBINATIONS - 1; index >= 0; index--) {

        //
        // Walk the table backward untill the drive capacity holds all of the
        // data and the bytes per setor are equal
        //

         if ((ULONG) (DriveMediaConstants[index].NumberOfHeads *
             (DriveMediaConstants[index].MaximumTrack + 1) *
             DriveMediaConstants[index].SectorsPerTrack *
             DriveMediaConstants[index].BytesPerSector) <=
             fdoExtension->CommonExtension.PartitionLength.LowPart &&
             DriveMediaConstants[index].BytesPerSector ==
             geometry->BytesPerSector) {

             geometry->MediaType = DriveMediaConstants[index].MediaType;
             geometry->TracksPerCylinder = DriveMediaConstants[index].NumberOfHeads;
             geometry->SectorsPerTrack = DriveMediaConstants[index].SectorsPerTrack;
             geometry->Cylinders.LowPart = DriveMediaConstants[index].MaximumTrack+1;
             break;
         }
    }

    if (index == -1) {

        //
        // Set the media type to unknow and zero the geometry information.
        //

        geometry->MediaType = Unknown;


    } else {
        //
        // DMF check breaks the insight SCSI floppy, so its disabled for that case
        //
        PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;

        // if (diskData->EnableDMF == TRUE) {

            //
            //check to see if DMF
            //

            PSCSI_REQUEST_BLOCK srb;
            PVOID               readData;

            //
            // Allocate a Srb for the read command.
            //

            readData = ExAllocatePool(NonPagedPoolNx, geometry->BytesPerSector);
            if (readData == NULL) {
                return STATUS_NO_MEMORY;
            }

            srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

            if (srb == NULL) {

                ExFreePool(readData);
                return STATUS_NO_MEMORY;
            }

            RtlZeroMemory(readData, geometry->BytesPerSector);
            RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

            srb->CdbLength = 10;
            srb->Cdb[0] = SCSIOP_READ;
            srb->Cdb[5] = 0;
            srb->Cdb[8] = (UCHAR) 1;

            //
            // Set timeout value.
            //

            srb->TimeOutValue = fdoExtension->TimeOutValue;

            //
            // Send the mode select data.
            //

            status = ClassSendSrbSynchronous(DeviceObject,
                      srb,
                      readData,
                      geometry->BytesPerSector,
                      FALSE
                      );

            if (NT_SUCCESS(status)) {
                char *pchar = (char *)readData;

                pchar += 3; //skip 3 bytes jump code

                // If the MSDMF3. signature is there then mark it as DMF diskette
                if (RtlCompareMemory(pchar, "MSDMF3.", 7) == 7) {
                    diskData->IsDMF = TRUE;
                }

            }
            ExFreePool(readData);
            ExFreePool(srb);
        // }// else
    }
    return status;
}

ULONG
DetermineDriveType(
    PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

    The routine determines the device type so that the supported medias can be
    determined.  It does a mode sense for the default parameters.  This code
    assumes that the returned values are for the maximum device size.

Arguments:

    DeviceObject - Supplies the device object to be tested.

Return Value:

    None

--*/
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PVOID modeData;
    PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
    PMODE_FLEXIBLE_DISK_PAGE pageData;
    ULONG length;
    LONG index;
    UCHAR numberOfHeads;
    UCHAR sectorsPerTrack;
    USHORT maximumTrack;
    BOOLEAN applyFix = FALSE;

    PAGED_CODE();

    if (diskData->DriveType != DRIVE_TYPE_NONE) {
        return(diskData->DriveType);
    }

    modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);

    if (modeData == NULL) {
        return(DRIVE_TYPE_NONE);
    }

    RtlZeroMemory(modeData, MODE_DATA_SIZE);

    length = ClassModeSense(DeviceObject,
                            modeData,
                            MODE_DATA_SIZE,
                            MODE_PAGE_FLEXIBILE);

    if (length < sizeof(MODE_PARAMETER_HEADER)) {

        //
        // Retry the request one more time
        // in case of a check condition.
        //
        length = ClassModeSense(DeviceObject,
                                modeData,
                                MODE_DATA_SIZE,
                                MODE_PAGE_FLEXIBILE);

        if (length < sizeof(MODE_PARAMETER_HEADER)) {

            ExFreePool(modeData);
            return(DRIVE_TYPE_NONE);
        }
    }

    //
    // Look for the flexible disk mode page.
    //

    pageData = ClassFindModePage( modeData,
                                  length,
                                  MODE_PAGE_FLEXIBILE,
                                  TRUE);

    //
    // Make sure the page is returned and is large enough.
    //

    if ((pageData != NULL) &&
        (pageData->PageLength + 2 >=
         offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {

       //
       // Pull out the heads, cylinders, and sectors.
       //

       numberOfHeads = pageData->NumberOfHeads;
       maximumTrack = pageData->NumberOfCylinders[1];
       maximumTrack |= pageData->NumberOfCylinders[0] << 8;
       sectorsPerTrack = pageData->SectorsPerTrack;


       //
       // Convert from number of cylinders to maximum track.
       //

       maximumTrack--;

       //
       // Search for the maximum supported media. Based on the number of heads,
       // sectors per track and number of cylinders
       //
       for (index = 0; index < NUMBER_OF_DRIVE_MEDIA_COMBINATIONS; index++) {

            //
            // Walk the table forward until the drive capacity holds all of the
            // data and the bytes per setor are equal
            //

            if (DriveMediaConstants[index].NumberOfHeads == numberOfHeads &&
                DriveMediaConstants[index].MaximumTrack == maximumTrack &&
                DriveMediaConstants[index].SectorsPerTrack ==sectorsPerTrack) {

                ExFreePool(modeData);

                //
                // index is now a drive media combination.  Compare this to
                // the maximum drive media type in the drive media table.
                //

                for (length = 0; length < NUMBER_OF_DRIVE_TYPES; length++) {

                    if (DriveMediaLimits[length].HighestDriveMediaType == index) {
                        return(length);
                    }
                }
                return(DRIVE_TYPE_NONE);
           }
       }

       // If the maximum track is greater than 8 bits then divide the
       // number of tracks by 3 and multiply the number of heads by 3.
       // This is a special case for the 20.8 MB floppy.
       //

       if (!applyFix && maximumTrack >= 0x0100) {
           maximumTrack++;
           maximumTrack /= 3;
           maximumTrack--;
           numberOfHeads *= 3;
       } else {
           ExFreePool(modeData);
           return(DRIVE_TYPE_NONE);
       }

    }

    ExFreePool(modeData);
    return(DRIVE_TYPE_NONE);
}


BOOLEAN
FlCheckFormatParameters(
    IN PDEVICE_OBJECT DeviceObject,
    IN PFORMAT_PARAMETERS FormatParameters
    )

/*++

Routine Description:

    This routine checks the supplied format parameters to make sure that
    they'll work on the drive to be formatted.

Arguments:

    DeviceObject - Pointer to the device object to be formated.

    FormatParameters - a pointer to the caller's parameters for the FORMAT.

Return Value:

    TRUE if parameters are OK.
    FALSE if the parameters are bad.

--*/

{
    PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
    DRIVE_MEDIA_TYPE driveMediaType;
    ULONG index;

    PAGED_CODE();

    //
    // Get the device type.
    //

    index = DetermineDriveType(DeviceObject);

    if (index == DRIVE_TYPE_NONE) {

        //
        // If the determine device type failed then just use the media type
        // and try the parameters.
        //

        driveMediaType = Drive360Media160;

        while (( DriveMediaConstants[driveMediaType].MediaType !=
               FormatParameters->MediaType ) &&
               ( driveMediaType < Drive288Media288) ) {

               driveMediaType++;
        }

    } else {

        //
        // Figure out which entry in the DriveMediaConstants table to use.
        //

        driveMediaType =
            DriveMediaLimits[index].HighestDriveMediaType;

        while ( ( DriveMediaConstants[driveMediaType].MediaType !=
            FormatParameters->MediaType ) &&
            ( driveMediaType > DriveMediaLimits[index].
            LowestDriveMediaType ) ) {

            driveMediaType--;
        }

    }


    if ( DriveMediaConstants[driveMediaType].MediaType !=
        FormatParameters->MediaType ) {
        return FALSE;

    } else {

        driveMediaConstants = &DriveMediaConstants[driveMediaType];

        if ( ( FormatParameters->StartHeadNumber >
            (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
            ( FormatParameters->EndHeadNumber >
            (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
            ( FormatParameters->StartCylinderNumber >
            driveMediaConstants->MaximumTrack ) ||
            ( FormatParameters->EndCylinderNumber >
            driveMediaConstants->MaximumTrack ) ||
            ( FormatParameters->EndCylinderNumber <
            FormatParameters->StartCylinderNumber ) ) {

            return FALSE;

        } else {

            return TRUE;
        }
    }
}

NTSTATUS
FormatMedia(
    PDEVICE_OBJECT DeviceObject,
    MEDIA_TYPE MediaType
    )
/*++

Routine Description:

    This routine formats the floppy disk.  The entire floppy is formated in
    one shot.

Arguments:

    DeviceObject - Supplies the device object to be tested.

    Irp - Supplies a pointer to the requesting Irp.

    MediaType - Supplies the media type format the device for.

Return Value:

    Returns a status for the operation.

--*/
{
    PVOID modeData;
    PSCSI_REQUEST_BLOCK srb;
    PMODE_FLEXIBLE_DISK_PAGE pageData;
    DRIVE_MEDIA_TYPE driveMediaType;
    PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
    ULONG length;
    NTSTATUS status;

    PAGED_CODE();

    modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);

    if (modeData == NULL) {
        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    RtlZeroMemory(modeData, MODE_DATA_SIZE);

    length = ClassModeSense(DeviceObject,
                            modeData,
                            MODE_DATA_SIZE,
                            MODE_PAGE_FLEXIBILE);

    if (length < sizeof(MODE_PARAMETER_HEADER)) {
        ExFreePool(modeData);
        return(STATUS_INVALID_DEVICE_REQUEST);
    }

    //
    // Look for the flexible disk mode page.
    //

    pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);

    //
    // Make sure the page is returned and is large enough.
    //

    if ((pageData == NULL) ||
        (pageData->PageLength + 2 <
         offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {

        ExFreePool(modeData);
        return(STATUS_INVALID_DEVICE_REQUEST);

    }

    //
    // Look for a drive media type which matches the requested media type.
    //
    //
    //start from Drive120MMedia120M instead of Drive2080Media2080
    //
    for (driveMediaType = Drive120MMedia120M;
    DriveMediaConstants[driveMediaType].MediaType != MediaType;
    driveMediaType--) {
         if (driveMediaType == Drive360Media160) {

             ExFreePool(modeData);
             return(STATUS_INVALID_PARAMETER);

         }
    }

    driveMediaConstants = &DriveMediaConstants[driveMediaType];

    if ((pageData->NumberOfHeads != driveMediaConstants->NumberOfHeads) ||
        (pageData->SectorsPerTrack != driveMediaConstants->SectorsPerTrack) ||
        ((pageData->NumberOfCylinders[0] != (UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8)) &&
         (pageData->NumberOfCylinders[1] != (UCHAR)driveMediaConstants->MaximumTrack+1)) ||
        (pageData->BytesPerSector[0] != driveMediaConstants->BytesPerSector >> 8 )) {

        //
        // Update the flexible parameters page with the new parameters.
        //

        pageData->NumberOfHeads = driveMediaConstants->NumberOfHeads;
        pageData->SectorsPerTrack = driveMediaConstants->SectorsPerTrack;
        pageData->NumberOfCylinders[0] = (UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8);
        pageData->NumberOfCylinders[1] = (UCHAR)driveMediaConstants->MaximumTrack+1;
        pageData->BytesPerSector[0] = driveMediaConstants->BytesPerSector >> 8;

        //
        // Clear the mode parameter header.
        //

        RtlZeroMemory(modeData, sizeof(MODE_PARAMETER_HEADER));

        //
        // Set the length equal to the length returned for the flexible page.
        //

        length = pageData->PageLength + 2;

        //
        // Copy the page after the mode parameter header.
        //

        RtlMoveMemory((PCHAR) modeData + sizeof(MODE_PARAMETER_HEADER),
                pageData,
                length
                );
            length += sizeof(MODE_PARAMETER_HEADER);


        //
        // Allocate a Srb for the format command.
        //

        srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

        if (srb == NULL) {

            ExFreePool(modeData);
            return(STATUS_INSUFFICIENT_RESOURCES);
        }

        RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

        srb->CdbLength = 6;
        srb->Cdb[0] = SCSIOP_MODE_SELECT;
        srb->Cdb[4] = (UCHAR) length;

        //
        // Set the PF bit.
        //

        srb->Cdb[1] |= 0x10;

        //
        // Set timeout value.
        //

        srb->TimeOutValue = 2;

        //
        // Send the mode select data.
        //

        status = ClassSendSrbSynchronous(DeviceObject,
                  srb,
                  modeData,
                  length,
                  TRUE
                  );

        //
        // The mode data not needed any more so free it.
        //

        ExFreePool(modeData);

        if (!NT_SUCCESS(status)) {
            ExFreePool(srb);
            return(status);
        }

    } else {

        //
        // The mode data not needed any more so free it.
        //

        ExFreePool(modeData);

        //
        // Allocate a Srb for the format command.
        //

        srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

        if (srb == NULL) {
            return(STATUS_INSUFFICIENT_RESOURCES);
        }

    }

    RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

    srb->CdbLength = 6;

    srb->Cdb[0] = SCSIOP_FORMAT_UNIT;

    //
    // Set timeout value.
    //

    srb->TimeOutValue = 10 * 60;

    status = ClassSendSrbSynchronous(DeviceObject,
                                     srb,
                                     NULL,
                                     0,
                                     FALSE
                                     );
    ExFreePool(srb);

    return(status);

}

VOID
ScsiFlopProcessError(
    PDEVICE_OBJECT DeviceObject,
    PSCSI_REQUEST_BLOCK Srb,
    NTSTATUS *Status,
    BOOLEAN *Retry
    )
/*++

Routine Description:

   This routine checks the type of error.  If the error indicate the floppy
   controller needs to be reinitialize a command is made to do it.

Arguments:

    DeviceObject - Supplies a pointer to the device object.

    Srb - Supplies a pointer to the failing Srb.

    Status - Status with which the IRP will be completed.

    Retry - Indication of whether the request will be retried.

Return Value:

    None.

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
    PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
    PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
    PIO_STACK_LOCATION irpStack;
    PIRP irp;
    PSCSI_REQUEST_BLOCK srb;
    LARGE_INTEGER largeInt;
    PCOMPLETION_CONTEXT context;
    PCDB cdb;
    ULONG_PTR alignment;
    ULONG majorFunction;

    UNREFERENCED_PARAMETER(Status);
    UNREFERENCED_PARAMETER(Retry);

    largeInt.QuadPart = 1;

    //
    // Check the status.  The initialization command only needs to be sent
    // if UNIT ATTENTION or LUN NOT READY is returned.
    //

    if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {

        //
        // The drive does not require reinitialization.
        //

        return;
    }

    //
    // Reset the drive type.
    //

    diskData->DriveType = DRIVE_TYPE_NONE;
    diskData->IsDMF = FALSE;

    fdoExtension->DiskGeometry.MediaType = Unknown;

    if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {

        // FLPYDISK.SYS never returns a non-zero value for the ChangeCount
        // on an IOCTL_DISK_CHECK_VERIFY.  Some things seem to work better
        // if we do the same.  In particular, FatVerifyVolume() can exit between
        // the IOCTL_DISK_CHECK_VERIFY and the IOCTL_DISK_GET_DRIVE_GEOMETRY
        // if a non-zero ChangeCount is returned, and this appears to cause
        // issues formatting unformatted media in some situations.
        //
        // This is something that should probably be revisited at some point.
        //
        fdoExtension->MediaChangeCount = 0;

        if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) &&
            (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED)) {

            struct _START_STOP *startStopCdb;

            DebugPrint((2,"Sending SCSIOP_START_STOP_UNIT\n"));

            context = ExAllocatePool(NonPagedPoolNx,
                                     sizeof(COMPLETION_CONTEXT));

            if (context == NULL) {

                return;
            }
#if (NTDDI_VERSION >= NTDDI_WIN8)
            srb = &context->Srb.Srb;
#else
            srb = &context->Srb;
#endif

            RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

            srb->SrbFlags = SRB_FLAGS_DISABLE_AUTOSENSE;

            srb->CdbLength = 6;

            startStopCdb = (struct _START_STOP *)srb->Cdb;

            startStopCdb->OperationCode = SCSIOP_START_STOP_UNIT;
            startStopCdb->Start = 1;

            // A Start Stop Unit request has no transfer buffer.
            // Set the request to IRP_MJ_FLUSH_BUFFERS when calling
            // IoBuildAsynchronousFsdRequest() so that it ignores
            // the buffer pointer and buffer length parameters.
            //
            majorFunction = IRP_MJ_FLUSH_BUFFERS;

        } else if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) {

            // Return ERROR_UNRECOGNIZED_MEDIA instead of
            // STATUS_DEVICE_DATA_ERROR to make shell happy.
            //
            *Status = STATUS_UNRECOGNIZED_MEDIA;
            return;

        } else {

            return;
        }

    } else if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
             senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INIT_COMMAND_REQUIRED ||
             (senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {

        ULONG sizeNeeded;
        ULONG tmpSize;
        BOOLEAN overFlow;

        DebugPrint((1, "ScsiFlopProcessError: Reinitializing the floppy.\n"));

        //
        // Send the special mode sense command to enable writes on the
        // floptical drive.
        //

        alignment = DeviceObject->AlignmentRequirement ?
            DeviceObject->AlignmentRequirement : 1;

        sizeNeeded = 0;
        overFlow = TRUE;
        if (SUCCEEDED(ULongAdd(sizeof(COMPLETION_CONTEXT), 0x2a, &tmpSize))) {

            if (SUCCEEDED(ULongAdd(tmpSize, (ULONG) alignment, &sizeNeeded))) {
                overFlow = FALSE;
            }
        }

        context = NULL;

        if (!overFlow) {
            context = ExAllocatePool(NonPagedPoolNx, sizeNeeded);
        }

        if (context == NULL) {

            //
            // If there is not enough memory to fulfill this request,
            // simply return. A subsequent retry will fail and another
            // chance to start the unit.
            //

            return;
        }

#if (NTDDI_VERSION >= NTDDI_WIN8)
        srb = &context->Srb.Srb;
#else
        srb = &context->Srb;
#endif

        RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

        //
        // Set the transfer length.
        //

        srb->DataTransferLength = 0x2a;
        srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;

        //
        // The data buffer must be aligned.
        //

        srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
            ~(alignment - 1));


        //
        // Build the start unit CDB.
        //

        srb->CdbLength = 6;
        cdb = (PCDB)srb->Cdb;
        cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
        cdb->MODE_SENSE.PageCode = 0x2e;
        cdb->MODE_SENSE.AllocationLength = 0x2a;

        majorFunction = IRP_MJ_READ;

    } else {

        return;
    }

    context->DeviceObject = DeviceObject;

    //
    // Write length to SRB.
    //

    srb->Length = SCSI_REQUEST_BLOCK_SIZE;

    srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
    srb->TimeOutValue = fdoExtension->TimeOutValue;

    //
    // Build the asynchronous request
    // to be sent to the port driver.
    //

    irp = IoBuildAsynchronousFsdRequest(majorFunction,
                       DeviceObject,
                       srb->DataBuffer,
                       srb->DataTransferLength,
                       &largeInt,
                       NULL);

    if(irp == NULL) {
        ExFreePool(context);
        return;
    }


    IoSetCompletionRoutine(irp,
           (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
           context,
           TRUE,
           TRUE,
           TRUE);

    ClassAcquireRemoveLock(DeviceObject, irp);

    irpStack = IoGetNextIrpStackLocation(irp);

    irpStack->MajorFunction = IRP_MJ_SCSI;

    srb->OriginalRequest = irp;

    //
    // Save SRB address in next stack for port driver.
    //

    irpStack->Parameters.Others.Argument1 = (PVOID)srb;

    //
    // Can't release the remove lock yet - let ClassAsynchronousCompletion
    // take care of that for us.
    //

    (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);

    return;
}

NTSTATUS
FlopticalFormatMedia(
    PDEVICE_OBJECT DeviceObject,
    PFORMAT_PARAMETERS Format
    )
/*++

Routine Description:

    This routine is used to do perform a format tracks for the 20.8 MB
    floppy.  Because the device does not support format tracks and the full
    format takes a long time a write of zeros is done instead.

Arguments:

    DeviceObject - Supplies the device object to be tested.

    Format - Supplies the format parameters.

Return Value:

    Returns a status for the operation.

--*/
{
    IO_STATUS_BLOCK ioStatus;
    PIRP irp;
    KEVENT event;
    LARGE_INTEGER offset;
    ULONG length;
    PVOID buffer;
    PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
    NTSTATUS status;

    PAGED_CODE();

    driveMediaConstants = &DriveMediaConstants[Drive2080Media2080];

    //
    // Calculate the length of the buffer.
    //

    length = ((Format->EndCylinderNumber - Format->StartCylinderNumber) *
        driveMediaConstants->NumberOfHeads +
        Format->EndHeadNumber - Format->StartHeadNumber + 1) *
        driveMediaConstants->SectorsPerTrack *
        driveMediaConstants->BytesPerSector;

    buffer = ExAllocatePool(NonPagedPoolNxCacheAligned, length);

    if (buffer == NULL) {
        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    RtlZeroMemory(buffer, length);

    offset.QuadPart =
    (Format->StartCylinderNumber * driveMediaConstants->NumberOfHeads +
    Format->StartHeadNumber) * driveMediaConstants->SectorsPerTrack *
    driveMediaConstants->BytesPerSector;

    //
    // Set the event object to the unsignaled state.
    // It will be used to signal request completion.
    //

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    //
    // Build the synchronous request with data transfer.
    //

    irp = IoBuildSynchronousFsdRequest(
       IRP_MJ_WRITE,
       DeviceObject,
       buffer,
       length,
       &offset,
       &event,
       &ioStatus);

    if (irp != NULL) {
        status = IoCallDriver(DeviceObject, irp);

        if (status == STATUS_PENDING) {

            //
            // Wait for the request to complete if necessary.
            //

            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        }

        //
        // If the call  driver suceeded then set the status to the status block.
        //

        if (NT_SUCCESS(status)) {
            status = ioStatus.Status;
        }
    } else {
       status = STATUS_INSUFFICIENT_RESOURCES;
    }

    ExFreePool(buffer);

    return(status);

}


NTSTATUS
ScsiFlopRemoveDevice(
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR Type
    )
/*++

Routine Description:

    This routine is responsible for releasing any resources in use by the
    sfloppy driver.  This routine is called
    when all outstanding requests have been completed and the driver has
    disappeared - no requests may be issued to the lower drivers.

Arguments:

    DeviceObject - the device object being removed

    Type - the type of remove operation (QUERY, REMOVE or CANCEL)

Return Value:

    for a query - success if the device can be removed or a failure code
                  indiciating why not.

    for a remove or cancel - STATUS_SUCCESS

--*/

{
    PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
        DeviceObject->DeviceExtension;
    PDISK_DATA diskData = deviceExtension->CommonExtension.DriverData;
    NTSTATUS status;

    PAGED_CODE();

    if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
       (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
        return STATUS_SUCCESS;
    }

    if (Type == IRP_MN_REMOVE_DEVICE){
        if(deviceExtension->DeviceDescriptor) {
            ExFreePool(deviceExtension->DeviceDescriptor);
            deviceExtension->DeviceDescriptor = NULL;
        }

        if(deviceExtension->AdapterDescriptor) {
            ExFreePool(deviceExtension->AdapterDescriptor);
            deviceExtension->AdapterDescriptor = NULL;
        }

        if(deviceExtension->SenseData) {
            ExFreePool(deviceExtension->SenseData);
            deviceExtension->SenseData = NULL;
        }

        ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
    }

    if(diskData->FloppyInterfaceString.Buffer != NULL) {
        
        status = IoSetDeviceInterfaceState(
                   &(diskData->FloppyInterfaceString),
                   FALSE);

        if (!NT_SUCCESS(status)) {
            // Failed to disable device interface during removal. Not a fatal error.
            DebugPrint((1, "ScsiFlopRemoveDevice: Unable to set device "
                           "interface state to FALSE for fdo %p "
                           "[%08lx]\n",
                        DeviceObject, status));
        }

        RtlFreeUnicodeString(&(diskData->FloppyInterfaceString));
        RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
    }

    if(Type == IRP_MN_REMOVE_DEVICE) {
        IoGetConfigurationInformation()->FloppyCount--;
    }

    return STATUS_SUCCESS;
}


NTSTATUS
ScsiFlopStopDevice(
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR Type
    )
{
    UNREFERENCED_PARAMETER(DeviceObject);
    UNREFERENCED_PARAMETER(Type);

    return STATUS_SUCCESS;
}


NTSTATUS
USBFlopGetMediaTypes(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
/*++

Routine Description:

    This routines determines the current or default geometry of the drive
    for IOCTL_DISK_GET_DRIVE_GEOMETRY, or all currently supported geometries
    of the drive (which is determined by its currently inserted media) for
    IOCTL_DISK_GET_MEDIA_TYPES.

    The returned geometries are determined by issuing a Read Format Capacities
    request and then matching the returned {Number of Blocks, Block Length}
    pairs in a table of known floppy geometries.

Arguments:

    DeviceObject - Supplies the device object.

    Irp - A IOCTL_DISK_GET_DRIVE_GEOMETRY or a IOCTL_DISK_GET_MEDIA_TYPES Irp.
          If NULL, the device geometry is updated with the current device
          geometry.

Return Value:

    Status is returned.

--*/
    PFUNCTIONAL_DEVICE_EXTENSION    fdoExtension;
    PIO_STACK_LOCATION              irpStack;
    ULONG                           ioControlCode;
    PDISK_GEOMETRY                  outputBuffer;
    PDISK_GEOMETRY                  outputBufferEnd;
    ULONG                           outputBufferLength;
    PSCSI_REQUEST_BLOCK             srb;
    PVOID                           dataBuffer;
    ULONG                           dataTransferLength;
    struct _READ_FORMATTED_CAPACITIES *cdb;
    PFORMATTED_CAPACITY_LIST        capList;
    NTSTATUS                        status;

    PAGED_CODE();

    fdoExtension = DeviceObject->DeviceExtension;

    if (Irp != NULL) {

        // Get the Irp parameters
        //
        irpStack = IoGetCurrentIrpStackLocation(Irp);

        ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

        Irp->IoStatus.Information = 0;

        outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;

        outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;

        if (outputBufferLength < sizeof(DISK_GEOMETRY))
        {
            return STATUS_BUFFER_TOO_SMALL;
        }

        // Pointer arithmetic to allow multiple DISK_GEOMETRY's to be returned.
        // Rounds BufferEnd down to integral multiple of DISK_GEOMETRY structs.
        //
        outputBufferEnd = outputBuffer +
                          outputBufferLength / sizeof(DISK_GEOMETRY);

    } else {

        // No Irp to return the result in, just update the current geometry
        // in the device extension.
        //
        ioControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;

        outputBuffer        = NULL;

        outputBufferEnd     = NULL;

        outputBufferLength  = 0;
    }

    if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {

        fdoExtension->DiskGeometry.MediaType = Unknown;

        status = ClassReadDriveCapacity(DeviceObject);

        if (!NT_SUCCESS(status))
        {
            // If the media is not recongized, we want to return the default
            // geometry so that the media can be formatted.  Unrecognized media
            // causes SCSI_SENSE_MEDIUM_ERROR, which gets reported as
            // STATUS_DEVICE_DATA_ERROR.  Ignore these errors, but return other
            // errors, such as STATUS_NO_MEDIA_IN_DEVICE.
            //
            if (status != STATUS_UNRECOGNIZED_MEDIA)
            {
                DebugPrint((2,"IOCTL_DISK_GET_DRIVE_GEOMETRY returns %08X\n", status));

                return status;
            }
        }
    }

    // Allocate an SRB for the SCSIOP_READ_FORMATTED_CAPACITY request
    //
    srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

    if (srb == NULL)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // Allocate a transfer buffer for the SCSIOP_READ_FORMATTED_CAPACITY request
    // The length of the returned descriptor array is limited to a byte field
    // in the capacity list header.
    //
    dataTransferLength = sizeof(FORMATTED_CAPACITY_LIST) +
                         31 * sizeof(FORMATTED_CAPACITY_DESCRIPTOR);

    ASSERT(dataTransferLength < 0x100);

    dataBuffer = ExAllocatePool(NonPagedPoolNx, dataTransferLength);

    if (dataBuffer == NULL)
    {
        ExFreePool(srb);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // Initialize the SRB and CDB
    //
    RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

    RtlZeroMemory(dataBuffer, dataTransferLength);

    srb->CdbLength = sizeof(struct _READ_FORMATTED_CAPACITIES);

    srb->TimeOutValue = fdoExtension->TimeOutValue;

    cdb = (struct _READ_FORMATTED_CAPACITIES *)srb->Cdb;

    cdb->OperationCode = SCSIOP_READ_FORMATTED_CAPACITY;
    cdb->AllocationLength[1] = (UCHAR)dataTransferLength;

    //
    // Send down the SCSIOP_READ_FORMATTED_CAPACITY request
    //
    status = ClassSendSrbSynchronous(DeviceObject,
                                     srb,
                                     dataBuffer,
                                     dataTransferLength,
                                     FALSE);

    capList = (PFORMATTED_CAPACITY_LIST)dataBuffer;

    // If we don't get as much data as requested, it is not an error.
    //
    if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
    {
        status = STATUS_SUCCESS;
    }

    if (NT_SUCCESS(status) &&
        srb->DataTransferLength >= sizeof(FORMATTED_CAPACITY_LIST) &&
        capList->CapacityListLength &&
        capList->CapacityListLength % sizeof(FORMATTED_CAPACITY_DESCRIPTOR) == 0)
    {
        ULONG   NumberOfBlocks;
        ULONG   BlockLength;
        ULONG   count;
        ULONG   i, j;
        LONG    currentGeometry;
        BOOLEAN capacityMatches[FLOPPY_CAPACITIES];

        // Subtract the size of the Capacity List Header to get
        // just the size of the Capacity List Descriptor array.
        //
        srb->DataTransferLength -= sizeof(FORMATTED_CAPACITY_LIST);

        // Only look at the Capacity List Descriptors that were actually
        // returned.
        //
        if (srb->DataTransferLength < capList->CapacityListLength)
        {
            count = srb->DataTransferLength /
                    sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
        }
        else
        {
            count = capList->CapacityListLength /
                    sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
        }

        // Updated only if a match is found for the first Capacity List
        // Descriptor returned by the device.
        //
        currentGeometry = -1;

        // Initialize the array of capacities that hit a match.
        //
        RtlZeroMemory(capacityMatches, sizeof(capacityMatches));

        // Iterate over each Capacity List Descriptor returned from the device
        // and record matching capacities in the capacity match array.
        //
        for (i = 0; i < count; i++)
        {
            NumberOfBlocks = (capList->Descriptors[i].NumberOfBlocks[0] << 24) +
                             (capList->Descriptors[i].NumberOfBlocks[1] << 16) +
                             (capList->Descriptors[i].NumberOfBlocks[2] <<  8) +
                             (capList->Descriptors[i].NumberOfBlocks[3]);

            BlockLength = (capList->Descriptors[i].BlockLength[0] << 16) +
                          (capList->Descriptors[i].BlockLength[1] <<  8) +
                          (capList->Descriptors[i].BlockLength[2]);

            // Given the {NumberOfBlocks, BlockLength} from this Capacity List
            // Descriptor, find a matching entry in FloppyCapacities[].
            //
            for (j = 0; j < FLOPPY_CAPACITIES; j++)
            {
                if (NumberOfBlocks == FloppyCapacities[j].NumberOfBlocks &&
                    BlockLength    == FloppyCapacities[j].BlockLength)
                {
                    // A matching capacity was found, record it.
                    //
                    capacityMatches[j] = TRUE;

                    // A match was found for the first Capacity List
                    // Descriptor returned by the device.
                    //
                    if (i == 0)
                    {
                        currentGeometry = j;
                    }
                } else if ((capList->Descriptors[i].Valid) &&
                           (BlockLength == FloppyCapacities[j].BlockLength)) {

                    ULONG inx;
                    ULONG mediaInx;

                    //
                    // Check if this is 32MB media type. 32MB media
                    // reports variable NumberOfBlocks. So we cannot
                    // use that to determine the drive type
                    //
                    inx = DetermineDriveType(DeviceObject);
                    if (inx != DRIVE_TYPE_NONE) {
                        mediaInx = DriveMediaLimits[inx].HighestDriveMediaType;
                        if ((DriveMediaConstants[mediaInx].MediaType)
                             == F3_32M_512) {
                            capacityMatches[j] = TRUE;

                            if (i == 0) {
                                currentGeometry = j;
                            }
                        }
                    }
                }
            }
        }

        // Default status is STATUS_UNRECOGNIZED_MEDIA, unless we return
        // either STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW.
        //
        status = STATUS_UNRECOGNIZED_MEDIA;

        if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {

            if (currentGeometry != -1)
            {
                // Update the current device geometry
                //
                fdoExtension->DiskGeometry = FloppyGeometries[currentGeometry];

                //
                // Calculate sector to byte shift.
                //

                WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
                          fdoExtension->SectorShift);

                fdoExtension->CommonExtension.PartitionLength.QuadPart =
                    (LONGLONG)FloppyCapacities[currentGeometry].NumberOfBlocks *
                    FloppyCapacities[currentGeometry].BlockLength;

                DebugPrint((2,"geometry  is: %3d %2d %d %2d %4d  %2d  %08X\n",
                            fdoExtension->DiskGeometry.Cylinders.LowPart,
                            fdoExtension->DiskGeometry.MediaType,
                            fdoExtension->DiskGeometry.TracksPerCylinder,
                            fdoExtension->DiskGeometry.SectorsPerTrack,
                            fdoExtension->DiskGeometry.BytesPerSector,
                            fdoExtension->SectorShift,
                            fdoExtension->CommonExtension.PartitionLength.LowPart));

                // Return the current device geometry
                //
                if (Irp != NULL)
                {
                    *outputBuffer = FloppyGeometries[currentGeometry];

                    Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
                }

                status = STATUS_SUCCESS;
            }

        } else {

            // Iterate over the capacities and return the geometry
            // corresponding to each matching Capacity List Descriptor
            // returned from the device.
            //
            // The resulting list should be in sorted ascending order,
            // assuming that the FloppyGeometries[] array is in sorted
            // ascending order.
            //
            for (i = 0; i < FLOPPY_CAPACITIES; i++)
            {
                if (capacityMatches[i] && FloppyCapacities[i].CanFormat)
                {
                    if (outputBuffer < outputBufferEnd)
                    {
                        *outputBuffer++ = FloppyGeometries[i];

                        Irp->IoStatus.Information += sizeof(DISK_GEOMETRY);

                        DebugPrint((2,"geometry    : %3d %2d %d %2d %4d\n",
                                    FloppyGeometries[i].Cylinders.LowPart,
                                    FloppyGeometries[i].MediaType,
                                    FloppyGeometries[i].TracksPerCylinder,
                                    FloppyGeometries[i].SectorsPerTrack,
                                    FloppyGeometries[i].BytesPerSector));

                        status = STATUS_SUCCESS;
                    }
                    else
                    {
                        // We ran out of output buffer room before we ran out
                        // geometries to return.
                        //
                        status = STATUS_BUFFER_OVERFLOW;
                    }
                }
            }
        }
    }
    else if (NT_SUCCESS(status))
    {
        // The SCSIOP_READ_FORMATTED_CAPACITY request was successful, but
        // returned data does not appear valid.
        //
        status = STATUS_UNSUCCESSFUL;
    }

    ExFreePool(dataBuffer);
    ExFreePool(srb);

    return status;
}


NTSTATUS
USBFlopFormatTracks(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
/*++

Routine Description:

    This routines formats the specified tracks.  If multiple tracks are
    specified, each is formatted with a separate Format Unit request.

Arguments:

    DeviceObject - Supplies the device object.

    Irp - A IOCTL_DISK_FORMAT_TRACKS Irp.

Return Value:

    Status is returned.

--*/
    PFUNCTIONAL_DEVICE_EXTENSION    fdoExtension;
    PIO_STACK_LOCATION              irpStack;
    PFORMAT_PARAMETERS              formatParameters;
    PDISK_GEOMETRY                  geometry;
    PFORMATTED_CAPACITY             capacity;
    PSCSI_REQUEST_BLOCK             srb;
    PFORMAT_UNIT_PARAMETER_LIST     parameterList;
    PCDB12FORMAT                    cdb;
    ULONG                           i;
    ULONG                           cylinder, head;
    NTSTATUS                        status = STATUS_SUCCESS;

    PAGED_CODE();

    fdoExtension = DeviceObject->DeviceExtension;

    // Get the Irp parameters
    //
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        sizeof(FORMAT_PARAMETERS))
    {
        return STATUS_INVALID_PARAMETER;
    }

    formatParameters = (PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;

    // Find the geometry / capacity entries corresponding to the format
    // parameters MediaType
    //
    geometry = NULL;
    capacity = NULL;

    for (i=0; i<FLOPPY_CAPACITIES; i++)
    {
        if (FloppyGeometries[i].MediaType == formatParameters->MediaType)
        {
            geometry = &FloppyGeometries[i];
            capacity = &FloppyCapacities[i];

            break;
        }
    }

    if (geometry == NULL)
    {
        return STATUS_INVALID_PARAMETER;
    }

    // Check if the format parameters are valid
    //
    if ((formatParameters->StartCylinderNumber >
         geometry->Cylinders.LowPart - 1)       ||

        (formatParameters->EndCylinderNumber >
         geometry->Cylinders.LowPart - 1)       ||

        (formatParameters->StartHeadNumber >
         geometry->TracksPerCylinder - 1)       ||

        (formatParameters->EndHeadNumber >
         geometry->TracksPerCylinder - 1)       ||

        (formatParameters->StartCylinderNumber >
         formatParameters->EndCylinderNumber)   ||

        (formatParameters->StartHeadNumber >
         formatParameters->EndHeadNumber))
    {
        return STATUS_INVALID_PARAMETER;
    }

    // Don't low level format LS-120 media, Imation says it's best to not
    // do this.
    //
    if ((formatParameters->MediaType == F3_120M_512) ||
        (formatParameters->MediaType == F3_240M_512) ||
        (formatParameters->MediaType == F3_32M_512))
    {
        return STATUS_SUCCESS;
    }

    // Allocate an SRB for the SCSIOP_FORMAT_UNIT request
    //
    srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);

    if (srb == NULL)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // Allocate a transfer buffer for the SCSIOP_FORMAT_UNIT parameter list
    //
    parameterList = ExAllocatePool(NonPagedPoolNx,
                                   sizeof(FORMAT_UNIT_PARAMETER_LIST));

    if (parameterList == NULL)
    {
        ExFreePool(srb);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    // Initialize the parameter list
    //
    RtlZeroMemory(parameterList, sizeof(FORMAT_UNIT_PARAMETER_LIST));

    parameterList->DefectListHeader.SingleTrack = 1;
    parameterList->DefectListHeader.DisableCert = 1;  // TEAC requires this set
    parameterList->DefectListHeader.FormatOptionsValid = 1;
    parameterList->DefectListHeader.DefectListLengthLsb = 8;

    parameterList->FormatDescriptor.NumberOfBlocks[0] =
        (UCHAR)((capacity->NumberOfBlocks >> 24) & 0xFF);

    parameterList->FormatDescriptor.NumberOfBlocks[1] =
        (UCHAR)((capacity->NumberOfBlocks >> 16) & 0xFF);

    parameterList->FormatDescriptor.NumberOfBlocks[2] =
        (UCHAR)((capacity->NumberOfBlocks >> 8) & 0xFF);

    parameterList->FormatDescriptor.NumberOfBlocks[3] =
        (UCHAR)(capacity->NumberOfBlocks & 0xFF);

    parameterList->FormatDescriptor.BlockLength[0] =
        (UCHAR)((capacity->BlockLength >> 16) & 0xFF);

    parameterList->FormatDescriptor.BlockLength[1] =
        (UCHAR)((capacity->BlockLength >> 8) & 0xFF);

    parameterList->FormatDescriptor.BlockLength[2] =
        (UCHAR)(capacity->BlockLength & 0xFF);


    for (cylinder =  formatParameters->StartCylinderNumber;
         cylinder <= formatParameters->EndCylinderNumber;
         cylinder++)
    {
        for (head =  formatParameters->StartHeadNumber;
             head <= formatParameters->EndHeadNumber;
             head++)
        {
            // Initialize the SRB and CDB
            //
            RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

            srb->CdbLength = sizeof(CDB12FORMAT);

            srb->TimeOutValue = fdoExtension->TimeOutValue;

            cdb = (PCDB12FORMAT)srb->Cdb;

            cdb->OperationCode = SCSIOP_FORMAT_UNIT;
            cdb->DefectListFormat = 7;
            cdb->FmtData = 1;
            cdb->TrackNumber = (UCHAR)cylinder;
            cdb->ParameterListLengthLsb = sizeof(FORMAT_UNIT_PARAMETER_LIST);

            parameterList->DefectListHeader.Side = (UCHAR)head;

            //
            // Send down the SCSIOP_FORMAT_UNIT request
            //
            status = ClassSendSrbSynchronous(DeviceObject,
                                             srb,
                                             parameterList,
                                             sizeof(FORMAT_UNIT_PARAMETER_LIST),
                                             TRUE);

            if (!NT_SUCCESS(status))
            {
                break;
            }
        }
        if (!NT_SUCCESS(status))
        {
            break;
        }
    }

    if (NT_SUCCESS(status) && formatParameters->StartCylinderNumber == 0)
    {
        // Update the device geometry
        //

        DebugPrint((2,"geometry was: %3d %2d %d %2d %4d  %2d  %08X\n",
                    fdoExtension->DiskGeometry.Cylinders.LowPart,
                    fdoExtension->DiskGeometry.MediaType,
                    fdoExtension->DiskGeometry.TracksPerCylinder,
                    fdoExtension->DiskGeometry.SectorsPerTrack,
                    fdoExtension->DiskGeometry.BytesPerSector,
                    fdoExtension->SectorShift,
                    fdoExtension->CommonExtension.PartitionLength.LowPart));

        fdoExtension->DiskGeometry = *geometry;

        //
        // Calculate sector to byte shift.
        //

        WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
                  fdoExtension->SectorShift);

        fdoExtension->CommonExtension.PartitionLength.QuadPart =
            (LONGLONG)capacity->NumberOfBlocks *
            capacity->BlockLength;

        DebugPrint((2,"geometry  is: %3d %2d %d %2d %4d  %2d  %08X\n",
                    fdoExtension->DiskGeometry.Cylinders.LowPart,
                    fdoExtension->DiskGeometry.MediaType,
                    fdoExtension->DiskGeometry.TracksPerCylinder,
                    fdoExtension->DiskGeometry.SectorsPerTrack,
                    fdoExtension->DiskGeometry.BytesPerSector,
                    fdoExtension->SectorShift,
                    fdoExtension->CommonExtension.PartitionLength.LowPart));
    }

    // Free everything we allocated
    //
    ExFreePool(parameterList);
    ExFreePool(srb);

    return status;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS