2278 lines
56 KiB
C
2278 lines
56 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
floppy.c
|
||
|
||
Abstract:
|
||
|
||
SCSI floppy class driver
|
||
|
||
Author:
|
||
|
||
Jeff Havens (jhavens)
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "stddef.h"
|
||
#include "ntddk.h"
|
||
#include "scsi.h"
|
||
#include "class.h"
|
||
|
||
#define MODE_DATA_SIZE 192
|
||
#define SCSI_FLOPPY_TIMEOUT 20
|
||
|
||
//
|
||
// 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_MEDIA_COMBINATIONS 20
|
||
#define NUMBER_OF_DRIVE_TYPES 6
|
||
#define DRIVE_TYPE_NONE NUMBER_OF_DRIVE_TYPES
|
||
|
||
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
|
||
} 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, Drive144Media144}, // DRIVE_TYPE_1440
|
||
{ Drive288Media288, Drive288Media288}, // DRIVE_TYPE_2880
|
||
{ Drive2080Media2080, Drive2080Media2080 }
|
||
};
|
||
|
||
#endif
|
||
//
|
||
// For each drive/media combination, define important constants.
|
||
//
|
||
|
||
typedef struct _DRIVE_MEDIA_CONSTANTS {
|
||
MEDIA_TYPE MediaType;
|
||
USHORT BytesPerSector;
|
||
UCHAR SectorsPerTrack;
|
||
UCHAR 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[NUMBER_OF_DRIVE_MEDIA_COMBINATIONS] =
|
||
{
|
||
|
||
{ 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 }
|
||
|
||
};
|
||
|
||
//
|
||
// floppy device data
|
||
//
|
||
|
||
typedef struct _DISK_DATA {
|
||
ULONG DriveType;
|
||
} DISK_DATA, *PDISK_DATA;
|
||
|
||
#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
NTSTATUS
|
||
ScsiFlopInitialize(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
BOOLEAN
|
||
FindScsiFlops(
|
||
IN PDRIVER_OBJECT DriveObject,
|
||
IN PDEVICE_OBJECT PortDeviceObject,
|
||
IN ULONG PortNumber
|
||
);
|
||
|
||
NTSTATUS
|
||
ScsiFlopCreate (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
ScsiFlopReadWrite(
|
||
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 PortNumber,
|
||
IN PULONG DeviceCount,
|
||
IN PIO_SCSI_CAPABILITIES PortCapabilities,
|
||
IN PSCSI_INQUIRY_DATA LunInfo
|
||
);
|
||
|
||
VOID
|
||
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
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
return ScsiFlopInitialize(DriverObject);
|
||
|
||
} // end DriverEntry()
|
||
|
||
|
||
NTSTATUS
|
||
ScsiFlopInitialize(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the hard floppy class driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by system.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG portNumber = 0;
|
||
PDEVICE_OBJECT portDeviceObject;
|
||
PFILE_OBJECT fileObject;
|
||
NTSTATUS status;
|
||
STRING deviceNameString;
|
||
UNICODE_STRING unicodeDeviceName;
|
||
CCHAR deviceNameBuffer[256];
|
||
BOOLEAN foundOne = FALSE;
|
||
|
||
DebugPrint((1,"\n\nSCSI floppy Class Driver\n"));
|
||
|
||
//
|
||
// Set up the device driver entry points.
|
||
//
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiFlopCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_READ] = ScsiFlopReadWrite;
|
||
DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiFlopReadWrite;
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiFlopDeviceControl;
|
||
|
||
//
|
||
// Open port driver device objects by name.
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// Create port driver name.
|
||
//
|
||
|
||
sprintf(deviceNameBuffer,
|
||
"\\Device\\ScsiPort%d",
|
||
portNumber);
|
||
|
||
DebugPrint((2,"ScsiFlopInitialize: Open %s\n", deviceNameBuffer));
|
||
|
||
RtlInitString(&deviceNameString,
|
||
deviceNameBuffer);
|
||
|
||
status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
|
||
&deviceNameString,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(status)){
|
||
break;
|
||
}
|
||
|
||
status = IoGetDeviceObjectPointer(&unicodeDeviceName,
|
||
FILE_READ_ATTRIBUTES,
|
||
&fileObject,
|
||
&portDeviceObject);
|
||
|
||
RtlFreeUnicodeString(&unicodeDeviceName);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// SCSI port driver exists.
|
||
//
|
||
|
||
foundOne |= FindScsiFlops(DriverObject,
|
||
portDeviceObject,
|
||
portNumber++);
|
||
|
||
|
||
//
|
||
// The port device object is no longer explictly needed by us so
|
||
// dereference the file handle.
|
||
//
|
||
|
||
ObDereferenceObject(fileObject);
|
||
|
||
} else {
|
||
break;
|
||
}
|
||
|
||
} while (status == STATUS_SUCCESS);
|
||
|
||
|
||
if (foundOne) {
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
return(status);
|
||
}
|
||
|
||
} // end ScsiFlopInitialize()
|
||
|
||
|
||
BOOLEAN
|
||
FindScsiFlops(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PortDeviceObject,
|
||
IN ULONG PortNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
DriverObject
|
||
PortDeviceObject - Device object use to send requests to port driver.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if a SCSI floppy is found.
|
||
--*/
|
||
|
||
{
|
||
PIO_SCSI_CAPABILITIES portCapabilities;
|
||
PULONG diskCount;
|
||
PCONFIGURATION_INFORMATION configurationInformation;
|
||
PCHAR buffer;
|
||
PSCSI_INQUIRY_DATA lunInfo;
|
||
PSCSI_ADAPTER_BUS_INFO adapterInfo;
|
||
PINQUIRYDATA inquiryData;
|
||
ULONG scsiBus;
|
||
NTSTATUS status;
|
||
BOOLEAN foundOne = FALSE;
|
||
|
||
//
|
||
// Call port driver to get adapter capabilities.
|
||
//
|
||
|
||
status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Call port driver to get inquiry information to find disks.
|
||
//
|
||
|
||
status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Get the number of disks already initialized.
|
||
//
|
||
|
||
configurationInformation = IoGetConfigurationInformation();
|
||
diskCount = &configurationInformation->FloppyCount;
|
||
|
||
adapterInfo = (PVOID) buffer;
|
||
|
||
for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
|
||
|
||
//
|
||
// Get the SCSI bus scan data for this bus.
|
||
//
|
||
|
||
lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
|
||
|
||
//
|
||
// Search list for unclaimed disk devices.
|
||
//
|
||
|
||
while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
|
||
|
||
inquiryData = (PVOID)lunInfo->InquiryData;
|
||
|
||
DebugPrint((3,"FindScsiDevices: Inquiry data at %lx\n",
|
||
inquiryData));
|
||
|
||
if ((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) &&
|
||
inquiryData->RemovableMedia &&
|
||
(!lunInfo->DeviceClaimed)) {
|
||
|
||
DebugPrint((1,
|
||
"FindScsiDevices: Vendor string is %.24s\n",
|
||
inquiryData->VendorId));
|
||
|
||
//
|
||
// Create device objects for floppy
|
||
//
|
||
|
||
status = CreateFlopDeviceObject(DriverObject,
|
||
PortDeviceObject,
|
||
PortNumber,
|
||
diskCount,
|
||
portCapabilities,
|
||
lunInfo);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Increment system floppy device count.
|
||
//
|
||
|
||
(*diskCount)++;
|
||
foundOne = TRUE;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get next LunInfo.
|
||
//
|
||
|
||
if (lunInfo->NextInquiryDataOffset == 0) {
|
||
break;
|
||
}
|
||
|
||
lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
|
||
}
|
||
}
|
||
|
||
ExFreePool(buffer);
|
||
|
||
return foundOne;
|
||
|
||
} // end FindScsiFlops()
|
||
|
||
|
||
NTSTATUS
|
||
CreateFlopDeviceObject(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PortDeviceObject,
|
||
IN ULONG PortNumber,
|
||
IN PULONG DeviceCount,
|
||
IN PIO_SCSI_CAPABILITIES PortCapabilities,
|
||
IN PSCSI_INQUIRY_DATA LunInfo
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
PortCapabilities - Pointer to structure returned by SCSI port
|
||
driver describing adapter capabilites (and limitations).
|
||
LunInfo - Pointer to configuration information for this device.
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
UCHAR ntNameBuffer[256];
|
||
UCHAR arcNameBuffer[256];
|
||
STRING ntNameString;
|
||
STRING arcNameString;
|
||
UNICODE_STRING ntUnicodeString;
|
||
UNICODE_STRING arcUnicodeString;
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PDISK_DATA diskData;
|
||
PVOID senseData;
|
||
|
||
DebugPrint((3,"CreateFlopDeviceObject: Enter routine\n"));
|
||
|
||
//
|
||
// Try to claim the device.
|
||
//
|
||
|
||
status = ScsiClassClaimDevice(
|
||
PortDeviceObject,
|
||
LunInfo,
|
||
FALSE,
|
||
&PortDeviceObject
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Create device object for this device.
|
||
//
|
||
|
||
sprintf(ntNameBuffer,
|
||
"\\Device\\Floppy%d",
|
||
*DeviceCount);
|
||
|
||
RtlInitString(&ntNameString,
|
||
ntNameBuffer);
|
||
|
||
DebugPrint((2,"CreateFlopDeviceObjects: Create device object %s\n",
|
||
ntNameBuffer));
|
||
|
||
//
|
||
// Convert ANSI string to Unicode.
|
||
//
|
||
|
||
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
|
||
&ntNameString,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((1,
|
||
"CreateDiskDeviceObjects: Cannot convert string %s\n",
|
||
ntNameBuffer));
|
||
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Create device object for this Floppy.
|
||
//
|
||
|
||
status = IoCreateDevice(DriverObject,
|
||
DEVICE_EXTENSION_SIZE,
|
||
&ntUnicodeString,
|
||
FILE_DEVICE_DISK,
|
||
FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((1,"CreateFlopDeviceObjects: Can not create device %s\n",
|
||
ntNameBuffer));
|
||
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
|
||
goto CreateFlopDeviceObjectExit;
|
||
}
|
||
|
||
//
|
||
// Indicate that IRPs should include MDLs.
|
||
//
|
||
|
||
deviceObject->Flags |= DO_DIRECT_IO;
|
||
|
||
//
|
||
// Set up required stack size in device object.
|
||
//
|
||
|
||
deviceObject->StackSize = PortDeviceObject->StackSize + 1;
|
||
|
||
deviceExtension = deviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Reset the drive type.
|
||
//
|
||
|
||
diskData = (PDISK_DATA) (deviceExtension + 1);
|
||
diskData->DriveType = DRIVE_TYPE_NONE;
|
||
|
||
//
|
||
// Disable synchronous transfer for floppy requests.
|
||
//
|
||
|
||
deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||
|
||
//
|
||
// This is the physical device.
|
||
//
|
||
|
||
deviceExtension->PhysicalDevice = deviceObject;
|
||
|
||
//
|
||
// Copy port device object to device extension.
|
||
//
|
||
|
||
deviceExtension->PortDeviceObject = PortDeviceObject;
|
||
|
||
//
|
||
// Save address of port driver capabilities.
|
||
//
|
||
|
||
deviceExtension->PortCapabilities = PortCapabilities;
|
||
|
||
//
|
||
// Allocate request sense buffer.
|
||
//
|
||
|
||
senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
|
||
|
||
if (senseData == NULL) {
|
||
|
||
//
|
||
// The buffer cannot be allocated.
|
||
// Delete device object.
|
||
//
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CreateFlopDeviceObjectExit;
|
||
}
|
||
|
||
//
|
||
// Set the sense data pointer in the device extension.
|
||
//
|
||
|
||
deviceExtension->SenseData = senseData;
|
||
|
||
//
|
||
// Path/TargetId/LUN describes a device location on the SCSI bus.
|
||
// This information comes from the LunInfo buffer.
|
||
//
|
||
|
||
deviceExtension->PathId = LunInfo->PathId;
|
||
deviceExtension->TargetId = LunInfo->TargetId;
|
||
deviceExtension->Lun = LunInfo->Lun;
|
||
|
||
//
|
||
// Set timeout value in seconds.
|
||
//
|
||
|
||
deviceExtension->TimeOutValue = SCSI_FLOPPY_TIMEOUT;
|
||
|
||
//
|
||
// Back pointer to device object.
|
||
//
|
||
|
||
deviceExtension->DeviceObject = deviceObject;
|
||
|
||
deviceExtension->ClassError = ScsiFlopProcessError;
|
||
|
||
//
|
||
// Make sure this is a flopppy device.
|
||
//
|
||
|
||
if (!IsFloppyDevice(deviceObject) || !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA) ||
|
||
(((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType != DIRECT_ACCESS_DEVICE)) {
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
ExFreePool(senseData);
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto CreateFlopDeviceObjectExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate buffer for drive geometry.
|
||
//
|
||
|
||
deviceExtension->DiskGeometry =
|
||
ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
|
||
|
||
if (deviceExtension->DiskGeometry == NULL) {
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
ExFreePool(senseData);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto CreateFlopDeviceObjectExit;
|
||
}
|
||
|
||
RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
|
||
|
||
//
|
||
// Flops are not partitionable so starting offset is 0.
|
||
//
|
||
|
||
deviceExtension->StartingOffset.LowPart = 0;
|
||
deviceExtension->StartingOffset.HighPart = 0;
|
||
|
||
//
|
||
// 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).
|
||
//
|
||
|
||
sprintf(arcNameBuffer,
|
||
"\\ArcName\\scsi(%d)disk(%d)fdisk(%d)",
|
||
PortNumber,
|
||
LunInfo->TargetId,
|
||
LunInfo->Lun);
|
||
|
||
RtlInitString(&arcNameString, arcNameBuffer);
|
||
status = RtlAnsiStringToUnicodeString(&arcUnicodeString,
|
||
&arcNameString,
|
||
TRUE);
|
||
if (!NT_SUCCESS( status )) {
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
return status;
|
||
}
|
||
IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
|
||
RtlFreeUnicodeString(&arcUnicodeString);
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
sprintf(arcNameBuffer,
|
||
"\\ArcName\\multi(%d)disk(%d)fdisk(%d)",
|
||
0,
|
||
0,
|
||
*DeviceCount);
|
||
|
||
RtlInitString(&arcNameString, arcNameBuffer);
|
||
status = RtlAnsiStringToUnicodeString(&arcUnicodeString,
|
||
&arcNameString,
|
||
TRUE);
|
||
if (!NT_SUCCESS( status ) ) {
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
return status;
|
||
}
|
||
|
||
IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
|
||
RtlFreeUnicodeString(&arcUnicodeString);
|
||
RtlFreeUnicodeString(&ntUnicodeString);
|
||
|
||
//
|
||
// Determine the media type if possible. Set the current media type to
|
||
// Unknown so that determine media type will check the media.
|
||
//
|
||
|
||
deviceExtension->DiskGeometry->MediaType = Unknown;
|
||
DetermineMediaType(deviceObject);
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
CreateFlopDeviceObjectExit:
|
||
|
||
//
|
||
// Release the claim to the device.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ScsiClassClaimDevice(
|
||
PortDeviceObject,
|
||
LunInfo,
|
||
TRUE,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
return status;
|
||
|
||
} // end CreateFlopDeviceObject()
|
||
|
||
NTSTATUS
|
||
ScsiFlopCreate (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL currentIrql;
|
||
|
||
DebugPrint((3, "ScsiFlopCreate: Enter routine\n"));
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
||
IoCompleteRequest(Irp, 0);
|
||
KeLowerIrql(currentIrql);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // end ScsiFlopCreate()
|
||
|
||
|
||
NTSTATUS
|
||
ScsiFlopReadWrite(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
KIRQL currentIrql;
|
||
ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
|
||
LARGE_INTEGER startingOffset =
|
||
currentIrpStack->Parameters.Read.ByteOffset;
|
||
ULONG maximumTransferLength =
|
||
deviceExtension->PortCapabilities->MaximumTransferLength;
|
||
ULONG transferPages;
|
||
|
||
DebugPrint((3,"ScsiFlopReadWrite: Enter routine\n"));
|
||
|
||
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
|
||
!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
|
||
|
||
//
|
||
// if DO_VERIFY_VOLUME bit is set
|
||
// in device object flags, fail request.
|
||
//
|
||
|
||
DebugPrint((2,"ScsiFlopReadWrite: Volume verfication needed\n"));
|
||
|
||
Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
||
IoCompleteRequest(Irp, 0);
|
||
KeLowerIrql(currentIrql);
|
||
|
||
return STATUS_VERIFY_REQUIRED;
|
||
}
|
||
|
||
//
|
||
// Add partition byte offset to make start byte relative to
|
||
// beginning of floppy.
|
||
//
|
||
|
||
currentIrpStack->Parameters.Read.ByteOffset.QuadPart =
|
||
startingOffset.QuadPart + deviceExtension->StartingOffset.QuadPart;
|
||
|
||
//
|
||
// Calculate number of pages in this transfer.
|
||
//
|
||
|
||
transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
||
MmGetMdlVirtualAddress(Irp->MdlAddress),
|
||
currentIrpStack->Parameters.Read.Length);
|
||
|
||
//
|
||
// Check if request length is greater than the maximum number of
|
||
// bytes that the hardware can transfer.
|
||
//
|
||
|
||
if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
|
||
transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
|
||
|
||
DebugPrint((2,"ScsiDiskReadWrite: Request greater than maximum\n"));
|
||
DebugPrint((2,"ScsiDiskReadWrite: Maximum is %lx\n",
|
||
maximumTransferLength));
|
||
DebugPrint((2,"ScsiDiskReadWrite: Byte count is %lx\n",
|
||
currentIrpStack->Parameters.Read.Length));
|
||
|
||
transferPages =
|
||
deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
|
||
|
||
if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
|
||
maximumTransferLength = transferPages << PAGE_SHIFT;
|
||
}
|
||
|
||
//
|
||
// Check that maximum transfer size is not zero.
|
||
//
|
||
|
||
if (maximumTransferLength == 0) {
|
||
maximumTransferLength = PAGE_SIZE;
|
||
}
|
||
|
||
//
|
||
// Mark IRP with status pending.
|
||
//
|
||
|
||
IoMarkIrpPending(Irp);
|
||
|
||
//
|
||
// Request greater than port driver maximum.
|
||
// Break up into smaller routines.
|
||
//
|
||
|
||
ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
|
||
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
//
|
||
// Build SRB and CDB for this IRP.
|
||
//
|
||
|
||
ScsiClassBuildRequest(DeviceObject, Irp);
|
||
|
||
//
|
||
// Return the results of the call to the port driver.
|
||
//
|
||
|
||
return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
|
||
|
||
} // end ScsiFlopReadWrite()
|
||
|
||
|
||
NTSTATUS
|
||
ScsiFlopDeviceControl(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL currentIrql;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDEVICE_EXTENSION deviceExtension = 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;
|
||
|
||
srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
|
||
|
||
if (srb == NULL) {
|
||
|
||
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
if (IoIsErrorUserInduced(STATUS_INSUFFICIENT_RESOURCES)) {
|
||
|
||
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
|
||
}
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
||
IoCompleteRequest(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_GET_DRIVE_GEOMETRY:
|
||
|
||
DebugPrint((3,"ScsiDeviceIoControl: Get drive geometry\n"));
|
||
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
DetermineMediaType(DeviceObject);
|
||
|
||
//
|
||
// Copy drive geometry information from device extension.
|
||
//
|
||
|
||
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
|
||
deviceExtension->DiskGeometry,
|
||
sizeof(DISK_GEOMETRY));
|
||
|
||
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
|
||
status = STATUS_SUCCESS;
|
||
|
||
break;
|
||
|
||
|
||
case IOCTL_DISK_GET_MEDIA_TYPES:
|
||
|
||
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:
|
||
|
||
//
|
||
// 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:
|
||
|
||
//
|
||
// Determine if the device is writable.
|
||
//
|
||
|
||
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
||
|
||
if (modeData == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
||
|
||
length = ScsiClassModeSense(DeviceObject,
|
||
(PUCHAR) modeData,
|
||
MODE_DATA_SIZE,
|
||
MODE_SENSE_RETURN_ALL);
|
||
|
||
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
||
|
||
//
|
||
// Retry the request in case of a check condition.
|
||
//
|
||
|
||
length = ScsiClassModeSense(DeviceObject,
|
||
(PUCHAR) 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;
|
||
}
|
||
|
||
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(ScsiClassDeviceControl(DeviceObject, Irp));
|
||
|
||
break;
|
||
|
||
} // end switch( ...
|
||
|
||
Irp->IoStatus.Status = status;
|
||
|
||
if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
|
||
|
||
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
|
||
}
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
||
IoCompleteRequest(Irp, 0);
|
||
KeLowerIrql(currentIrql);
|
||
|
||
ExFreePool(srb);
|
||
|
||
return status;
|
||
|
||
} // end ScsiFlopDeviceControl()
|
||
|
||
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(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
||
|
||
if (modeData == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
||
|
||
length = ScsiClassModeSense(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 = ScsiClassModeSense(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 = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
|
||
|
||
if (pageData != NULL) {
|
||
|
||
DebugPrint((1, "ScsiFlop: Flexible disk page found, This is a floppy.\n"));
|
||
|
||
//
|
||
// As a speical case for the floptical driver do a magic mode sense to
|
||
// enable the drive.
|
||
//
|
||
|
||
ScsiClassModeSense(DeviceObject, modeData, 0x2a, 0x2e);
|
||
|
||
ExFreePool(modeData);
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
ExFreePool(modeData);
|
||
return(FALSE);
|
||
|
||
}
|
||
|
||
VOID
|
||
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
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PDISK_GEOMETRY geometry;
|
||
LONG index;
|
||
NTSTATUS status;
|
||
|
||
geometry = deviceExtension->DiskGeometry;
|
||
|
||
//
|
||
// Issue ReadCapacity to update device extension
|
||
// with information for current media.
|
||
//
|
||
|
||
status = ScsiClassReadDriveCapacity(DeviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Set the media type to unknow and zero the geometry information.
|
||
//
|
||
|
||
geometry->MediaType = Unknown;
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// 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) <=
|
||
deviceExtension->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;
|
||
|
||
}
|
||
}
|
||
|
||
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
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PVOID modeData;
|
||
PDISK_DATA diskData = (PDISK_DATA) (deviceExtension + 1);
|
||
PMODE_FLEXIBLE_DISK_PAGE pageData;
|
||
ULONG length;
|
||
LONG index;
|
||
UCHAR numberOfHeads;
|
||
UCHAR sectorsPerTrack;
|
||
USHORT maximumTrack;
|
||
|
||
if (diskData->DriveType != DRIVE_TYPE_NONE) {
|
||
return(diskData->DriveType);
|
||
}
|
||
|
||
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
||
|
||
if (modeData == NULL) {
|
||
return(DRIVE_TYPE_NONE);
|
||
}
|
||
|
||
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
||
|
||
length = ScsiClassModeSense(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 = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
|
||
|
||
//
|
||
// 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;
|
||
|
||
//
|
||
// 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 (maximumTrack - 1 >= 0x0100) {
|
||
maximumTrack /= 3;
|
||
numberOfHeads *= 3;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
}
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// 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;
|
||
|
||
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
||
|
||
if (modeData == NULL) {
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
||
|
||
length = ScsiClassModeSense(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 = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
for (driveMediaType = Drive2080Media2080;
|
||
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[1] != 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[1] = 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(NonPagedPool, 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 = ScsiClassSendSrbSynchronous(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(NonPagedPool, 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 = ScsiClassSendSrbSynchronous(DeviceObject,
|
||
srb,
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
PDISK_DATA diskData = (PDISK_DATA) (deviceExtension + 1);
|
||
PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
|
||
PIO_STACK_LOCATION irpStack;
|
||
PIRP irp;
|
||
PSCSI_REQUEST_BLOCK srb;
|
||
LARGE_INTEGER largeInt;
|
||
PCOMPLETION_CONTEXT context;
|
||
PCDB cdb;
|
||
ULONG alignment;
|
||
|
||
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;
|
||
|
||
if (deviceExtension->DiskGeometry != NULL) {
|
||
deviceExtension->DiskGeometry->MediaType = Unknown;
|
||
}
|
||
|
||
|
||
if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
|
||
senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INIT_COMMAND_REQUIRED ||
|
||
(senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
|
||
|
||
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;
|
||
|
||
context = ExAllocatePool(
|
||
NonPagedPool,
|
||
sizeof(COMPLETION_CONTEXT) + 0x2a + alignment
|
||
);
|
||
|
||
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;
|
||
}
|
||
|
||
srb = &context->Srb;
|
||
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) (context + 1) + (alignment - 1)) &
|
||
~(alignment - 1));
|
||
|
||
|
||
//
|
||
// Build the start unit CDB.
|
||
//
|
||
|
||
srb->CdbLength = 6;
|
||
cdb = (PCDB)srb->Cdb;
|
||
cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
|
||
cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
|
||
cdb->MODE_SENSE.PageCode = 0x2e;
|
||
cdb->MODE_SENSE.AllocationLength = 0x2a;
|
||
|
||
|
||
} else {
|
||
|
||
return;
|
||
}
|
||
|
||
context->DeviceObject = DeviceObject;
|
||
|
||
//
|
||
// Write length to SRB.
|
||
//
|
||
|
||
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
|
||
//
|
||
// Set up SCSI bus address.
|
||
//
|
||
|
||
srb->PathId = deviceExtension->PathId;
|
||
srb->TargetId = deviceExtension->TargetId;
|
||
srb->Lun = deviceExtension->Lun;
|
||
|
||
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
srb->TimeOutValue = deviceExtension->TimeOutValue;
|
||
|
||
//
|
||
// Build the asynchronous request
|
||
// to be sent to the port driver.
|
||
//
|
||
|
||
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
|
||
DeviceObject,
|
||
srb->DataBuffer,
|
||
srb->DataTransferLength,
|
||
&largeInt,
|
||
NULL);
|
||
|
||
IoSetCompletionRoutine(irp,
|
||
(PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
|
||
context,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
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;
|
||
|
||
//
|
||
// Set up IRP Address.
|
||
//
|
||
|
||
(VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
|
||
|
||
|
||
}
|
||
|
||
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;
|
||
|
||
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(NonPagedPoolCacheAligned, 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);
|
||
|
||
|
||
status = IoCallDriver(DeviceObject, irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Wait for the request to complete if necessary.
|
||
//
|
||
|
||
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
||
}
|
||
|
||
//
|
||
// If the call driver suceeded then set the status to the status block.
|
||
//
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
status = ioStatus.Status;
|
||
}
|
||
|
||
ExFreePool(buffer);
|
||
|
||
return(status);
|
||
|
||
}
|
||
|