|
|
/*++
Copyright (C) 1993-99 Microsoft Corporation
Module Name:
devpdo.c
Abstract:
--*/
#include "ideport.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, IdeSendIdePassThrough)
#pragma alloc_text(PAGE, DeviceInitIdStrings)
#pragma alloc_text(PAGE, DeviceInitDeviceType)
#pragma alloc_text(PAGE, DeviceQueryDeviceRelations)
#pragma alloc_text(PAGE, DeviceUsageNotification)
#pragma alloc_text(PAGE, DeviceBuildStorageDeviceDescriptor)
#pragma alloc_text(PAGE, DeviceQueryPnPDeviceState)
#pragma alloc_text(PAGE, DeviceQueryCapabilities)
#pragma alloc_text(PAGE, DeviceBuildBusId)
#pragma alloc_text(PAGE, DeviceBuildCompatibleId)
#pragma alloc_text(PAGE, DeviceBuildHardwareId)
#pragma alloc_text(PAGE, DeviceBuildInstanceId)
#pragma alloc_text(PAGE, DeviceQueryId)
#pragma alloc_text(PAGE, DeviceQueryText)
#pragma alloc_text(PAGE, DeviceIdeTestUnitReady)
#pragma alloc_text(PAGE, DeviceQueryInitData)
#pragma alloc_text(PAGE, DeviceQueryStopRemoveDevice)
#pragma alloc_text(PAGE, DeviceStopDevice)
#pragma alloc_text(PAGE, DeviceScsiGetAddress)
#pragma alloc_text(PAGE, DeviceStorageQueryProperty)
#pragma alloc_text(PAGE, CopyField)
#pragma alloc_text(NONPAGE, DeviceIdeModeSelect)
#pragma alloc_text(NONPAGE, DeviceInitDeviceState)
#pragma alloc_text(NONPAGE, DeviceStartDeviceQueue)
#endif // ALLOC_PRAGMA
PDEVICE_OBJECT DeviceCreatePhysicalDeviceObject ( IN PDRIVER_OBJECT DriverObject, IN PFDO_EXTENSION FdoExtension, IN PUNICODE_STRING DeviceObjectName ) { PDEVICE_OBJECT physicalDeviceObject; PPDO_EXTENSION pdoExtension; NTSTATUS status;
physicalDeviceObject = NULL;
status = IoCreateDevice( DriverObject, // our driver object
sizeof(PDO_EXTENSION), // size of our extension
DeviceObjectName, // our name
FILE_DEVICE_MASS_STORAGE, // device type
FILE_DEVICE_SECURE_OPEN, // device characteristics
FALSE, // not exclusive
&physicalDeviceObject // store new device object here
);
if (NT_SUCCESS(status)) {
//
// spinning up could take a lot of current;
//
physicalDeviceObject->Flags |= DO_POWER_INRUSH | DO_DIRECT_IO;
//
// fix up alignment requirement
//
physicalDeviceObject->AlignmentRequirement = FdoExtension->DeviceObject->AlignmentRequirement; if (physicalDeviceObject->AlignmentRequirement < 1) { physicalDeviceObject->AlignmentRequirement = 1; }
pdoExtension = physicalDeviceObject->DeviceExtension; RtlZeroMemory (pdoExtension, sizeof(PDO_EXTENSION));
//
// Keeping track of those device objects
//
pdoExtension->DriverObject = DriverObject; pdoExtension->DeviceObject = physicalDeviceObject;
//
// keep track of our parent
//
pdoExtension->ParentDeviceExtension = FdoExtension;
//
// Dispatch Table
//
pdoExtension->DefaultDispatch = IdePortNoSupportIrp; pdoExtension->PnPDispatchTable = PdoPnpDispatchTable; pdoExtension->PowerDispatchTable = PdoPowerDispatchTable; pdoExtension->WmiDispatchTable = PdoWmiDispatchTable;
//
// We have to be in this D0 state before we can be enumurated
//
pdoExtension->SystemPowerState = PowerSystemWorking; pdoExtension->DevicePowerState = PowerDeviceD0; }
return physicalDeviceObject; }
NTSTATUS DeviceStartDevice ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPDO_EXTENSION pdoExtension; KEVENT event;
pdoExtension = RefPdoWithTag( DeviceObject, TRUE, DeviceStartDevice );
if (pdoExtension) {
KIRQL currentIrql;
// ISSUE: if we are not lun0, we really should wait for lun0 to start first
#if defined (IDEPORT_WMI_SUPPORT)
//
// register with WMI
//
if (!(pdoExtension->PdoState & PDOS_STARTED)) { IdePortWmiRegister ((PDEVICE_EXTENSION_HEADER)pdoExtension); } else { DebugPrint((1, "ATAPI: PDOe %x Didn't register for WMI\n", pdoExtension)); } #endif // IDEPORT_WMI_SUPPORT
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
SETMASK (pdoExtension->PdoState, PDOS_STARTED); CLRMASK (pdoExtension->PdoState, PDOS_STOPPED | PDOS_REMOVED | PDOS_SURPRISE_REMOVED | PDOS_DISABLED_BY_USER);
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
//
// need to init device with acpi GTF before processing
// the first request
//
// the assert could fire if the device is not powered up
// ignore the assert for the time being. Everything should
// work fine as the first request would power up the device
//
//ASSERT(pdoExtension->InitDeviceWithAcpiGtf == 0);
InterlockedIncrement (&pdoExtension->InitDeviceWithAcpiGtf);
//
// keep the device queue block until we can go through some
// init code
//
DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_START, FALSE);
//
// clear the stop_device block
//
status = DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE);
//
// init pdo with acpi bios _GTF data
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
DeviceQueryInitData( pdoExtension );
//
// can't really tell if it is enabled or not
// assume it is.
//
pdoExtension->WriteCacheEnable = TRUE;
status = DeviceInitDeviceState( pdoExtension, DeviceInitCompletionRoutine, &event );
if (!NT_SUCCESS(status)) {
ASSERT(NT_SUCCESS(status)); DeviceInitCompletionRoutine ( &event, status );
} else {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); }
//
// open the queue
//
DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_START);
UnrefPdoWithTag( pdoExtension, DeviceStartDevice );
status = STATUS_SUCCESS;
} else {
status = STATUS_DEVICE_DOES_NOT_EXIST; }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status; }
NTSTATUS DeviceStartDeviceQueue ( IN PPDO_EXTENSION PdoExtension, IN ULONG StopFlagToClear ) { NTSTATUS status; KIRQL currentIrql; BOOLEAN restartQueue; ULONG oldPdoState;
restartQueue = FALSE;
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql);
oldPdoState = PdoExtension->PdoState;
CLRMASK (PdoExtension->PdoState, StopFlagToClear);
if (PdoExtension->PdoState & PDOS_DEADMEAT) {
restartQueue = FALSE;
} else if ((oldPdoState & PDOS_MUST_QUEUE) != (PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
//
// make sure we have actually cleared some
// PDOS_MUST_QUEUE bits.
//
if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
restartQueue = TRUE; } }
KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
//
// Restart queue
//
if (restartQueue) {
KeAcquireSpinLock(&PdoExtension->ParentDeviceExtension->SpinLock, ¤tIrql);
GetNextLuPendingRequest(PdoExtension->ParentDeviceExtension, PdoExtension);
KeLowerIrql(currentIrql);
DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp started with 0x%x items queued\n", PdoExtension->DeviceObject, PdoExtension->NumberOfIrpQueued)); }
return STATUS_SUCCESS; }
NTSTATUS DeviceStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPDO_EXTENSION pdoExtension;
PAGED_CODE();
pdoExtension = RefPdoWithTag( DeviceObject, TRUE, DeviceStopDevice );
if (pdoExtension) {
DebugPrint (( DBG_PNP, "pdoe 0x%x 0x%x (%d, %d, %d) got a STOP device\n", pdoExtension, pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun ));
status = DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE, FALSE); UnrefPdoWithTag ( pdoExtension, DeviceStopDevice );
} else {
status = STATUS_DEVICE_DOES_NOT_EXIST; }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT );
return status; }
NTSTATUS DeviceStopDeviceQueueSafe ( IN PPDO_EXTENSION PdoExtension, IN ULONG QueueStopFlag, IN BOOLEAN LowMem ) { NTSTATUS status; PPDO_STOP_QUEUE_CONTEXT context; KIRQL currentIrql; BOOLEAN queueAlreadyBlocked = FALSE; PENUMERATION_STRUCT enumStruct; ULONG retryCount = 1; ULONG locked;
ASSERT (PDOS_MUST_QUEUE & QueueStopFlag);
//
// make sure the queue is not already blocked for the same reason
//
ASSERT (!(PdoExtension->PdoState & QueueStopFlag));
if (LowMem) {
//
//Lock
//
ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock), 1, 0) == 0);
enumStruct=PdoExtension->ParentDeviceExtension->PreAllocEnumStruct; if (enumStruct) { context=enumStruct->StopQContext; retryCount=5; } else { ASSERT(enumStruct); LowMem=FALSE; retryCount=1; } }
if (!LowMem) { context = ExAllocatePool (NonPagedPool, sizeof(*context)); }
if (context) {
//
// check to see if queue is already blocked
//
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql); if (PdoExtension->PdoState & (PDOS_MUST_QUEUE | PDOS_DEADMEAT)) {
SETMASK (PdoExtension->PdoState, QueueStopFlag); queueAlreadyBlocked = TRUE; } KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
RtlZeroMemory (context, sizeof (*context)); KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
context->PdoExtension = PdoExtension; context->QueueStopFlag = QueueStopFlag; context->AtaPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_NO_OP;
if (queueAlreadyBlocked) {
IdeStopQueueCompletionRoutine ( PdoExtension->DeviceObject, context, STATUS_SUCCESS );
status = STATUS_SUCCESS;
} else {
//
// send a no-op request to block the queue
//
status = STATUS_INSUFFICIENT_RESOURCES;
//
// if lowMem=0, this loop will execute only once
//
while (status == STATUS_INSUFFICIENT_RESOURCES && retryCount--) { status = IssueAsyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &context->AtaPassThroughData, FALSE, IdeStopQueueCompletionRoutine, context, TRUE, // TRUE really means complete this irp before starting a new one
DEFAULT_ATA_PASS_THROUGH_TIMEOUT, LowMem ); ASSERT (NT_SUCCESS(status));
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL); }
status = context->Status; } }
//
// Don't free the context if it was Pre-alloced.
//
if (!LowMem) { ExFreePool (context); } else {
// Unlock
ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock), 0, 1) == 1); }
} else {
status = STATUS_NO_MEMORY; }
return status; }
VOID IdeStopQueueCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PPDO_STOP_QUEUE_CONTEXT Context, IN NTSTATUS Status ) { PPDO_EXTENSION pdoExtension; KIRQL currentIrql;
pdoExtension = Context->PdoExtension; Context->Status = Status;
if (NT_SUCCESS(Status)) {
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
if (Context->QueueStopFlag == PDOS_QUEUE_FROZEN_BY_STOP_DEVICE) {
SETMASK (pdoExtension->PdoState, PDOS_STOPPED); }
SETMASK (pdoExtension->PdoState, Context->QueueStopFlag);
DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp stopped with 0x%x items queued\n", DeviceObject, pdoExtension->NumberOfIrpQueued));
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
} else {
DebugPrint ((0, "IdePort: unable to stop pdo 0x%x\n", pdoExtension)); }
KeSetEvent (&Context->Event, 0, FALSE);
return; }
NTSTATUS DeviceRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPDO_EXTENSION pdoExtension; KIRQL currentIrql; PDEVICE_OBJECT parentAttacheePdo; BOOLEAN freePdo; BOOLEAN callIoDeleteDevice; BOOLEAN deregWmi = FALSE;
pdoExtension = RefPdoWithTag( DeviceObject, TRUE, DeviceRemoveDevice );
if (pdoExtension) {
PIO_STACK_LOCATION thisIrpSp;
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
if (thisIrpSp->MinorFunction == IRP_MN_SURPRISE_REMOVAL) {
//
// freeze the queue if it is a surprise remove. This is
// necessary since a surprise remove on the fdo would
// clear the interrupt object. Any request that gets
// sent down after the surprise remove will cause an access
// violation if it makes into startio.
//
DeviceStopDeviceQueueSafe(pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE, TRUE ); }
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
if (pdoExtension->PdoState & PDOS_NEED_RESCAN) {
CLRMASK (pdoExtension->PdoState, PDOS_NEED_RESCAN);
//
// get ready for IoInvalidateDeviceRelations
//
parentAttacheePdo = pdoExtension->ParentDeviceExtension->AttacheePdo;
} else {
parentAttacheePdo = NULL; }
if (thisIrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
DebugPrint (( DBG_PNP, "pdoe 0x%x 0x%x (%d, %d, %d) got a REMOVE device\n", pdoExtension, pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun ));
if (pdoExtension->PdoState & (PDOS_DEADMEAT | PDOS_SURPRISE_REMOVED)) {
SETMASK (pdoExtension->PdoState, PDOS_REMOVED);
if (pdoExtension->PdoState & PDOS_REPORTED_TO_PNP) {
freePdo = FALSE;
} else {
freePdo = TRUE; }
} else {
SETMASK (pdoExtension->PdoState, PDOS_DISABLED_BY_USER); freePdo = FALSE; }
if ((pdoExtension->PdoState & PDOS_STARTED) && !(pdoExtension->PdoState & PDOS_SURPRISE_REMOVED)) { deregWmi = TRUE; } CLRMASK (pdoExtension->PdoState, PDOS_STARTED);
//
// not claimed anymore
//
CLRMASK (pdoExtension->PdoState, PDOS_DEVICE_CLIAMED);
callIoDeleteDevice = TRUE;
} else {
DebugPrint (( DBG_PNP, "pdoe 0x%x 0x%x (%d, %d, %d) got a SURPRISE_REMOVE device\n", pdoExtension, pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun ));
SETMASK (pdoExtension->PdoState, PDOS_SURPRISE_REMOVED | PDOS_DEADMEAT);
if (pdoExtension->PdoState & PDOS_STARTED) { deregWmi = TRUE; }
freePdo = TRUE; freePdo = FALSE; callIoDeleteDevice = FALSE; }
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
#if defined (IDEPORT_WMI_SUPPORT)
//
// deregister with WMI
//
if (deregWmi) {
IdePortWmiDeregister ((PDEVICE_EXTENSION_HEADER)pdoExtension); } #endif // IDEPORT_WMI_SUPPORT
if (freePdo) {
status = FreePdoWithTag( pdoExtension, TRUE, callIoDeleteDevice, DeviceRemoveDevice );
} else {
//
// release the pdo
//
UnrefPdoWithTag ( pdoExtension, DeviceRemoveDevice ); }
if (parentAttacheePdo) {
IoInvalidateDeviceRelations ( parentAttacheePdo, BusRelations ); } }
Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_SUCCESS;
} // DeviceRemoveDevice
NTSTATUS DeviceUsageNotification ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PPDO_EXTENSION pdoExtension; NTSTATUS status;
PAGED_CODE();
pdoExtension = RefPdoWithTag( DeviceObject, FALSE, DeviceUsageNotification ); status = Irp->IoStatus.Status;
if (pdoExtension) {
PIO_STACK_LOCATION irpSp; PDEVICE_OBJECT targetDeviceObject; IO_STATUS_BLOCK ioStatus; PULONG deviceUsageCount;
irpSp = IoGetCurrentIrpStackLocation(Irp);
if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
//
// Adjust the paging path count for this device.
//
deviceUsageCount = &pdoExtension->PagingPathCount;
//
// changing device state
//
IoInvalidateDeviceState(pdoExtension->DeviceObject);
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation) {
//
// Adjust the paging path count for this device.
//
deviceUsageCount = &pdoExtension->HiberPathCount;
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
//
// Adjust the paging path count for this device.
//
deviceUsageCount = &pdoExtension->CrashDumpPathCount;
} else {
deviceUsageCount = NULL; DebugPrint ((DBG_ALWAYS, "ATAPI: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n", irpSp->Parameters.UsageNotification.Type)); }
//
// get the top of parent's device stack
//
targetDeviceObject = IoGetAttachedDeviceReference( pdoExtension-> ParentDeviceExtension-> DeviceObject);
ioStatus.Status = STATUS_NOT_SUPPORTED; status = IdePortSyncSendIrp (targetDeviceObject, irpSp, &ioStatus);
ObDereferenceObject (targetDeviceObject);
if (NT_SUCCESS(status)) {
POWER_STATE powerState;
if (deviceUsageCount) {
IoAdjustPagingPathCount ( deviceUsageCount, irpSp->Parameters.UsageNotification.InPath ); }
if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
//
// reset the idle timeout to "forever"
//
DeviceRegisterIdleDetection ( pdoExtension, DEVICE_VERY_LONG_IDLE_TIMEOUT, DEVICE_VERY_LONG_IDLE_TIMEOUT );
if (pdoExtension->IdleCounter) {
PoSetDeviceBusy (pdoExtension->IdleCounter); }
//
// spin up the crash dump drive
//
powerState.DeviceState = PowerDeviceD0; PoRequestPowerIrp ( pdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL ); } }
//
// release the pdo
//
UnrefPdoWithTag ( pdoExtension, DeviceUsageNotification );
} else {
status = STATUS_NO_SUCH_DEVICE; }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status;
} // DeviceUsageNotification
NTSTATUS DeviceQueryStopRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPDO_EXTENSION pdoExtension; PIO_STACK_LOCATION thisIrpSp;
PAGED_CODE();
thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
pdoExtension = RefPdoWithTag( DeviceObject, TRUE, DeviceQueryStopRemoveDevice );
if (pdoExtension) {
if ((pdoExtension->PdoState & PDOS_LEGACY_ATTACHER) && (thisIrpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE)) {
status = STATUS_UNSUCCESSFUL;
} else if (pdoExtension->PagingPathCount || pdoExtension->CrashDumpPathCount) {
//
// Check the paging path count for this device.
//
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS; }
UnrefPdoWithTag ( pdoExtension, DeviceQueryStopRemoveDevice );
} else {
status = STATUS_NO_SUCH_DEVICE; DebugPrint((1, "Query remove failed\n")); }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status;
} // DeviceQueryStopRemoveDevice
NTSTATUS DeviceQueryId ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp; PPDO_EXTENSION pdoExtension; NTSTATUS status; PWSTR idString;
PAGED_CODE();
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
idString = NULL; status = STATUS_DEVICE_DOES_NOT_EXIST;
pdoExtension = RefPdoWithTag ( DeviceObject, TRUE, DeviceQueryId ); if (pdoExtension) {
switch (thisIrpSp->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
//
// Caller wants the bus ID of this device.
//
idString = DeviceBuildBusId(pdoExtension); break;
case BusQueryInstanceID:
//
// Caller wants the unique id of the device
//
idString = DeviceBuildInstanceId(pdoExtension); break;
case BusQueryCompatibleIDs:
//
// Caller wants the compatible id of the device
//
idString = DeviceBuildCompatibleId(pdoExtension); break;
case BusQueryHardwareIDs:
//
// Caller wants the hardware id of the device
//
idString = DeviceBuildHardwareId(pdoExtension); break;
default: DebugPrint ((1, "ideport: QueryID type %d not supported\n", thisIrpSp->Parameters.QueryId.IdType)); status = STATUS_NOT_SUPPORTED; break; }
UnrefPdoWithTag( pdoExtension, DeviceQueryId ); }
if( idString != NULL ){ Irp->IoStatus.Information = (ULONG_PTR) idString; status = STATUS_SUCCESS; }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status;
} // DeviceQueryId
PWSTR DeviceBuildBusId( IN PPDO_EXTENSION pdoExtension ) { #define IDE_BUS_ID_PREFIX "IDE\\"
PUCHAR deviceTypeIdString; ULONG deviceTypeIdLen; UCHAR compatibleId[10];
USHORT idStringBufLen;
PUCHAR idString; ANSI_STRING ansiBusIdString; PWCHAR idWString; UNICODE_STRING unicodeIdString;
PAGED_CODE();
//
// get the device type
//
deviceTypeIdString = (PUCHAR)IdePortGetDeviceTypeString ( pdoExtension->ScsiDeviceType );
if (deviceTypeIdString == NULL) {
sprintf (compatibleId, "Type%d", pdoExtension->ScsiDeviceType);
deviceTypeIdString = compatibleId; } deviceTypeIdLen = strlen(deviceTypeIdString);
idStringBufLen = (USHORT)(strlen( IDE_BUS_ID_PREFIX ) + deviceTypeIdLen + sizeof (pdoExtension->FullVendorProductId) + sizeof (pdoExtension->FullProductRevisionId) + sizeof (pdoExtension->FullSerialNumber) + 1);
//
// get the string buffers
//
idWString = ExAllocatePool( PagedPool, idStringBufLen * sizeof(WCHAR)); idString = ExAllocatePool( PagedPool, idStringBufLen);
if (idString && idWString) {
//
// build the ansi string
//
sprintf(idString, IDE_BUS_ID_PREFIX);
CopyField(idString + strlen(idString), deviceTypeIdString, deviceTypeIdLen, '_');
CopyField(idString + strlen(idString), pdoExtension->FullVendorProductId, sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR), '_'); CopyField(idString + strlen(idString), pdoExtension->FullProductRevisionId, sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR), '_');
RtlInitAnsiString ( &ansiBusIdString, idString );
//
// build the unicode string
//
unicodeIdString.Length = 0; unicodeIdString.MaximumLength = idStringBufLen * sizeof(WCHAR); unicodeIdString.Buffer = (PWSTR) idWString;
RtlAnsiStringToUnicodeString( &unicodeIdString, &ansiBusIdString, FALSE );
unicodeIdString.Buffer[unicodeIdString.Length/sizeof(WCHAR)] = L'\0';
} else {
if (idWString) { ExFreePool (idWString); } }
if (idString) { ExFreePool (idString); } return idWString; }
PWSTR DeviceBuildInstanceId( IN PPDO_EXTENSION pdoExtension ) { PWSTR idString; USHORT idStringBufLen; NTSTATUS status; WCHAR ideNonUniqueIdFormat[] = L"%x.%x.%x";
PAGED_CODE();
idStringBufLen = (sizeof(pdoExtension->FullSerialNumber) + 1) * sizeof(WCHAR); idString = ExAllocatePool (PagedPool, idStringBufLen); if( idString == NULL ){
return NULL; }
//
// Form the string and return it.
//
if (pdoExtension->FullSerialNumber[0]) {
ANSI_STRING ansiCompatibleIdString; UNICODE_STRING unicodeIdString;
//
// unique id
//
RtlInitAnsiString ( &ansiCompatibleIdString, pdoExtension->FullSerialNumber );
unicodeIdString.Length = 0; unicodeIdString.MaximumLength = idStringBufLen; unicodeIdString.Buffer = idString;
RtlAnsiStringToUnicodeString( &unicodeIdString, &ansiCompatibleIdString, FALSE );
idString[unicodeIdString.Length / 2] = L'\0';
} else {
//
// non-unique id
//
swprintf( idString, ideNonUniqueIdFormat, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun); }
return idString; }
PWSTR DeviceBuildCompatibleId( IN PPDO_EXTENSION pdoExtension ) { NTSTATUS status;
PCSTR compatibleIdString;
ANSI_STRING ansiCompatibleIdString; UNICODE_STRING unicodeIdString;
PWCHAR compIdStrings; ULONG totalBufferLen;
PAGED_CODE();
if (pdoExtension->ParentDeviceExtension->HwDeviceExtension-> DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
//
// ls-120 drive detected
// return the special ls-120 compatible ID
//
compatibleIdString = SuperFloppyCompatibleIdString;
} else {
compatibleIdString = IdePortGetCompatibleIdString (pdoExtension->ScsiDeviceType);
}
RtlInitAnsiString ( &ansiCompatibleIdString, compatibleIdString );
totalBufferLen = RtlAnsiStringToUnicodeSize ( &ansiCompatibleIdString );
unicodeIdString.Length = 0; unicodeIdString.MaximumLength = (USHORT) totalBufferLen;
//
// null terminator
//
totalBufferLen += sizeof(WCHAR);
//
// multi-string null terminator
//
totalBufferLen += sizeof(WCHAR);
compIdStrings = ExAllocatePool (PagedPool, totalBufferLen);
if (compIdStrings) {
unicodeIdString.Buffer = compIdStrings; } else {
unicodeIdString.Buffer = NULL; }
if (unicodeIdString.Buffer) {
RtlAnsiStringToUnicodeString( &unicodeIdString, &ansiCompatibleIdString, FALSE );
unicodeIdString.Buffer[unicodeIdString.Length/2 + 0] = L'\0'; unicodeIdString.Buffer[unicodeIdString.Length/2 + 1] = L'\0'; }
return compIdStrings; }
PWSTR DeviceBuildHardwareId( IN PPDO_EXTENSION pdoExtension ) { #define NUMBER_HARDWARE_STRINGS 5
ULONG i; PWSTR idMultiString; PWSTR idString; UCHAR scratch[64]; ULONG idStringLen; NTSTATUS status; ANSI_STRING ansiCompatibleIdString; UNICODE_STRING unicodeIdString;
PCSTR deviceTypeCompIdString; UCHAR deviceTypeCompId[20]; PCSTR deviceTypeIdString; UCHAR deviceTypeId[20];
UCHAR ScsiDeviceType;
PAGED_CODE();
ScsiDeviceType = pdoExtension->ScsiDeviceType;
idStringLen = (64 * NUMBER_HARDWARE_STRINGS + sizeof (UCHAR)) * sizeof (WCHAR); idMultiString = ExAllocatePool (PagedPool, idStringLen); if (idMultiString == NULL) {
return NULL; }
deviceTypeIdString = IdePortGetDeviceTypeString(ScsiDeviceType); if (deviceTypeIdString == NULL) {
sprintf (deviceTypeId, "Type%d", ScsiDeviceType);
deviceTypeIdString = deviceTypeId; }
if (pdoExtension->ParentDeviceExtension->HwDeviceExtension-> DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
//
// ls-120 drive detected
// return the special ls-120 compatible ID
//
deviceTypeCompIdString = SuperFloppyCompatibleIdString;
} else {
deviceTypeCompIdString = IdePortGetCompatibleIdString (ScsiDeviceType); if (deviceTypeCompIdString == NULL) {
sprintf (deviceTypeCompId, "GenType%d", ScsiDeviceType);
deviceTypeCompIdString = deviceTypeCompId; } }
//
// Zero out the string buffer
//
RtlZeroMemory(idMultiString, idStringLen); idString = idMultiString;
for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
//
// Build each of the hardware id's
//
switch(i) {
//
// Bus + Dev Type + Vendor + Product + Revision
//
case 0: {
sprintf(scratch, "IDE\\%s", deviceTypeIdString);
CopyField(scratch + strlen(scratch), pdoExtension->FullVendorProductId, sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR), '_'); CopyField(scratch + strlen(scratch), pdoExtension->FullProductRevisionId, sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR), '_'); break; }
//
// bus + vendor + product + revision[0]
case 1: {
sprintf(scratch, "IDE\\");
CopyField(scratch + strlen(scratch), pdoExtension->FullVendorProductId, sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR), '_'); CopyField(scratch + strlen(scratch), pdoExtension->FullProductRevisionId, sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR), '_'); break; }
//
// bus + device + vendor + product
case 2: {
sprintf(scratch, "IDE\\%s", deviceTypeIdString);
CopyField(scratch + strlen(scratch), pdoExtension->FullVendorProductId, sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR), '_'); break; }
//
// vendor + product + revision[0] (win9x)
case 3: {
CopyField(scratch, pdoExtension->FullVendorProductId, sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR), '_'); CopyField(scratch + strlen(scratch), pdoExtension->FullProductRevisionId, sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR), '_');
break; }
case 4: {
strcpy(scratch, deviceTypeCompIdString); break; }
default: {
break; } }
RtlInitAnsiString ( &ansiCompatibleIdString, scratch );
unicodeIdString.Length = 0; unicodeIdString.MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize( &ansiCompatibleIdString ); unicodeIdString.Buffer = idString;
RtlAnsiStringToUnicodeString( &unicodeIdString, &ansiCompatibleIdString, FALSE );
idString[unicodeIdString.Length / 2] = L'\0'; idString += unicodeIdString.Length / 2+ 1; } idString[0] = L'\0';
return idMultiString;
#undef NUMBER_HARDWARE_STRINGS
}
VOID CopyField( IN PUCHAR Destination, IN PUCHAR Source, IN ULONG Count, IN UCHAR Change )
/*++
Routine Description:
This routine will copy Count string bytes from Source to Destination. If it finds a nul byte in the Source it will translate that and any subsequent bytes into Change. It will also replace non-printable characters with the specified character.
Arguments:
Destination - the location to copy bytes
Source - the location to copy bytes from
Count - the number of bytes to be copied
Return Value:
none
--*/
{ ULONG i = 0; BOOLEAN pastEnd = FALSE;
PAGED_CODE();
for(i = 0; i < Count; i++) {
if(!pastEnd) {
if(Source[i] == 0) {
pastEnd = TRUE;
Destination[i] = Change;
} else if ((Source[i] <= L' ') || (Source[i] > ((WCHAR)0x7f)) || (Source[i] == L',')) {
Destination[i] = Change;
} else {
Destination[i] = Source[i];
} } else { Destination[i] = Change; } }
Destination[i] = L'\0'; return; }
NTSTATUS DeviceDeviceIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp); PPDO_EXTENSION pdoExtension; BOOLEAN passItToFdo; PDEVICE_OBJECT parentDeviceObject; NTSTATUS status; ULONG controlCode;
controlCode = thisIrpSp->Parameters.DeviceIoControl.IoControlCode;
if ((DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_STORAGE_BASE) && (DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_SCSI_BASE)) {
status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
//
// RefPdo makes sure that the pdo is not removed.
//
pdoExtension = RefPdoWithTag( DeviceObject, FALSE, Irp );
if (pdoExtension) {
passItToFdo = TRUE; parentDeviceObject = pdoExtension->ParentDeviceExtension->DeviceObject;
switch (controlCode) {
case IOCTL_SCSI_PASS_THROUGH_DIRECT: case IOCTL_SCSI_PASS_THROUGH:
status = PortSetPassThroughAddress(Irp, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun );
if (NT_SUCCESS(status)) {
//
// pass it to fdo
//
passItToFdo = TRUE;
} else {
//
// Error - complete it
//
passItToFdo = FALSE; Irp->IoStatus.Status = status; } break;
case IOCTL_ATA_PASS_THROUGH:
status = IdeAtaPassThroughSetPortAddress(Irp, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun ); if (NT_SUCCESS(status)) {
//
// This was originally designed to handle the request
// at the FDO. It was later decided to restrict this
// to the PDO. The routine should be slightly re-designed
// for this case by removing set and get address and passing
// in the PDO to it. This will be done later
//
status = IdeHandleAtaPassThroughIoctl( pdoExtension->ParentDeviceExtension, Irp, FALSE );
} else {
//
// Error - complete it
//
}
Irp->IoStatus.Status = status;
//
// don't pass it to the fdo.
//
passItToFdo = FALSE; break;
case IOCTL_ATA_PASS_THROUGH_DIRECT:
status = IdeAtaPassThroughSetPortAddress(Irp, pdoExtension->PathId, pdoExtension->TargetId, pdoExtension->Lun ); if (NT_SUCCESS(status)) {
status = IdeHandleAtaPassThroughIoctl( pdoExtension->ParentDeviceExtension, Irp, TRUE );
} else {
//
// Error - complete it
//
}
Irp->IoStatus.Status = status;
//
// don't pass it to the fdo.
//
passItToFdo = FALSE; break;
case IOCTL_IDE_PASS_THROUGH:
//
// Do not support this ioclt
//
//Irp->IoStatus.Status = IdeSendIdePassThrough(pdoExtension, Irp);
passItToFdo = FALSE; Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case IOCTL_SCSI_GET_ADDRESS:
passItToFdo = FALSE; Irp->IoStatus.Status = DeviceScsiGetAddress(pdoExtension, Irp);
break;
case IOCTL_SCSI_GET_DUMP_POINTERS:
passItToFdo = FALSE; Irp->IoStatus.Status = DeviceGetDumpPointers(pdoExtension, Irp);
break;
case IOCTL_STORAGE_QUERY_PROPERTY: status = DeviceStorageQueryProperty(pdoExtension, Irp);
if (status == STATUS_NOT_SUPPORTED) {
//
// not supported - pass it to fdo
//
passItToFdo = TRUE;
} else {
//
// handled here. complete it
//
passItToFdo = FALSE; Irp->IoStatus.Status = status; }
break;
case IOCTL_SCSI_MINIPORT: case IOCTL_SCSI_GET_INQUIRY_DATA: case IOCTL_SCSI_GET_CAPABILITIES:
//
// these need to be handled by the fdo
//
passItToFdo = TRUE; break;
case IOCTL_SCSI_RESCAN_BUS: default:
//
// do not pass down unknown ioctls to the fdo
// these ioctls should be sent directly to the fdo
//
passItToFdo = FALSE; Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; break;
}
UnrefPdoWithTag( pdoExtension, Irp );
} else {
passItToFdo = FALSE; Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; }
if (passItToFdo) {
return IdePortDeviceControl (parentDeviceObject, Irp);
} else {
status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } }
NTSTATUS DeviceScsiGetAddress ( PPDO_EXTENSION PdoExtension, PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status;
PAGED_CODE();
if(thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SCSI_ADDRESS)) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
scsiAddress->Length = sizeof(SCSI_ADDRESS); scsiAddress->PortNumber = (UCHAR) PdoExtension-> ParentDeviceExtension->ScsiPortNumber; scsiAddress->PathId = PdoExtension->PathId; scsiAddress->TargetId = PdoExtension->TargetId; scsiAddress->Lun = PdoExtension->Lun;
Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
status = STATUS_SUCCESS; }
return status; }
NTSTATUS DeviceGetDumpPointers( PPDO_EXTENSION PdoExtension, PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status;
//
// Get parameters for crash dump driver.
//
if (Irp->RequestorMode != KernelMode) {
status = STATUS_INVALID_DEVICE_REQUEST;
} else if (thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS)) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
PCRASHDUMP_INIT_DATA dumpInitData;
//
// caller needs to free this
//
// ISSUE: make sure we tell the parent to power up
//
dumpInitData = ExAllocatePool (NonPagedPool, sizeof (CRASHDUMP_INIT_DATA) );
if (dumpInitData) {
PDUMP_POINTERS dumpPointers; dumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory (dumpInitData, sizeof (CRASHDUMP_INIT_DATA)); dumpInitData->PathId = PdoExtension->PathId; dumpInitData->TargetId = PdoExtension->TargetId; dumpInitData->Lun = PdoExtension->Lun;
dumpInitData->LiveHwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
dumpPointers->AdapterObject = NULL; dumpPointers->MappedRegisterBase = NULL; dumpPointers->DumpData = dumpInitData; dumpPointers->CommonBufferVa = NULL; dumpPointers->CommonBufferPa.QuadPart = 0; dumpPointers->CommonBufferSize = 0; dumpPointers->DeviceObject = PdoExtension->DeviceObject; dumpPointers->AllocateCommonBuffers = FALSE;
Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
status = STATUS_SUCCESS;
} else {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(CRASHDUMP_INIT_DATA), IDEPORT_TAG_DUMP_POINTER );
status = STATUS_INSUFFICIENT_RESOURCES; } }
return status; }
NTSTATUS DeviceStorageQueryProperty ( PPDO_EXTENSION PdoExtension, PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp); PSTORAGE_PROPERTY_QUERY storageQuery; NTSTATUS status;
PAGED_CODE();
storageQuery = Irp->AssociatedIrp.SystemBuffer; status = STATUS_NOT_SUPPORTED;
if (thisIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) {
status = STATUS_INVALID_PARAMETER;
} else {
if (storageQuery->PropertyId == StorageDeviceProperty) { // device property
ULONG bufferSize;
switch (storageQuery->QueryType) { case PropertyStandardQuery: DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyStandardQuery\n" ));
bufferSize = thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength; status = DeviceBuildStorageDeviceDescriptor( PdoExtension, (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer, &bufferSize ); if (NT_SUCCESS(status)) {
Irp->IoStatus.Information = bufferSize; }
break;
case PropertyExistsQuery: DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyExistsQuery\n")); // ISSUE: Will be implemented when required
status = STATUS_SUCCESS; break;
case PropertyMaskQuery: DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyMaskQuery\n")); //ISSUE: Will implement when required
status = STATUS_NOT_IMPLEMENTED; break;
default: DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY unknown type\n")); // ISSUE: Will implement when required
status = STATUS_NOT_IMPLEMENTED; break; } } }
return status; }
NTSTATUS DeviceBuildStorageDeviceDescriptor( PPDO_EXTENSION pdoExtension, IN OUT PSTORAGE_DEVICE_DESCRIPTOR StorageDeviceDescriptor, IN OUT PULONG BufferSize ) {
STORAGE_DEVICE_DESCRIPTOR localStorageDeviceDescriptor; ULONG productIdLength; ULONG revisionIdLength; ULONG serialNumberLength; PUCHAR bytebuffer; ULONG byteLeft; ULONG byteToCopy;
INQUIRYDATA InquiryData; NTSTATUS status;
ASSERT (pdoExtension); ASSERT (StorageDeviceDescriptor);
productIdLength = strlen(pdoExtension->FullVendorProductId) + sizeof(UCHAR); revisionIdLength = strlen(pdoExtension->FullProductRevisionId) + sizeof(UCHAR); serialNumberLength = strlen(pdoExtension->FullSerialNumber) + sizeof(UCHAR);
RtlZeroMemory (&localStorageDeviceDescriptor, sizeof (STORAGE_DEVICE_DESCRIPTOR)); localStorageDeviceDescriptor.Version = sizeof (STORAGE_DEVICE_DESCRIPTOR); localStorageDeviceDescriptor.Size = sizeof (STORAGE_DEVICE_DESCRIPTOR) + INQUIRYDATABUFFERSIZE + productIdLength + revisionIdLength + serialNumberLength;
localStorageDeviceDescriptor.DeviceType = pdoExtension->ScsiDeviceType;
if (pdoExtension-> ParentDeviceExtension-> HwDeviceExtension-> DeviceFlags[pdoExtension->TargetId] & DFLAGS_REMOVABLE_DRIVE) {
localStorageDeviceDescriptor.RemovableMedia = TRUE; }
if (pdoExtension-> ParentDeviceExtension-> HwDeviceExtension-> DeviceFlags[pdoExtension->TargetId] & DFLAGS_ATAPI_DEVICE) {
localStorageDeviceDescriptor.BusType = BusTypeAtapi; } else {
localStorageDeviceDescriptor.BusType = BusTypeAta; }
bytebuffer = (PUCHAR) StorageDeviceDescriptor; byteLeft = *BufferSize;
//
// copy the basic STORAGE_DEVICE_DESCRIPTOR
//
if (byteLeft) {
byteToCopy = min(sizeof (STORAGE_DEVICE_DESCRIPTOR), byteLeft);
RtlCopyMemory (StorageDeviceDescriptor, &localStorageDeviceDescriptor, byteToCopy);
bytebuffer += byteToCopy; byteLeft -= byteToCopy; }
//
// copy raw device properties (Inquiry Data)
//
if (byteLeft) {
status = IssueInquirySafe( pdoExtension->ParentDeviceExtension, pdoExtension, &InquiryData, FALSE );
if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
byteToCopy = min(INQUIRYDATABUFFERSIZE, byteLeft);
RtlCopyMemory (bytebuffer, &InquiryData, byteToCopy);
StorageDeviceDescriptor->RawPropertiesLength = byteToCopy;
bytebuffer += byteToCopy; byteLeft -= byteToCopy; } }
//
// copy product ID
//
if (byteLeft) {
byteToCopy = min(productIdLength, byteLeft);
RtlCopyMemory (bytebuffer, pdoExtension->FullVendorProductId, byteToCopy); bytebuffer[byteToCopy - 1] = '\0';
StorageDeviceDescriptor->ProductIdOffset = *BufferSize - byteLeft;
bytebuffer += byteToCopy; byteLeft -= byteToCopy; }
//
// copy revision ID
//
if (byteLeft) {
byteToCopy = min(productIdLength, byteLeft);
RtlCopyMemory (bytebuffer, pdoExtension->FullProductRevisionId, byteToCopy); bytebuffer[byteToCopy - 1] = '\0';
StorageDeviceDescriptor->ProductRevisionOffset = *BufferSize - byteLeft;
bytebuffer += byteToCopy; byteLeft -= byteToCopy; }
//
// copy serial #
//
if (byteLeft) {
byteToCopy = min(serialNumberLength, byteLeft);
RtlCopyMemory (bytebuffer, pdoExtension->FullSerialNumber, byteToCopy); bytebuffer[byteToCopy - 1] = '\0';
StorageDeviceDescriptor->SerialNumberOffset = *BufferSize - byteLeft;
bytebuffer += byteToCopy; byteLeft -= byteToCopy; }
*BufferSize -= byteLeft;
return STATUS_SUCCESS;
} // DeviceBuildStorageDeviceDescriptor
NTSTATUS DeviceQueryCapabilities ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp; PPDO_EXTENSION pdoExtension; PDEVICE_CAPABILITIES capabilities; NTSTATUS status;
PAGED_CODE();
thisIrpSp = IoGetCurrentIrpStackLocation( Irp ); capabilities = thisIrpSp->Parameters.DeviceCapabilities.Capabilities;
pdoExtension = RefPdoWithTag ( DeviceObject, TRUE, DeviceQueryCapabilities );
if (pdoExtension == NULL) {
status = STATUS_DEVICE_DOES_NOT_EXIST;
} else {
DEVICE_CAPABILITIES parentDeviceCapabilities;
status = IdeGetDeviceCapabilities( pdoExtension->ParentDeviceExtension->AttacheePdo, &parentDeviceCapabilities);
if (NT_SUCCESS(status)) {
RtlMoveMemory ( capabilities, &parentDeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
if (pdoExtension->FullSerialNumber[0]) {
capabilities->UniqueID = TRUE; } else {
capabilities->UniqueID = FALSE; }
//
// never!
//
capabilities->Removable = FALSE; capabilities->SurpriseRemovalOK = FALSE;
capabilities->Address = PNP_ADDRESS(pdoExtension->TargetId, pdoExtension->Lun); capabilities->UINumber = pdoExtension->TargetId;
capabilities->D1Latency = 31 * (1000 * 10); // 31s
capabilities->D2Latency = 31 * (1000 * 10); // 31s
capabilities->D3Latency = 31 * (1000 * 10); // 31s
}
UnrefPdoWithTag ( pdoExtension, DeviceQueryCapabilities );
}
Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // DeviceQueryCapabitilies
NTSTATUS IdePortInsertByKeyDeviceQueue ( IN PPDO_EXTENSION PdoExtension, IN PIRP Irp, IN ULONG SortKey, OUT PBOOLEAN Inserted ) { KIRQL currentIrql; NTSTATUS status; POWER_STATE powerState;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb; BOOLEAN urgentSrb;
status = STATUS_SUCCESS; *Inserted = FALSE;
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
if (PdoExtension->LuFlags & PD_QUEUE_FROZEN) {
DebugPrint((1,"IdePortDispatch: Request put in frozen queue!\n")); }
*Inserted = KeInsertByKeyDeviceQueue( &PdoExtension->DeviceObject->DeviceQueue, &Irp->Tail.Overlay.DeviceQueueEntry, SortKey);
if (*Inserted == FALSE) {
//
// we need this check here because in the remove irp codepath
// setting the PDOS_REMOVED flag and flushing the queue are not
// atomic. If the queue is already flushed and there are no active
// requests, no one will pick this one up. If there is one active the
// flush would have cleared the queue busy and we could end up with
// two active requests simultaneously. If the PDOS_REMOVED flag is
// set then flush the queue to clear up any requests that got queued
// due to busy being set by this request. Note that if the flush in the
// remove happens after this it will just be an extra flush. No harm there
//
if (PdoExtension->PdoState & PDOS_REMOVED) {
//
// lower the irql
//
KeLowerIrql(currentIrql);
//
// The pdo has been removed. We have to flush any requests in
// the queue since the remove irp could be done with the flush
// already. Note that this will also clear the queue busy.
//
IdePortFlushLogicalUnit(PdoExtension->ParentDeviceExtension, PdoExtension, TRUE );
//
// complete the request in hand
//
srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED; Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// return true so that the dispatch routine doesn't attempt
// to send it down
//
*Inserted = TRUE;
return status; }
if (PdoExtension->PdoState & PDOS_QUEUE_BLOCKED) {
ASSERT (PdoExtension->PendingRequest == NULL); PdoExtension->PendingRequest = Irp; *Inserted = TRUE;
if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
//
// device is powered down
// use a large time in case it spins up slowly
//
if (srb->TimeOutValue < DEFAULT_SPINUP_TIME) {
srb->TimeOutValue = DEFAULT_SPINUP_TIME; }
//
// We are not powered up.
// issue an power up
//
powerState.DeviceState = PowerDeviceD0; status = PoRequestPowerIrp ( PdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL ); ASSERT (NT_SUCCESS(status));
DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n", PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, PdoExtension->TargetId, Irp)); }
} else if (srb->Function != SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
//
// If this irp is not for changing power state, we may have
// to queue it
//
if (PdoExtension->DevicePowerState != PowerDeviceD0) {
if (PdoExtension->DevicePowerState != PowerDeviceD3) {
//
// we are in D1 or D2.
// We can never be sure that we are in D0 when
// we tell the device to go from D1/D2 to D0.
// Some device lies and won't spin up until it sees
// a media access command. This causes longer time
// to execute the command
//
// to prevent the next command from timing out, we
// will increment its timeout
//
if (srb->TimeOutValue < 30) {
srb->TimeOutValue = 30; } }
//
// We are not powered up.
// issue an power up
//
powerState.DeviceState = PowerDeviceD0; status = PoRequestPowerIrp ( PdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL );
ASSERT (NT_SUCCESS(status)); status = STATUS_SUCCESS;
ASSERT (PdoExtension->PendingRequest == NULL); PdoExtension->PendingRequest = Irp;
DebugPrint ((1, "IdePort IdePortInsertByKeyDeviceQueue: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n", PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress, PdoExtension->TargetId, Irp));
*Inserted = TRUE; } }
} else {
#if DBG
InterlockedIncrement ( &PdoExtension->NumberOfIrpQueued ); #endif // DBG
}
KeLowerIrql(currentIrql); return status; }
VOID DeviceInitCompletionRoutine ( PVOID Context, NTSTATUS Status ) { PKEVENT event = Context;
if (!NT_SUCCESS(Status)) {
//ASSERT (!"DeviceInitDeviceState Failed\n");
DebugPrint((DBG_ALWAYS, "ATAPI: ERROR: DeviceInitDeviceStateFailed with Status %x\n", Status)); }
KeSetEvent (event, 0, FALSE); }
NTSTATUS DeviceQueryText ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp; PPDO_EXTENSION pdoExtension; PWCHAR returnString; LONG i; UNICODE_STRING unicodeString; ANSI_STRING ansiString; ULONG stringLen; NTSTATUS status;
PAGED_CODE(); thisIrpSp = IoGetCurrentIrpStackLocation (Irp);
returnString = NULL; Irp->IoStatus.Information = 0;
pdoExtension = RefPdoWithTag ( DeviceObject, TRUE, DeviceQueryText );
if (pdoExtension == NULL) {
status = STATUS_DEVICE_DOES_NOT_EXIST;
} else {
status = STATUS_NO_MEMORY;
if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
stringLen = sizeof (pdoExtension->FullVendorProductId); stringLen *= sizeof(WCHAR); returnString = ExAllocatePool ( PagedPool, stringLen ); if (returnString) {
unicodeString.Length = 0; unicodeString.MaximumLength = (USHORT) stringLen; unicodeString.Buffer = returnString;
//
// vendor ID
//
RtlInitAnsiString ( &ansiString, pdoExtension->FullVendorProductId );
RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, FALSE );
ASSERT(unicodeString.Length < unicodeString.MaximumLength); //
// get rid of trailing spaces and nulls
//
for (i=(unicodeString.Length/2)-1; i >= 0; i--) {
if ((returnString[i] == ' ') || (returnString[i] == 0)) {
continue;
} else {
break; } }
//
// null terminate it
//
returnString[i + 1] = 0;
status = STATUS_SUCCESS; } } else if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation) {
stringLen = 100;
returnString = ExAllocatePool ( PagedPool, stringLen );
if (returnString) {
wcscpy(returnString, (((pdoExtension->TargetId & 0x1) == 0) ? L"0" : L"1"));
RtlInitUnicodeString(&unicodeString, returnString);
//
// null terminate it
//
unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR) + 0] = L'\0';
status = STATUS_SUCCESS; }
} else {
status = STATUS_NOT_SUPPORTED; }
UnrefPdoWithTag ( pdoExtension, DeviceQueryText ); }
Irp->IoStatus.Information = (ULONG_PTR) returnString; Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status; } // DeviceQueryText
NTSTATUS IdeSendIdePassThrough ( IN PPDO_EXTENSION PdoExtension, IN PIRP Irp )
/*++
Routine Description:
This function sends a user specified IDE task registers It creates an srb which is processed normally by the port driver. This call is synchornous.
Arguments:
DeviceExtension - Supplies a pointer the SCSI adapter device extension.
RequestIrp - Supplies a pointe to the Irp which made the original request.
Return Value:
Returns a status indicating the success or failure of the operation.
--*/
{ PIO_STACK_LOCATION irpStack; PATA_PASS_THROUGH ataPassThroughData; ULONG dataBufferSize; BOOLEAN dataIn; NTSTATUS status; ULONG outputBufferSize;
PAGED_CODE();
DebugPrint((3,"IdePortSendPassThrough: Enter routine\n"));
//
// validate target device
//
if (PdoExtension->Lun != 0) {
return STATUS_INVALID_DEVICE_REQUEST; }
//
// Get a pointer to the control block.
//
irpStack = IoGetCurrentIrpStackLocation(Irp); ataPassThroughData = Irp->AssociatedIrp.SystemBuffer;
//
// Validiate the user buffer.
//
if (irpStack->Parameters.DeviceIoControl.InputBufferLength < FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
return STATUS_INVALID_PARAMETER; }
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
return STATUS_INVALID_PARAMETER; }
ASSERT(ataPassThroughData != NULL);
dataBufferSize = ataPassThroughData->DataBufferSize;
outputBufferSize = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer) + dataBufferSize;
if (outputBufferSize < dataBufferSize) {
//
// outputBufferSize overflows a ULONG
//
outputBufferSize = irpStack->Parameters.DeviceIoControl.OutputBufferLength; }
//
// SECURITY: This should be fixed. If the output buffer size is larger
// than the output buffer length, we could potentially bugcheck.
//
if ((irpStack->Parameters.DeviceIoControl.OutputBufferLength) >= outputBufferSize) {
dataIn = TRUE;
} else {
dataIn = FALSE; }
status = IssueSyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, ataPassThroughData, dataIn, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE );
if (NT_SUCCESS(status)) {
//
// SECURITY: verify that we always copy outpubuffersize
// data in the SUCCESS case
//
Irp->IoStatus.Information = outputBufferSize;
} else {
//
// ignore all errors
// let the caller figure out the error
// from the task file registers
//
status = STATUS_SUCCESS; Irp->IoStatus.Information = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer); }
Irp->IoStatus.Status = status; return status;
} // IdeSendIdePassThrough
VOID DeviceRegisterIdleDetection ( IN PPDO_EXTENSION PdoExtension, IN ULONG ConservationIdleTime, IN ULONG PerformanceIdleTime ) { NTSTATUS status; ATA_PASS_THROUGH ataPassThroughData;
//
// Many ATAPI device (Acer and Panasonice Changer) doesn't like ATA
// power down command. Since they auto-spin-down anyway, we are not
// go to power manage it
//
if (!(PdoExtension->PdoState & PDOS_NO_POWER_DOWN)) {
if (!PdoExtension->CrashDumpPathCount) {
RtlZeroMemory (&ataPassThroughData, sizeof(ataPassThroughData)); ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_IDLE_IMMEDIATE; ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
status = IssueSyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &ataPassThroughData, FALSE, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE );
if (NT_SUCCESS(status)) {
DEVICE_POWER_STATE devicePowerState;
//
// ISSUE
// should check the registry/device property whether
// idle detection has been disabled for this device
//
devicePowerState = PowerDeviceD3; PdoExtension->IdleCounter = PoRegisterDeviceForIdleDetection ( PdoExtension->DeviceObject, ConservationIdleTime, // seconds
PerformanceIdleTime, // seconds
devicePowerState );
DebugPrint ((1, "IdePort: pdoExtension 0x%x support power managerment command\n", PdoExtension));
} else {
KIRQL currentIrql;
KeAcquireSpinLock(&PdoExtension->PdoSpinLock, ¤tIrql);
SETMASK (PdoExtension->PdoState, PDOS_NO_POWER_DOWN);
KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
DebugPrint ((1, "IdePort: pdoExtension 0x%x DOES NOT support power managerment command\n", PdoExtension)); } } }
return; }
VOID DeviceUnregisterIdleDetection ( IN PPDO_EXTENSION PdoExtension ) { DEVICE_POWER_STATE devicePowerState; devicePowerState = PowerDeviceD3;
if (PdoExtension->IdleCounter) {
PoRegisterDeviceForIdleDetection ( PdoExtension->DeviceObject, 0, 0, devicePowerState );
PdoExtension->IdleCounter = NULL; } return; }
VOID DeviceInitIdStrings ( IN PPDO_EXTENSION PdoExtension, IN IDE_DEVICETYPE DeviceType, IN PINQUIRYDATA InquiryData, IN PIDENTIFY_DATA IdentifyData ) { LONG i; UCHAR c;
SPECIAL_ACTION_FLAG specialFlags;
PAGED_CODE();
ASSERT (PdoExtension); ASSERT (IdentifyData);
if (DeviceType == DeviceIsAta) {
CopyField( PdoExtension->FullVendorProductId, IdentifyData->ModelNumber, sizeof(PdoExtension->FullVendorProductId)-1, ' ' );
CopyField( PdoExtension->FullProductRevisionId, IdentifyData->FirmwareRevision, sizeof(PdoExtension->FullProductRevisionId)-1, ' ' );
//
// byte swap
//
for (i=0; i<sizeof(PdoExtension->FullVendorProductId)-1; i+=2) { c = PdoExtension->FullVendorProductId[i]; PdoExtension->FullVendorProductId[i] = PdoExtension->FullVendorProductId[i + 1]; PdoExtension->FullVendorProductId[i + 1] = c; } for (i=0; i<sizeof(PdoExtension->FullProductRevisionId)-1; i+=2) { c = PdoExtension->FullProductRevisionId[i]; PdoExtension->FullProductRevisionId[i] = PdoExtension->FullProductRevisionId[i + 1]; PdoExtension->FullProductRevisionId[i + 1] = c; }
} else if (DeviceType == DeviceIsAtapi) {
PUCHAR fullVendorProductId;
fullVendorProductId = PdoExtension->FullVendorProductId;
CopyField( fullVendorProductId, InquiryData->VendorId, 8, ' ' );
for (i=7; i >= 0; i--) {
if (fullVendorProductId[i] != ' ') {
fullVendorProductId[i + 1] = ' '; fullVendorProductId += i + 2; break; } }
CopyField( fullVendorProductId, InquiryData->ProductId, 16, ' ' );
fullVendorProductId += 16;
for (i=0; fullVendorProductId+i < PdoExtension->FullVendorProductId+40; i++) { fullVendorProductId[i] = ' '; }
CopyField( PdoExtension->FullProductRevisionId, InquiryData->ProductRevisionLevel, 4, ' ' );
for (i=4; i<8; i++) { PdoExtension->FullProductRevisionId[i] = ' '; }
} else {
ASSERT (FALSE); }
//
// take out trailing spaces
//
for (i=sizeof(PdoExtension->FullVendorProductId)-2; i >= 0; i--) {
if (PdoExtension->FullVendorProductId[i] != ' ') {
PdoExtension->FullVendorProductId[i+1] = '\0'; break; } }
for (i=sizeof(PdoExtension->FullProductRevisionId)-2; i >= 0; i--) {
if (PdoExtension->FullProductRevisionId[i] != ' ') {
PdoExtension->FullProductRevisionId[i+1] = '\0'; break; } }
//
// Check the vendor & product id to see if we should disable the serial
// number for this device.
//
specialFlags = IdeFindSpecialDevice(PdoExtension->FullVendorProductId, PdoExtension->FullProductRevisionId);
//
// look for serial number
//
// some device returns non-printable characters as part of its
// serial number. to get around this, we will turn all raw numbers
// into a string.
//
if ((specialFlags != disableSerialNumber) && (IdentifyData->SerialNumber[0] != ' ') && (IdentifyData->SerialNumber[0] != '\0')) {
for (i=0; i<sizeof(IdentifyData->SerialNumber); i++) {
sprintf (PdoExtension->FullSerialNumber+i*2, "%2x", IdentifyData->SerialNumber[i]); }
PdoExtension->FullSerialNumber[sizeof(PdoExtension->FullSerialNumber) - 1] = '\0';
} else {
PdoExtension->FullSerialNumber[0] = '\0'; }
DebugPrint (( DBG_BUSSCAN, "PDOE 0x%x: Full IDs \n\t%s\n\t%s\n\t%s\n", PdoExtension, PdoExtension->FullVendorProductId, PdoExtension->FullProductRevisionId, PdoExtension->FullSerialNumber ));
return; }
VOID DeviceInitDeviceType ( IN PPDO_EXTENSION PdoExtension, IN PINQUIRYDATA InquiryData ) { PdoExtension->ScsiDeviceType = InquiryData->DeviceType;
if(InquiryData->RemovableMedia) {
SETMASK (PdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA); }
return; }
NTSTATUS DeviceQueryDeviceRelations ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION thisIrpSp; PDEVICE_RELATIONS deviceRelations; NTSTATUS status;
IDE_PATH_ID pathId; PPDO_EXTENSION pdoExtension; PPDO_EXTENSION otherPdoExtension; ULONG numPdos;
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
case TargetDeviceRelation:
deviceRelations = ExAllocatePool ( NonPagedPool, sizeof(*deviceRelations) + sizeof(deviceRelations->Objects[0]) * 1 );
if (deviceRelations != NULL) {
deviceRelations->Count = 1; deviceRelations->Objects[0] = DeviceObject;
ObReferenceObjectByPointer(DeviceObject, 0, 0, KernelMode);
Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; } else {
Irp->IoStatus.Status = STATUS_NO_MEMORY; Irp->IoStatus.Information = 0; } break; }
status = Irp->IoStatus.Status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status; } // DeviceQueryDeviceRelations
NTSTATUS DeviceQueryInitData ( IN PPDO_EXTENSION PdoExtension ) { PDEVICE_SETTINGS deviceSettings; PDEVICE_SETTINGS tempDeviceSettings; NTSTATUS status; ATA_PASS_THROUGH ataPassThroughData;
PPDO_EXTENSION lun0PdoExtension; ULONG totalDeviceSettingEntries; ULONG firstNewEntryOffset;
PAGED_CODE();
DebugPrint (( DBG_PNP, "DeviceQueryInitData: Init. pdoe 0x%x (%d,%d,%d)\n", PdoExtension, PdoExtension->PathId, PdoExtension->TargetId, PdoExtension->Lun ));
deviceSettings = PdoExtension->AcpiDeviceSettings; if (deviceSettings == NULL) {
//
// ISSUE: we can't be sure acpi is always attached on lun0
//
// get the lun0 pdo
//
lun0PdoExtension = RefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension->PathId, PdoExtension->TargetId, 0, TRUE, DeviceQueryInitData );
if (lun0PdoExtension) {
ASSERT (lun0PdoExtension->TargetId == PdoExtension->TargetId);
status = DeviceQueryFirmwareBootSettings ( lun0PdoExtension, &deviceSettings );
//
// let go Lun0
//
UnrefPdoWithTag( lun0PdoExtension, DeviceQueryInitData ); }
if (deviceSettings) {
ULONG i; ULONG j;
for (i=0; i<deviceSettings->NumEntries; i++) {
//
// Ignore SET_DRIVE_PARAMETERS, SET_MULTIPLE and set transfermode commands
// in GTF
//
if (((deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_FEATURE) && (deviceSettings->FirmwareSettings[i].bFeaturesReg == IDE_SET_FEATURE_SET_TRANSFER_MODE)) || (deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_DRIVE_PARAMETERS) || (deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_MULTIPLE)) {
DebugPrint((DBG_ACPI, "Ignoring Command %xin GTF\n", deviceSettings->FirmwareSettings[i].bCommandReg ));
deviceSettings->NumEntries--;
//
// remove this command by shifting the rest up one entry
//
for (j=i; j<deviceSettings->NumEntries; j++) {
deviceSettings->FirmwareSettings[j] = deviceSettings->FirmwareSettings[j+1]; }
//
// we move something new into the current i entry
// better adjust i so that we will check this entry
// again
//
if (i < deviceSettings->NumEntries) { i--; } }
} }
//
// we need to add a new setting
//
if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) { totalDeviceSettingEntries = 2; } else { totalDeviceSettingEntries = 1; }
if (deviceSettings) { totalDeviceSettingEntries += deviceSettings->NumEntries; firstNewEntryOffset = deviceSettings->NumEntries; } else { firstNewEntryOffset = 0; }
tempDeviceSettings = ExAllocatePool ( NonPagedPool, sizeof(DEVICE_SETTINGS) + (totalDeviceSettingEntries) * sizeof(IDEREGS) );
if (tempDeviceSettings) {
tempDeviceSettings->NumEntries = totalDeviceSettingEntries;
//
// copy the settings from acpi query
//
if (deviceSettings) { RtlCopyMemory (&tempDeviceSettings->FirmwareSettings, &deviceSettings->FirmwareSettings, sizeof(IDEREGS) * deviceSettings->NumEntries);
//
// don't need the old structure anymore
//
ExFreePool (deviceSettings); deviceSettings = NULL; }
//
// add the new settings
//
RtlZeroMemory ( &tempDeviceSettings->FirmwareSettings[firstNewEntryOffset], sizeof (IDEREGS)); tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bFeaturesReg = IDE_SET_FEATURE_DISABLE_REVERT_TO_POWER_ON; tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bCommandReg = IDE_COMMAND_SET_FEATURE; tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL;
if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) {
RtlZeroMemory ( &tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1], sizeof (IDEREGS)); tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bFeaturesReg = IDE_SET_FEATURE_ENABLE_WRITE_CACHE; tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bCommandReg = IDE_COMMAND_SET_FEATURE; tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL; }
//
// throw away the old and keep the new
//
deviceSettings = tempDeviceSettings;
} else {
//
// someone took all the memory.
// we can't build a new device setting structure
// will have to use the old one
//
}
//
// keep it around
//
PdoExtension->AcpiDeviceSettings = deviceSettings;
}
return STATUS_SUCCESS; }
NTSTATUS DeviceInitDeviceState ( IN PPDO_EXTENSION PdoExtension, DEVICE_INIT_COMPLETION DeviceInitCompletionRoutine, PVOID DeviceInitCompletionContext ) { PDEVICE_SETTINGS deviceSettings; NTSTATUS status; PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext; ULONG deviceStateContextSize; ULONG numState; ULONG numRequestSent; DEVICE_INIT_STATE deviceInitState[deviceInitState_done];
if (!InterlockedExchange (&PdoExtension->InitDeviceWithAcpiGtf, 0)) {
//
// make sure we only do this once per start
//
return STATUS_SUCCESS; }
if (!(PdoExtension->PdoState & PDOS_STARTED)) {
DebugPrint ((DBG_PNP, "DeviceInitDeviceState: device not started...skipping acpi init\n"));
(DeviceInitCompletionRoutine) ( DeviceInitCompletionContext, STATUS_SUCCESS );
return STATUS_SUCCESS; }
deviceStateContextSize = sizeof (DEVICE_INIT_DEVICE_STATE_CONTEXT);
deviceStateContext = ExAllocatePool (NonPagedPool, deviceStateContextSize); if (deviceStateContext == NULL) {
return STATUS_NO_MEMORY; }
if (!RefPdoWithTag(PdoExtension->DeviceObject, FALSE, DeviceInitDeviceState)) { ExFreePool (deviceStateContext); return STATUS_NO_SUCH_DEVICE; }
RtlZeroMemory( deviceStateContext, deviceStateContextSize );
deviceSettings = PdoExtension->AcpiDeviceSettings;
//
// compute the total number of inti state we are going to have
//
numState = 0; if (deviceSettings) {
deviceStateContext->DeviceInitState[numState] = deviceInitState_acpi; numState++; } deviceStateContext->DeviceInitState[numState] = deviceInitState_done; numState++;
ASSERT(numState <= deviceInitState_max);
deviceStateContext->PdoExtension = PdoExtension; deviceStateContext->NumInitState = numState; deviceStateContext->DeviceInitCompletionRoutine = DeviceInitCompletionRoutine; deviceStateContext->DeviceInitCompletionContext = DeviceInitCompletionContext;
DeviceInitDeviceStateCompletionRoutine ( PdoExtension->DeviceObject, deviceStateContext, STATUS_SUCCESS );
return STATUS_PENDING; } // DeviceInitDeviceState
VOID DeviceInitDeviceStateCompletionRoutine ( PDEVICE_OBJECT DeviceObject, PVOID Context, NTSTATUS Status ) { ULONG numRequestCompleted; PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext = Context; PDEVICE_SETTINGS deviceSettings; PPDO_EXTENSION PdoExtension; NTSTATUS status;
if (!NT_SUCCESS(Status)) {
InterlockedIncrement (&deviceStateContext->NumRequestFailed); DebugPrint ((DBG_ALWAYS, "DeviceInitDeviceStateCompletionRoutine: Last init. command failed with status %x\n", Status)); }
PdoExtension = deviceStateContext->PdoExtension; switch (deviceStateContext->DeviceInitState[deviceStateContext->CurrentState]) {
case deviceInitState_acpi:
deviceSettings = PdoExtension->AcpiDeviceSettings; ASSERT (deviceSettings);
RtlZeroMemory ( &deviceStateContext->AtaPassThroughData, sizeof(deviceStateContext->AtaPassThroughData) );
deviceStateContext->AtaPassThroughData.IdeReg = deviceSettings->FirmwareSettings[deviceStateContext->NumAcpiRequestSent];
deviceStateContext->AtaPassThroughData.IdeReg.bReserved |= ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_URGENT;
deviceStateContext->NumAcpiRequestSent++; if (deviceStateContext->NumAcpiRequestSent >= deviceSettings->NumEntries) { //
// sent all acpi init state. go to the next state
//
deviceStateContext->CurrentState++; }
if ((deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg == IDE_SET_FEATURE_ENABLE_WRITE_CACHE) && (deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg == IDE_COMMAND_SET_FEATURE)) {
//
// only ata harddisk should have this entry
//
ASSERT (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE);
if (PdoExtension->WriteCacheEnable == FALSE) {
deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_DISABLE_WRITE_CACHE; } }
DebugPrint (( DBG_PNP, "IdePort: restore firmware settings from ACPI BIOS. ide command = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg, deviceStateContext->AtaPassThroughData.IdeReg.bSectorCountReg, deviceStateContext->AtaPassThroughData.IdeReg.bSectorNumberReg, deviceStateContext->AtaPassThroughData.IdeReg.bCylLowReg, deviceStateContext->AtaPassThroughData.IdeReg.bCylHighReg, deviceStateContext->AtaPassThroughData.IdeReg.bDriveHeadReg, deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg ));
status = IssueAsyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &deviceStateContext->AtaPassThroughData, TRUE, DeviceInitDeviceStateCompletionRoutine, deviceStateContext, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE ); if (!NT_SUCCESS(status)) {
//
// can't send the request
// notify the completion routine that we fail
//
DeviceInitDeviceStateCompletionRoutine ( PdoExtension->DeviceObject, deviceStateContext, status ); } break;
case deviceInitState_done:
//
// notify the original caller w/ error if any
//
(*deviceStateContext->DeviceInitCompletionRoutine) ( deviceStateContext->DeviceInitCompletionContext, deviceStateContext->NumRequestFailed ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS );
UnrefPdoWithTag( deviceStateContext->PdoExtension, DeviceInitDeviceState );
ExFreePool (deviceStateContext); break;
default: ASSERT(FALSE); }
return; }
NTSTATUS DeviceIdeReadCapacity ( IN PPDO_EXTENSION PdoExtension, IN OUT PIRP Irp ) { NTSTATUS status; PIDE_READ_CAPACITY_CONTEXT context; PATA_PASS_THROUGH ataPassThroughData; ULONG dataSize; PUCHAR dataOffset; PHW_DEVICE_EXTENSION hwDeviceExtension=PdoExtension->ParentDeviceExtension->HwDeviceExtension; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
//
// Check for device present flag
//
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; }
context = ExAllocatePool ( NonPagedPool, sizeof(IDE_READ_CAPACITY_CONTEXT) ); if ((context == NULL) || (Irp->MdlAddress == NULL)) {
if (context) { ExFreePool(context); }
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; srb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(IDE_READ_CAPACITY_CONTEXT), IDEPORT_TAG_READCAP_CONTEXT );
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; }
//
// save the old data buffer for restoring later
//
context->OldDataBuffer = srb->DataBuffer; context->GeometryIoctl=FALSE;
//
// map the buffer in
//
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); srb->DataBuffer = dataOffset + (ULONG)((PUCHAR)srb->DataBuffer - (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
context->PdoExtension = PdoExtension; context->OriginalIrp = Irp;
// MdlSafe failed
if (dataOffset == NULL) {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(MDL), IDEPORT_TAG_READCAP_MDL );
DeviceIdeReadCapacityCompletionRoutine ( PdoExtension->DeviceObject, context, STATUS_INSUFFICIENT_RESOURCES ); return STATUS_INSUFFICIENT_RESOURCES; }
IoMarkIrpPending(Irp);
ataPassThroughData = &context->AtaPassThroughData;
RtlZeroMemory ( ataPassThroughData, sizeof (*ataPassThroughData) );
ataPassThroughData->DataBufferSize = sizeof(IDENTIFY_DATA);
ataPassThroughData->IdeReg.bCommandReg = IDE_COMMAND_IDENTIFY; ataPassThroughData->IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
status = IssueAsyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, ataPassThroughData, TRUE, DeviceIdeReadCapacityCompletionRoutine, context, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE );
if (status != STATUS_PENDING) {
DeviceIdeReadCapacityCompletionRoutine ( PdoExtension->DeviceObject, context, status ); }
//
// the irp was marked pending. return status_pending
//
return STATUS_PENDING; }
VOID DeviceIdeReadCapacityCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, PVOID Context, NTSTATUS Status ) { PIDE_READ_CAPACITY_CONTEXT context = Context; PIRP irp = context->OriginalIrp; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp); PSCSI_REQUEST_BLOCK srb; KIRQL currentIrql; PKSPIN_LOCK spinLock; ULONG numberOfCylinders; ULONG numberOfHeads; ULONG sectorsPerTrack; PHW_DEVICE_EXTENSION hwDeviceExtension; ULONG i; ULONG totalCHSSize; ULONG targetId; PIDENTIFY_DATA identifyData;
srb = irpStack->Parameters.Scsi.Srb; targetId=srb->TargetId; hwDeviceExtension = context->PdoExtension->ParentDeviceExtension->HwDeviceExtension; spinLock = &context->PdoExtension->ParentDeviceExtension->SpinLock;
if (NT_SUCCESS(Status)) {
identifyData = (PIDENTIFY_DATA) context->AtaPassThroughData.DataBuffer;
IdePortFudgeAtaIdentifyData( identifyData );
if ( ((identifyData->MajorRevision == 0) || ((identifyData->NumberOfCurrentCylinders == 0) || (identifyData->NumberOfCurrentHeads == 0) || (identifyData->CurrentSectorsPerTrack == 0))) ) {
numberOfCylinders = identifyData->NumCylinders; numberOfHeads = identifyData->NumHeads; sectorsPerTrack = identifyData->NumSectorsPerTrack;
} else {
numberOfCylinders = identifyData->NumberOfCurrentCylinders; numberOfHeads = identifyData->NumberOfCurrentHeads; sectorsPerTrack = identifyData->CurrentSectorsPerTrack;
if (identifyData->UserAddressableSectors > (numberOfCylinders * numberOfHeads * sectorsPerTrack)) {
//
// some ide driver has a 2G jumer to get around bios
// problem. make sure we are not tricked the samw way.
//
if ((numberOfCylinders <= 0xfff) && (numberOfHeads == 0x10) && (sectorsPerTrack == 0x3f)) {
numberOfCylinders = identifyData->UserAddressableSectors / (0x10 * 0x3f); } }
}
//
// Workaround for devices that return 0 in the geometry fields.
//
if ((numberOfCylinders == 0) || (numberOfHeads == 0) || (sectorsPerTrack == 0)) {
//
// round up chs to 1
//
numberOfCylinders = 1; numberOfHeads = 1; sectorsPerTrack =1; totalCHSSize = 0;
} else {
totalCHSSize = (numberOfHeads * numberOfCylinders * sectorsPerTrack);
}
//
// update the HW Device Extension Data
//
KeAcquireSpinLock(spinLock, ¤tIrql);
InitDeviceGeometry( hwDeviceExtension, targetId, numberOfCylinders, numberOfHeads, sectorsPerTrack );
if (hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_IDENTIFY_INVALID) {
RtlMoveMemory ( hwDeviceExtension->IdentifyData + targetId, identifyData, sizeof (IDENTIFY_DATA) ); ASSERT(!(hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_REMOVABLE_DRIVE));
SETMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_VALID); CLRMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_INVALID); }
if (srb) { //
// Claim 512 byte blocks (big-endian).
//
((READ_CAPACITY_DATA UNALIGNED *)srb->DataBuffer)->BytesPerBlock = 0x20000;
//
// Calculate last sector.
//
if (context->PdoExtension->ParentDeviceExtension-> HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_LBA) { // LBA device
i = identifyData->UserAddressableSectors - 1;
//
// LBAs can only be 28 bits wide
//
if (i >= MAX_28BIT_LBA) { i = MAX_28BIT_LBA - 1; }
#ifdef ENABLE_48BIT_LBA
if (context->PdoExtension->ParentDeviceExtension-> HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_48BIT_LBA) {
i = identifyData->Max48BitLBA[0] - 1;
//
// currently we support only upto 32 bits.
//
ASSERT(identifyData->Max48BitLBA[1] == 0); } #endif
DebugPrint((1, "IDE LBA disk %x - total # of sectors = 0x%x\n", srb->TargetId, identifyData->UserAddressableSectors));
} else {
// CHS device
//i = (numberOfHeads * numberOfCylinders * sectorsPerTrack) - 1;
i=totalCHSSize - 1;
DebugPrint((1, "IDE CHS disk %x - #sectors %x, #heads %x, #cylinders %x\n", srb->TargetId, sectorsPerTrack, numberOfHeads, numberOfCylinders)); DebugPrint((1, "IDE CHS disk Identify data%x - #sectors %x, #heads %x, #cylinders %x\n", srb->TargetId, identifyData->NumSectorsPerTrack, identifyData->NumHeads, identifyData->NumCylinders)); DebugPrint((1, "IDE CHS disk Identify currentdata%x - #sectors %x, #heads %x, #cylinders %x\n", srb->TargetId, identifyData->CurrentSectorsPerTrack, identifyData->NumberOfCurrentHeads, identifyData->NumberOfCurrentCylinders)); }
((READ_CAPACITY_DATA UNALIGNED *)srb->DataBuffer)->LogicalBlockAddress = (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) | (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
srb->SrbStatus = SRB_STATUS_SUCCESS;
irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
}
KeReleaseSpinLock(spinLock, currentIrql);
} else {
if (srb) { if (Status==STATUS_INSUFFICIENT_RESOURCES) { srb->SrbStatus=SRB_STATUS_INTERNAL_ERROR; srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES; } else { srb->SrbStatus = SRB_STATUS_ERROR; } } }
if (srb) {
//
// restoring DataBuffer
//
srb->DataBuffer = context->OldDataBuffer; }
UnrefLogicalUnitExtensionWithTag( context->PdoExtension->ParentDeviceExtension, context->PdoExtension, irp );
IDEPORT_PUT_LUNEXT_IN_IRP (irpStack, NULL);
ExFreePool (context);
irp->IoStatus.Status = Status; IoCompleteRequest(irp, IO_NO_INCREMENT); return; }
NTSTATUS DeviceIdeModeSense ( IN PPDO_EXTENSION PdoExtension, IN OUT PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; PSCSI_REQUEST_BLOCK srb; PCDB cdb; ULONG modeDataBufferSize; ULONG dataBufferSize; ULONG dataBufferByteLeft; PMODE_PARAMETER_HEADER modePageHeader; PUCHAR pageData; PHW_DEVICE_EXTENSION hwDeviceExtension;
PAGED_CODE();
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp); srb = irpStack->Parameters.Scsi.Srb; cdb = (PCDB) srb->Cdb;
//
// Check for device present flag
//
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; }
ASSERT(cdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE);
//
// make sure this is for the right lun
//
if (cdb->MODE_SENSE.LogicalUnitNumber != PdoExtension->Lun) {
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto getout; }
//
// only support page control for current values
//
if (cdb->MODE_SENSE.Pc != 0) {
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto getout; }
//
// save the data buffer size for later use
//
modeDataBufferSize = srb->DataTransferLength;
//
// make sure the output buffer is at least the size of the header
//
if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) {
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_BUFFER_TOO_SMALL; goto getout; }
//
// some basic init.
//
modePageHeader = srb->DataBuffer; pageData = (PUCHAR) (modePageHeader + 1); RtlZeroMemory (modePageHeader, modeDataBufferSize); ASSERT (modeDataBufferSize); ASSERT (modePageHeader);
modePageHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) - FIELD_OFFSET(MODE_PARAMETER_HEADER, MediumType);
//
// get write protect bit from smart data
//
if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
ATA_PASS_THROUGH ataPassThroughData; NTSTATUS localStatus;
RtlZeroMemory ( &ataPassThroughData, sizeof (ataPassThroughData) );
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS; ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED; localStatus = IssueSyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &ataPassThroughData, FALSE, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE); if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR) {
if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){
modePageHeader->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT; } } }
dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) || (cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
//
// cache settings page
//
PMODE_CACHING_PAGE cachePage;
cachePage = (PMODE_CACHING_PAGE) pageData;
cachePage->PageCode = MODE_PAGE_CACHING; cachePage->PageSavable = 0; cachePage->PageLength = 0xa; cachePage->ReadDisableCache = 0; cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
//
// update out data buffer pointer
//
pageData += sizeof (MODE_CACHING_PAGE); dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE); modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
} else {
srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; srb->DataTransferLength -= dataBufferByteLeft; Irp->IoStatus.Information = srb->DataTransferLength; status = STATUS_BUFFER_TOO_SMALL; goto getout; } }
//
// update the number of bytes we are returning
//
srb->DataTransferLength -= dataBufferByteLeft; Irp->IoStatus.Information = srb->DataTransferLength; status = STATUS_SUCCESS; srb->SrbStatus = SRB_STATUS_SUCCESS;
getout:
UnrefPdoWithTag( PdoExtension, Irp );
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
NTSTATUS DeviceIdeModeSelect ( IN PPDO_EXTENSION PdoExtension, IN OUT PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; PSCSI_REQUEST_BLOCK srb; PCDB cdb;
ULONG modeDataBufferSize; PMODE_PARAMETER_HEADER modePageHeader; PUCHAR modePage; ULONG pageOffset; PMODE_CACHING_PAGE cachePage; PHW_DEVICE_EXTENSION hwDeviceExtension;
PAGED_CODE();
irpStack = IoGetCurrentIrpStackLocation(Irp); srb = irpStack->Parameters.Scsi.Srb; cdb = (PCDB) srb->Cdb;
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
//
// Check for device present flag
//
if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; }
ASSERT(cdb->MODE_SELECT.OperationCode == SCSIOP_MODE_SELECT);
//
// make sure this is for the right lun
//
if (cdb->MODE_SELECT.LogicalUnitNumber != PdoExtension->Lun) {
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto getout; }
//
// only support scsi-2 mode select format
//
if (cdb->MODE_SELECT.PFBit != 1) {
srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto getout; }
modeDataBufferSize = cdb->MODE_SELECT.ParameterListLength; modePageHeader = srb->DataBuffer;
if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) { srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto getout; }
pageOffset = sizeof(MODE_PARAMETER_HEADER) + modePageHeader->BlockDescriptorLength;
while (modeDataBufferSize > pageOffset) {
modePage = ((PUCHAR) modePageHeader) + pageOffset; cachePage = (PMODE_CACHING_PAGE) modePage;
if ((cachePage->PageCode == MODE_PAGE_CACHING) && ((modePageHeader->ModeDataLength - pageOffset) >= sizeof(MODE_CACHING_PAGE)) && (cachePage->PageLength == 0xa)) {
if (cachePage->WriteCacheEnable != PdoExtension->WriteCacheEnable) {
ATA_PASS_THROUGH ataPassThroughData; NTSTATUS localStatus;
RtlZeroMemory ( &ataPassThroughData, sizeof (ataPassThroughData) );
if (cachePage->WriteCacheEnable) { ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_ENABLE_WRITE_CACHE; } else { ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_DISABLE_WRITE_CACHE; } ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_SET_FEATURE; ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED; localStatus = IssueSyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &ataPassThroughData, FALSE, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE); if (NT_SUCCESS(localStatus) && !(ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR)) {
PdoExtension->WriteCacheEnable = cachePage->WriteCacheEnable; } else { status = STATUS_IO_DEVICE_ERROR; srb->SrbStatus = SRB_STATUS_ERROR; goto getout; }
}
pageOffset += sizeof(MODE_CACHING_PAGE);
} else { status = STATUS_INVALID_PARAMETER; srb->SrbStatus = SRB_STATUS_ERROR; goto getout; } }
status = STATUS_SUCCESS; srb->SrbStatus = SRB_STATUS_SUCCESS;
getout:
UnrefPdoWithTag( PdoExtension, Irp );
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
NTSTATUS DeviceQueryPnPDeviceState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { NTSTATUS status; PPDO_EXTENSION pdoExtension;
pdoExtension = RefPdoWithTag( DeviceObject, TRUE, DeviceQueryPnPDeviceState );
if (pdoExtension) {
PPNP_DEVICE_STATE deviceState;
DebugPrint((DBG_PNP, "QUERY_DEVICE_STATE for PDOE 0x%x\n", pdoExtension));
if(pdoExtension->PagingPathCount != 0) { deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information); SETMASK((*deviceState), PNP_DEVICE_NOT_DISABLEABLE); }
status = STATUS_SUCCESS;
UnrefPdoWithTag( pdoExtension, DeviceQueryPnPDeviceState );
} else {
status = STATUS_DEVICE_DOES_NOT_EXIST; }
Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status; }
NTSTATUS DeviceAtapiModeCommandCompletion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++
Description
Completes the original irp after copying the data from the current srb Arguments:
DeviceObject Not used Irp The irp - Not used Context Srb Return value:
STATUS_MORE_PROCESSING_REQUIRED --*/ { PIO_STACK_LOCATION irpStack; PIDE_MODE_COMMAND_CONTEXT context = Context; PSCSI_REQUEST_BLOCK srb = context->Srb; PSCSI_REQUEST_BLOCK originalSrb; PIRP originalIrp; UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) - sizeof(MODE_PARAMETER_HEADER); ULONG transferLength;
//
// retrieve the original srb and the irp
//
originalSrb = *((PVOID *) (srb+1)); ASSERT(originalSrb);
originalIrp = originalSrb->OriginalRequest; ASSERT(originalIrp);
transferLength = srb->DataTransferLength;
if (srb->Cdb[0] == ATAPI_MODE_SENSE) {
PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)(srb->DataBuffer); PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
header->ModeDataLength = header_10->ModeDataLengthLsb; header->MediumType = header_10->MediumType;
//
// ATAPI Mode Parameter Header doesn't have these fields.
//
header->DeviceSpecificParameter = header_10->Reserved[0];
//
// ISSUE:
//
header->BlockDescriptorLength = header_10->Reserved[4]; //
// copy the rest of the data
//
if (transferLength > sizeof(MODE_PARAMETER_HEADER_10)) {
RtlMoveMemory((PUCHAR)originalSrb->DataBuffer+sizeof(MODE_PARAMETER_HEADER), (PUCHAR)srb->DataBuffer+sizeof(MODE_PARAMETER_HEADER_10), transferLength - sizeof(MODE_PARAMETER_HEADER_10)); }
DebugPrint((1, "Mode Sense completed - status 0x%x, length 0x%x\n", srb->SrbStatus, srb->DataTransferLength ));
} else if (srb->Cdb[0] == ATAPI_MODE_SELECT) {
DebugPrint((1, "Mode Select completed - status 0x%x, length 0x%x\n", srb->SrbStatus, srb->DataTransferLength )); } else {
ASSERT (FALSE); }
//
// update the original srb
//
originalSrb->DataBuffer = context->OriginalDataBuffer; originalSrb->SrbStatus = srb->SrbStatus; originalSrb->ScsiStatus = srb->ScsiStatus;
if (transferLength > bytesAdjust) { originalSrb->DataTransferLength = transferLength - bytesAdjust; } else {
//
// error. transfer length should be zero.
// if it is less than the header, we will just pass it up.
//
originalSrb->DataTransferLength = transferLength; }
//
// Decrement the logUnitExtension reference count
//
irpStack = IoGetCurrentIrpStackLocation(originalIrp);
UnrefLogicalUnitExtensionWithTag( IDEPORT_GET_LUNEXT_IN_IRP(irpStack)->ParentDeviceExtension, IDEPORT_GET_LUNEXT_IN_IRP(irpStack), originalIrp );
//
// we will follow the same logic as we did for srb data transfer length.
//
if (Irp->IoStatus.Information > bytesAdjust) { originalIrp->IoStatus.Information = Irp->IoStatus.Information - bytesAdjust; } else { originalIrp->IoStatus.Information = Irp->IoStatus.Information; } originalIrp->IoStatus.Status = Irp->IoStatus.Status;
DebugPrint((1, "Original Mode command completed - status 0x%x, length 0x%x, irpstatus 0x%x\n", originalSrb->SrbStatus, originalSrb->DataTransferLength, originalIrp->IoStatus.Status ));
IoCompleteRequest(originalIrp, IO_NO_INCREMENT);
//
// Free the srb, buffer and the irp
//
ASSERT(srb->DataBuffer); ExFreePool(srb->DataBuffer);
ExFreePool(srb);
ExFreePool(context);
IdeFreeIrpAndMdl(Irp);
return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS DeviceAtapiModeSense ( IN PPDO_EXTENSION PdoExtension, IN PIRP Irp ) /*++
--*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb; PSCSI_REQUEST_BLOCK srb = NULL; NTSTATUS status; PVOID *pointer; PCDB cdb; PVOID modeSenseBuffer; PUCHAR dataOffset; PIDE_MODE_COMMAND_CONTEXT context; PMODE_PARAMETER_HEADER_10 header_10; PMODE_PARAMETER_HEADER header; UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) - sizeof(MODE_PARAMETER_HEADER); USHORT allocationLength;
IoMarkIrpPending(Irp);
context = NULL; srb = NULL;
//
// databuffer should be as big as the header
//
if (originalSrb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) {
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto GetOut; }
//
// allocate the context
//
context = ExAllocatePool ( NonPagedPool, sizeof(IDE_MODE_COMMAND_CONTEXT) );
if (context == NULL) {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(IDE_MODE_COMMAND_CONTEXT), IDEPORT_TAG_ATAPI_MODE_SENSE );
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
ASSERT(context);
context->OriginalDataBuffer = originalSrb->DataBuffer;
if (Irp->MdlAddress == NULL) {
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// map the buffer in
//
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); originalSrb->DataBuffer = dataOffset + (ULONG)((PUCHAR)originalSrb->DataBuffer - (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)); //
// allocate a new srb
//
srb = ExAllocatePool (NonPagedPool, sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
if (srb == NULL) {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(SCSI_REQUEST_BLOCK), IDEPORT_TAG_ATAPI_MODE_SENSE );
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// Save the original SRB after the Srb.
//
pointer = (PVOID *) (srb+1); *pointer = originalSrb;
//
// Fill in SRB fields.
//
RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
//
// Allocate a new buffer
//
modeSenseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, originalSrb->DataTransferLength + bytesAdjust );
RtlZeroMemory(modeSenseBuffer,originalSrb->DataTransferLength+bytesAdjust); header_10 = (PMODE_PARAMETER_HEADER_10)modeSenseBuffer; header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
header_10->ModeDataLengthLsb = header->ModeDataLength; header_10->MediumType = header->MediumType;
header_10->Reserved[4] = header->BlockDescriptorLength;
srb->DataBuffer = modeSenseBuffer; srb->DataTransferLength = originalSrb->DataTransferLength + bytesAdjust;
srb->CdbLength = 12;
allocationLength = ((PCDB)originalSrb->Cdb)->MODE_SENSE.AllocationLength; allocationLength += bytesAdjust;
cdb = (PCDB) srb->Cdb;
RtlZeroMemory(cdb, sizeof(CDB));
cdb->MODE_SENSE10.OperationCode = ATAPI_MODE_SENSE; cdb->MODE_SENSE10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SENSE.LogicalUnitNumber; cdb->MODE_SENSE10.PageCode = ((PCDB)originalSrb->Cdb)->MODE_SENSE.PageCode; cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR) (allocationLength >> 8); cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR) (allocationLength & 0xFF);
context->Srb = srb;
//
// send the srb
//
status = IdeBuildAndSendIrp (PdoExtension, srb, DeviceAtapiModeCommandCompletion, context );
if (NT_SUCCESS(status)) {
ASSERT(status == STATUS_PENDING);
return STATUS_PENDING; }
GetOut:
if (srb) { ExFreePool(srb); }
if (context) {
originalSrb->DataBuffer = context->OriginalDataBuffer; ExFreePool(context); }
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_PENDING; }
NTSTATUS DeviceAtapiModeSelect ( IN PPDO_EXTENSION PdoExtension, IN PIRP Irp ) /*++
--*/ { PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb; PSCSI_REQUEST_BLOCK srb = NULL; NTSTATUS status; PVOID *pointer; PCDB cdb; PVOID modeSelectBuffer; PUCHAR dataOffset; PIDE_MODE_COMMAND_CONTEXT context; PMODE_PARAMETER_HEADER_10 header_10; PMODE_PARAMETER_HEADER header; UCHAR bytesToSkip; UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) - sizeof(MODE_PARAMETER_HEADER); USHORT paramListLength;
IoMarkIrpPending(Irp);
context = NULL; srb = NULL;
//
// the databuffer should be big enough to hold the header
//
if (originalSrb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) {
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto GetOut; }
header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
//
// do not copy the block descriptor. Atapi devices don't use
// the block descriptor.
//
bytesToSkip = sizeof(MODE_PARAMETER_HEADER) + header->BlockDescriptorLength;
//
// the databuffer should be big enough to hold the header
// and the block descriptor (specified in the header)
//
if (originalSrb->DataTransferLength < bytesToSkip) {
originalSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST; status = STATUS_INVALID_DEVICE_REQUEST; goto GetOut; }
//
// allocate the context
//
context = ExAllocatePool ( NonPagedPool, sizeof(IDE_MODE_COMMAND_CONTEXT) );
if (context == NULL) {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(IDE_MODE_COMMAND_CONTEXT), IDEPORT_TAG_ATAPI_MODE_SENSE );
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
ASSERT(context);
context->OriginalDataBuffer = originalSrb->DataBuffer;
if (Irp->MdlAddress == NULL) {
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// map the buffer in
//
dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); originalSrb->DataBuffer = dataOffset + (ULONG)((PUCHAR)originalSrb->DataBuffer - (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
//
// allocate a new srb
//
srb = ExAllocatePool (NonPagedPool, sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
if (srb == NULL) {
IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension, PdoExtension->TargetId, NonPagedPool, sizeof(SCSI_REQUEST_BLOCK), IDEPORT_TAG_ATAPI_MODE_SENSE );
originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR; originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
status = STATUS_INSUFFICIENT_RESOURCES; goto GetOut; }
//
// Save the original SRB after the Srb.
//
pointer = (PVOID *) (srb+1); *pointer = originalSrb;
//
// Fill in SRB fields.
//
RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
//
// Allocate a new buffer (we should subtract the block descriptor length
// leave it like this for the time being)
//
modeSelectBuffer = ExAllocatePool(NonPagedPoolCacheAligned, originalSrb->DataTransferLength + bytesAdjust );
RtlZeroMemory(modeSelectBuffer, sizeof(MODE_PARAMETER_HEADER_10)); header_10 = (PMODE_PARAMETER_HEADER_10)modeSelectBuffer;
header_10->ModeDataLengthLsb = header->ModeDataLength; header_10->MediumType = header->MediumType;
//
// block descriptor length in header_10 should be 0 for ATAPI devices
//
//header_10->Reserved[4] = header->BlockDescriptorLength;
//
// copy the rest of the buffer, if any
//
if (originalSrb->DataTransferLength > bytesToSkip) {
RtlCopyMemory(((PUCHAR)modeSelectBuffer+sizeof(MODE_PARAMETER_HEADER_10)), ((PUCHAR)originalSrb->DataBuffer + bytesToSkip), (originalSrb->DataTransferLength - bytesToSkip) ); }
/*
RtlCopyMemory(((PUCHAR)modeSelectBuffer+sizeof(MODE_PARAMETER_HEADER_10)), ((PUCHAR)originalSrb->DataBuffer + sizeof(MODE_PARAMETER_HEADER)), (originalSrb->DataTransferLength - sizeof(MODE_PARAMETER_HEADER)) ); */
srb->DataBuffer = modeSelectBuffer; srb->DataTransferLength = originalSrb->DataTransferLength + sizeof(MODE_PARAMETER_HEADER_10) - bytesToSkip;
srb->CdbLength = 12; paramListLength = ((PCDB)originalSrb->Cdb)->MODE_SELECT.ParameterListLength; paramListLength += sizeof(MODE_PARAMETER_HEADER_10); paramListLength -= bytesToSkip;
//
// fill in the cdb
//
cdb = (PCDB) srb->Cdb;
RtlZeroMemory(cdb, sizeof(CDB));
cdb->MODE_SELECT10.OperationCode = ATAPI_MODE_SELECT; cdb->MODE_SELECT10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SELECT.LogicalUnitNumber; cdb->MODE_SELECT10.SPBit = ((PCDB)originalSrb->Cdb)->MODE_SELECT.SPBit; cdb->MODE_SELECT10.PFBit = 1; cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (paramListLength >> 8); cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (paramListLength & 0xFF);
context->Srb = srb;
//
// send the srb
//
status = IdeBuildAndSendIrp (PdoExtension, srb, DeviceAtapiModeCommandCompletion, context );
if (NT_SUCCESS(status)) {
ASSERT(status == STATUS_PENDING); return STATUS_PENDING; }
GetOut:
if (srb) { ExFreePool(srb); }
if (context) {
originalSrb->DataBuffer = context->OriginalDataBuffer;
ExFreePool(context); }
UnrefLogicalUnitExtensionWithTag( PdoExtension->ParentDeviceExtension, PdoExtension, Irp );
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_PENDING; }
#if 0
NTSTATUS DeviceIdeTestUnitReady ( IN PPDO_EXTENSION PdoExtension, IN OUT PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; PSCSI_REQUEST_BLOCK srb; PHW_DEVICE_EXTENSION hwDeviceExtension;
PAGED_CODE();
hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp); srb = irpStack->Parameters.Scsi.Srb;
//
// get write protect bit from smart data
//
if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
ATA_PASS_THROUGH ataPassThroughData; NTSTATUS localStatus;
RtlZeroMemory ( &ataPassThroughData, sizeof (ataPassThroughData) );
ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS; ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED; localStatus = IssueSyncAtaPassThroughSafe ( PdoExtension->ParentDeviceExtension, PdoExtension, &ataPassThroughData, FALSE, FALSE, DEFAULT_ATA_PASS_THROUGH_TIMEOUT, FALSE); if (NT_SUCCESS(localStatus)) {
if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR){ if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){ //
// Special case: If current media is write-protected,
// the 0xDA command will always fail since the write-protect bit
// is sticky,so we can ignore this error
//
status = SRB_STATUS_SUCCESS; } } } }
dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
if (IsNEC_98) {
HANDLE pageHandle; ULONG numberOfCylinders; ULONG numberOfHeads; ULONG sectorsPerTrack; KIRQL currentIrql; PKSPIN_LOCK spinLock;
//
// take a snap shot of the CHS values
//
spinLock = &PdoExtension->ParentDeviceExtension->SpinLock;
//
// lock the code before grabbing a lock
//
pageHandle = MmLockPagableCodeSection(DeviceIdeModeSense); KeAcquireSpinLock(spinLock, ¤tIrql);
numberOfCylinders = hwDeviceExtension->NumberOfCylinders[srb->TargetId]; numberOfHeads = hwDeviceExtension->NumberOfHeads[srb->TargetId]; sectorsPerTrack = hwDeviceExtension->SectorsPerTrack[srb->TargetId];
KeReleaseSpinLock(spinLock, currentIrql); MmUnlockPagableImageSection(pageHandle);
//
// Set pages which are formated as nec-scsi.
//
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) || (cdb->MODE_SENSE.PageCode == MODE_PAGE_ERROR_RECOVERY)) {
//
// error recovery page
//
if (dataBufferByteLeft >= 0x6 + 2) {
PMODE_DISCONNECT_PAGE recoveryPage;
recoveryPage = (PMODE_DISCONNECT_PAGE) pageData;
recoveryPage->PageCode = MODE_PAGE_ERROR_RECOVERY; recoveryPage->PageLength = 0x6;
//
// update out data buffer pointer
//
pageData += recoveryPage->PageLength + 2; dataBufferByteLeft -= (recoveryPage->PageLength + 2); modePageHeader->ModeDataLength += recoveryPage->PageLength + 2;
} else {
status = STATUS_BUFFER_TOO_SMALL; goto getout; } }
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) || (cdb->MODE_SENSE.PageCode == MODE_PAGE_FORMAT_DEVICE)) {
//
// format device page
//
if (dataBufferByteLeft >= 0x16 + 2) {
PMODE_FORMAT_PAGE formatPage;
formatPage = (PMODE_FORMAT_PAGE) pageData;
formatPage->PageCode = MODE_PAGE_FORMAT_DEVICE; formatPage->PageLength = 0x16;
//
// SectorsPerTrack
//
((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte1 = ((PFOUR_BYTE)§orsPerTrack)->Byte0;
((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte0 = ((PFOUR_BYTE)§orsPerTrack)->Byte1;
//
// update out data buffer pointer
//
pageData += formatPage->PageLength + 2; dataBufferByteLeft -= (formatPage->PageLength + 2); modePageHeader->ModeDataLength += formatPage->PageLength + 2;
} else {
status = STATUS_BUFFER_TOO_SMALL; goto getout; } }
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) || (cdb->MODE_SENSE.PageCode == MODE_PAGE_RIGID_GEOMETRY)) {
//
// rigid geometry page
//
if (dataBufferByteLeft >= 0x12 + 2) {
PMODE_RIGID_GEOMETRY_PAGE geometryPage;
geometryPage = (PMODE_RIGID_GEOMETRY_PAGE) pageData;
geometryPage->PageCode = MODE_PAGE_RIGID_GEOMETRY; geometryPage->PageLength = 0x12;
//
// NumberOfHeads
//
geometryPage->NumberOfHeads = (UCHAR) numberOfHeads;
//
// NumberOfCylinders
//
((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte2 = ((PFOUR_BYTE)&numberOfCylinders)->Byte0; ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte1 = ((PFOUR_BYTE)&numberOfCylinders)->Byte1; ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte0 = 0;
//
// update out data buffer pointer
//
pageData += geometryPage->PageLength + 2; dataBufferByteLeft -= (geometryPage->PageLength + 2); modePageHeader->ModeDataLength += geometryPage->PageLength + 2;
} else {
status = STATUS_BUFFER_TOO_SMALL; goto getout; } } }
if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) || (cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
//
// cache settings page
//
PMODE_CACHING_PAGE cachePage;
cachePage = (PMODE_CACHING_PAGE) pageData;
cachePage->PageCode = MODE_PAGE_CACHING; cachePage->PageSavable = 0; cachePage->PageLength = 0xa; cachePage->ReadDisableCache = 0; cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
//
// update out data buffer pointer
//
pageData += sizeof (MODE_CACHING_PAGE); dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE); modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
} else {
status = STATUS_BUFFER_TOO_SMALL; goto getout; } }
//
// update the number of bytes we are returning
//
srb->DataTransferLength -= dataBufferByteLeft; Irp->IoStatus.Information = srb->DataTransferLength; status = STATUS_SUCCESS; srb->SrbStatus = SRB_STATUS_SUCCESS;
getout:
UnrefPdoWithTag( PdoExtension, Irp );
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } #endif
|