NT4/private/ntos/dd/scsiflop/floppy.c
2020-09-30 17:12:29 +02:00

2278 lines
56 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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, &currentIrql);
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, &currentIrql);
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, &currentIrql);
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, &currentIrql);
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);
}