/*++ 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; iFullVendorProductId)-1; i+=2) { c = PdoExtension->FullVendorProductId[i]; PdoExtension->FullVendorProductId[i] = PdoExtension->FullVendorProductId[i + 1]; PdoExtension->FullVendorProductId[i + 1] = c; } for (i=0; iFullProductRevisionId)-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; iSerialNumber); 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; iNumEntries; 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; jNumEntries; 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