You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5587 lines
161 KiB
5587 lines
161 KiB
/*++
|
|
|
|
|
|
Copyright (C) Microsoft Corporation, 1997 - 2001
|
|
|
|
Module Name:
|
|
|
|
sbp2port.c
|
|
|
|
Abstract:
|
|
|
|
Main module for the SBP-2 port driver
|
|
|
|
Author:
|
|
|
|
George Chrysanthakopoulos January-1997
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "sbp2port.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
|
|
|
|
#if DBG
|
|
ULONG Sbp2DebugLevel = 0;
|
|
|
|
ULONG NewSbp2DebugLevel = DEFAULT_DEBUG_LEVEL;
|
|
ULONG Sbp2TrapLevel = FALSE;
|
|
#endif
|
|
|
|
BOOLEAN SystemIsNT;
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2AddDevice(
|
|
PDRIVER_OBJECT DriverObject,
|
|
PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2StartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2CreateDeviceRelations(
|
|
IN PFDO_DEVICE_EXTENSION FdoExtension,
|
|
IN PDEVICE_RELATIONS DeviceRelations
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2CreateDevObject(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2DeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2CreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2PnpDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2FDOPnpDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2CreatePdo(
|
|
IN PFDO_DEVICE_EXTENSION FdoExtension,
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
ULONG instanceNum
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2PowerControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2SystemControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2FdoRequestCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT Event
|
|
);
|
|
|
|
|
|
VOID
|
|
Sbp2Unload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildDeviceId(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniDeviceId
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildHardwareIds(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniHardwareIds
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildCompatIds(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniCompatIds
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildInstanceId(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniInstanceId
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildDeviceText(
|
|
IN DEVICE_TEXT_TYPE TextType,
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniDeviceText
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2ForwardIrpSynchronous(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
Sbp2PortForwardIrpSynchronousCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
#pragma alloc_text(PAGE, Sbp2AddDevice)
|
|
#pragma alloc_text(PAGE, Sbp2StartDevice)
|
|
#pragma alloc_text(PAGE, Sbp2CreateDeviceRelations)
|
|
#pragma alloc_text(PAGE, Sbp2CreatePdo)
|
|
#pragma alloc_text(PAGE, Sbp2CreateDevObject)
|
|
#pragma alloc_text(PAGE, Sbp2DeviceControl)
|
|
#pragma alloc_text(PAGE, Sbp2SystemControl)
|
|
#pragma alloc_text(PAGE, Sbp2CreateClose)
|
|
#pragma alloc_text(PAGE, Sbp2ForwardIrpSynchronous)
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called at system initialization time so we can fill in the basic dispatch points
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Supplies the driver object.
|
|
|
|
RegistryPath - Supplies the registry path for this driver.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Initialize the Driver Object with driver's entry points
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: DriverEntry: %s %s\n", __DATE__, __TIME__));
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = Sbp2CreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = Sbp2CreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Sbp2DeviceControl;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SCSI] = Sbp2ScsiRequests;
|
|
|
|
DriverObject->DriverExtension->AddDevice = Sbp2AddDevice;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = Sbp2PnpDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP_POWER] = Sbp2PnpDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = Sbp2PowerControl;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Sbp2SystemControl;
|
|
|
|
DriverObject->DriverStartIo = Sbp2StartIo;
|
|
DriverObject->DriverUnload = Sbp2Unload;
|
|
|
|
SystemIsNT = IoIsWdmVersionAvailable ((UCHAR)0x01, (UCHAR)0x10);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2AddDevice(
|
|
PDRIVER_OBJECT DriverObject,
|
|
PDEVICE_OBJECT Pdo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is our PNP AddDevice called with the PDO ejected from the bus driver
|
|
|
|
Arguments:
|
|
|
|
Argument1 - Driver Object.
|
|
Argument2 - PDO.
|
|
|
|
|
|
Return Value:
|
|
|
|
A valid return code for a DriverEntry routine.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (Sbp2CreateDevObject (DriverObject,Pdo));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2CreateDevObject(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates an object for the physical device specified and
|
|
sets up the deviceExtension.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
PhysicalDeviceObject = PDO we should attach to.
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PFDO_DEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
|
|
UNICODE_STRING uniDeviceName;
|
|
|
|
WCHAR buffer[64];
|
|
UNICODE_STRING unicodeDirectoryName;
|
|
HANDLE handle;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
ULONG NextId = 0;
|
|
|
|
//
|
|
// This is the sbp2 filter device object and name
|
|
//
|
|
|
|
do {
|
|
|
|
swprintf (buffer, L"\\Device\\Sbp2Port%x", NextId);
|
|
|
|
RtlInitUnicodeString (&uniDeviceName, buffer);
|
|
|
|
status = IoCreateDevice(DriverObject,
|
|
sizeof(FDO_DEVICE_EXTENSION),
|
|
&uniDeviceName,
|
|
FILE_DEVICE_BUS_EXTENDER,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
&deviceObject);
|
|
|
|
NextId++;
|
|
|
|
} while (status == STATUS_OBJECT_NAME_COLLISION);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
RtlZeroMemory(deviceExtension,sizeof(FDO_DEVICE_EXTENSION));
|
|
|
|
if (Pdo != NULL) {
|
|
|
|
if ((deviceExtension->LowerDeviceObject =
|
|
IoAttachDeviceToDeviceStack(deviceObject,Pdo))==NULL){
|
|
|
|
IoDeleteDevice(deviceObject);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
deviceExtension->Type = SBP2_FDO;
|
|
deviceExtension->DeviceFlags = 0;
|
|
deviceExtension->DeviceObject = deviceObject;
|
|
deviceExtension->Pdo = Pdo;
|
|
KeInitializeSpinLock(&deviceExtension->DeviceListLock);
|
|
KeInitializeMutex (&deviceExtension->EnableBusResetNotificationMutex, 0);
|
|
|
|
//
|
|
// create a directory object for Sbp2 children devices
|
|
//
|
|
|
|
swprintf(buffer, L"\\Device\\Sbp2");
|
|
|
|
RtlInitUnicodeString(&unicodeDirectoryName, buffer);
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&unicodeDirectoryName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwCreateDirectoryObject(&handle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&objectAttributes);
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
deviceExtension->Sbp2ObjectDirectory = handle;
|
|
|
|
} else {
|
|
|
|
//
|
|
// the directory is already created by another instance of this driver..
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExInitializeFastMutex(&deviceExtension->ResetMutex);
|
|
|
|
IoInitializeRemoveLock( &deviceExtension->RemoveLock,
|
|
'2pbS',
|
|
REMLOCK_TIMEOUT,
|
|
REMLOCK_HIGH_WATERMARK
|
|
);
|
|
|
|
#if DBG
|
|
deviceExtension->ulWorkItemCount = 0;
|
|
deviceExtension->ulBusResetMutexCount = 0;
|
|
#endif
|
|
|
|
deviceObject->Flags |= DO_DIRECT_IO;
|
|
deviceObject->Flags &=~DO_DEVICE_INITIALIZING;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2CreatePdo(
|
|
IN PFDO_DEVICE_EXTENSION FdoExtension,
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
ULONG InstanceNumber
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION pdoExtension;
|
|
DEVICE_TYPE devType;
|
|
WCHAR *buffer;
|
|
UNICODE_STRING uniDeviceName;
|
|
NTSTATUS status;
|
|
ULONG byteSwappedData;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (DeviceInfo->CmdSetId.QuadPart) {
|
|
|
|
case 0x10483:
|
|
case SCSI_COMMAND_SET_ID:
|
|
|
|
switch ((DeviceInfo->Lun.u.HighPart & 0x001F)) {
|
|
|
|
case PRINTER_DEVICE:
|
|
|
|
devType = FILE_DEVICE_PRINTER;
|
|
break;
|
|
|
|
case SCANNER_DEVICE:
|
|
|
|
devType = FILE_DEVICE_SCANNER;
|
|
break;
|
|
|
|
case READ_ONLY_DIRECT_ACCESS_DEVICE:
|
|
case RBC_DEVICE:
|
|
case DIRECT_ACCESS_DEVICE:
|
|
default:
|
|
|
|
devType = FILE_DEVICE_MASS_STORAGE;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
devType = FILE_DEVICE_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
buffer = ExAllocatePool(PagedPool,
|
|
5 * SBP2_MAX_TEXT_LEAF_LENGTH * sizeof (WCHAR)
|
|
);
|
|
|
|
if (buffer == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (DeviceInfo->uniVendorId.Buffer && DeviceInfo->uniModelId.Buffer) {
|
|
|
|
swprintf( buffer,
|
|
L"\\Device\\Sbp2\\%ws&%ws&%x&%08x_%08x_Instance%02d",
|
|
DeviceInfo->uniVendorId.Buffer,
|
|
DeviceInfo->uniModelId.Buffer,
|
|
DeviceInfo->Lun.u.LowPart,
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
|
|
InstanceNumber
|
|
);
|
|
}
|
|
else {
|
|
|
|
swprintf( buffer,
|
|
L"\\Device\\Sbp2\\UNKNOWN_VENDOR&UNKNOWN_MODEL&%x&%08x_%08x_Instance%02d",
|
|
DeviceInfo->Lun.u.LowPart,
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
|
|
InstanceNumber
|
|
);
|
|
}
|
|
|
|
RtlInitUnicodeString (&uniDeviceName, buffer);
|
|
|
|
//
|
|
// Need to create a device object for this device
|
|
//
|
|
|
|
status = IoCreateDevice(
|
|
FdoExtension->DeviceObject->DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
&uniDeviceName,
|
|
devType,
|
|
0,
|
|
FALSE,
|
|
&DeviceInfo->DeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ExFreePool (buffer);
|
|
return status;
|
|
}
|
|
|
|
// only set alignment if it's less than we require
|
|
if (DeviceInfo->DeviceObject->AlignmentRequirement < SBP2_ALIGNMENT_MASK)
|
|
DeviceInfo->DeviceObject->AlignmentRequirement = SBP2_ALIGNMENT_MASK;
|
|
|
|
pdoExtension = (PDEVICE_EXTENSION)DeviceInfo->DeviceObject->DeviceExtension;
|
|
|
|
RtlZeroMemory(pdoExtension,sizeof(DEVICE_EXTENSION));
|
|
|
|
pdoExtension->LowerDeviceObject = FdoExtension->LowerDeviceObject;
|
|
pdoExtension->DeviceObject = DeviceInfo->DeviceObject;
|
|
pdoExtension->Type = SBP2_PDO;
|
|
pdoExtension->DeviceInfo = DeviceInfo;
|
|
pdoExtension->DeviceInfo->MaxClassTransferSize = FdoExtension->MaxClassTransferSize;
|
|
pdoExtension->BusFdo = FdoExtension->DeviceObject;
|
|
|
|
#if DBG
|
|
pdoExtension->ulPendingEvents = 0;
|
|
pdoExtension->ulInternalEventCount = 0;
|
|
#endif
|
|
|
|
KeInitializeSpinLock (&pdoExtension->ExtensionDataSpinLock);
|
|
|
|
IoInitializeRemoveLock(
|
|
&pdoExtension->RemoveLock,
|
|
'2pbS',
|
|
REMLOCK_TIMEOUT,
|
|
REMLOCK_HIGH_WATERMARK
|
|
);
|
|
|
|
switch (DeviceInfo->CmdSetId.QuadPart) {
|
|
|
|
case 0x10483:
|
|
case SCSI_COMMAND_SET_ID:
|
|
|
|
//
|
|
// intepret device type only for scsi-variant command sets
|
|
//
|
|
// NOTE: sbp2port.h #define's MAX_GENERIC_NAME_LENGTH as 16
|
|
//
|
|
|
|
DeviceInfo->uniGenericName.Length = 0;
|
|
DeviceInfo->uniGenericName.MaximumLength = MAX_GENERIC_NAME_LENGTH;
|
|
DeviceInfo->uniGenericName.Buffer = ExAllocatePool(PagedPool, DeviceInfo->uniGenericName.MaximumLength);
|
|
|
|
if (!DeviceInfo->uniGenericName.Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniGenericName.Buffer!"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
RtlZeroMemory(DeviceInfo->uniGenericName.Buffer, DeviceInfo->uniGenericName.MaximumLength);
|
|
|
|
switch ((DeviceInfo->Lun.u.HighPart & 0x001F)) {
|
|
|
|
case RBC_DEVICE:
|
|
case DIRECT_ACCESS_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenDisk");
|
|
break;
|
|
|
|
case SEQUENTIAL_ACCESS_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenSequential");
|
|
break;
|
|
|
|
case PRINTER_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenPrinter");
|
|
break;
|
|
|
|
case WRITE_ONCE_READ_MULTIPLE_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenWorm");
|
|
break;
|
|
|
|
case READ_ONLY_DIRECT_ACCESS_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenCdRom");
|
|
break;
|
|
|
|
case SCANNER_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenScanner");
|
|
break;
|
|
|
|
case OPTICAL_DEVICE:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenOptical");
|
|
break;
|
|
|
|
case MEDIUM_CHANGER:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenChanger");
|
|
break;
|
|
|
|
default:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenSbp2Device");
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
RtlAppendUnicodeToString(&DeviceInfo->uniGenericName, L"GenSbp2Device");
|
|
break;
|
|
}
|
|
|
|
TRACE(TL_PNP_INFO, ("GenericName = %ws", DeviceInfo->uniGenericName.Buffer));
|
|
|
|
DeviceInfo->DeviceObject->Flags |= DO_DIRECT_IO;
|
|
|
|
status = Sbp2PreAllocateLists (pdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
IoDeleteDevice (pdoExtension->DeviceObject);
|
|
DeviceInfo->DeviceObject = NULL;
|
|
|
|
} else {
|
|
|
|
PWCHAR symlinkBuffer;
|
|
|
|
symlinkBuffer = ExAllocatePool(PagedPool,
|
|
3 * SBP2_MAX_TEXT_LEAF_LENGTH * sizeof (WCHAR)
|
|
);
|
|
|
|
if (symlinkBuffer) {
|
|
|
|
swprintf(
|
|
symlinkBuffer,
|
|
L"\\DosDevices\\Sbp2&LUN%x&%08x%08x&Instance%02d",
|
|
DeviceInfo->Lun.u.LowPart,
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
|
|
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
|
|
InstanceNumber
|
|
);
|
|
|
|
RtlInitUnicodeString (&pdoExtension->UniSymLinkName,symlinkBuffer);
|
|
|
|
status = IoCreateUnprotectedSymbolicLink(
|
|
&pdoExtension->UniSymLinkName,
|
|
&uniDeviceName
|
|
);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: CreatePdo: symLink=%ws\n",
|
|
symlinkBuffer
|
|
));
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT1((
|
|
"\nSbp2Port: CreatePdo: createSymLink err=x%x\n",
|
|
status
|
|
));
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT1(("\n Sbp2CreatePdo: failed to alloc sym link buf\n"));
|
|
}
|
|
|
|
//
|
|
// if sym link fails its not critical
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExFreePool (buffer);
|
|
|
|
DeviceInfo->DeviceObject->Flags &=~DO_DEVICE_INITIALIZING;
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2StartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is our START_DEVICE, called when we get an IPR_MN_START_DEVICE. Initializes the driver and
|
|
retrieves physical device information and 1394 bus information required for accessing the device.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject = Sbp2 driver's device object
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension=DeviceObject->DeviceExtension;
|
|
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
ULONG temp;
|
|
BOOLEAN enabledBusResetNotification = FALSE;
|
|
|
|
if (deviceExtension->Type == SBP2_PDO) {
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
Sbp2GetExclusiveValue(DeviceObject, &deviceExtension->Exclusive);
|
|
|
|
#endif
|
|
|
|
if (!TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED)){
|
|
|
|
//
|
|
// initialize our device state flags
|
|
//
|
|
|
|
deviceExtension->DevicePowerState = PowerDeviceD0;
|
|
deviceExtension->SystemPowerState = PowerSystemWorking;
|
|
|
|
deviceExtension->MaxOrbListDepth = MAX_ORB_LIST_DEPTH;
|
|
}
|
|
|
|
deviceExtension->DeviceFlags = DEVICE_FLAG_PNP_STOPPED |
|
|
DEVICE_FLAG_STOPPED | DEVICE_FLAG_INITIALIZING;
|
|
|
|
//
|
|
// Initiliaze the Timer and timeout DPC used for resets, reconnects and TASK functions
|
|
//
|
|
|
|
KeInitializeDpc(
|
|
&deviceExtension->DeviceManagementTimeoutDpc,
|
|
Sbp2DeviceManagementTimeoutDpc,
|
|
deviceExtension
|
|
);
|
|
|
|
KeInitializeTimer(&deviceExtension->DeviceManagementTimer);
|
|
|
|
KeInitializeSpinLock(&deviceExtension->OrbListSpinLock);
|
|
KeInitializeSpinLock(&deviceExtension->ExtensionDataSpinLock);
|
|
|
|
KeInitializeSpinLock(&deviceExtension->StatusFifoLock);
|
|
KeInitializeSpinLock(&deviceExtension->FreeContextLock);
|
|
KeInitializeSpinLock(&deviceExtension->BusRequestLock);
|
|
|
|
ASSERT(!deviceExtension->ulPendingEvents);
|
|
ASSERT(!deviceExtension->ulInternalEventCount);
|
|
|
|
#if DBG
|
|
deviceExtension->ulPendingEvents = 0;
|
|
deviceExtension->ulInternalEventCount = 0;
|
|
#endif
|
|
|
|
//
|
|
// Initialize our device Extension ORB's, status blocks, Irp and Irb's
|
|
// Also allocate 1394 addresses for extension-held sbp2 ORB's
|
|
//
|
|
|
|
status = Sbp2InitializeDeviceExtension(deviceExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitStartDevice;
|
|
}
|
|
|
|
DEBUGPRINT2(("\nSbp2Port: StartDev: cmd set id=x%x\n", deviceExtension->DeviceInfo->CmdSetId.QuadPart));
|
|
|
|
switch (deviceExtension->DeviceInfo->CmdSetId.QuadPart) {
|
|
|
|
case 0x0:
|
|
case 0x10483:
|
|
case SCSI_COMMAND_SET_ID:
|
|
|
|
SET_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_SPC_CMD_SET);
|
|
|
|
DEBUGPRINT2(("Sbp2Port: StartDev: enabling SPC cmd set\n"));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// login
|
|
//
|
|
|
|
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DEBUGPRINT1(("\nSbp2StartDev: Login failed with %x, retrying\n",status));
|
|
|
|
if (status == STATUS_ACCESS_DENIED) {
|
|
|
|
//
|
|
// retry the login. By now we should have access since our bus reset forced a logout
|
|
//
|
|
|
|
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_QUERY_LOGINS);
|
|
}
|
|
|
|
temp = 0;
|
|
|
|
do {
|
|
|
|
//
|
|
// Give things time (one second) to settle...
|
|
//
|
|
|
|
LARGE_INTEGER waitValue;
|
|
|
|
ASSERT(InterlockedIncrement(&deviceExtension->ulPendingEvents) == 1);
|
|
|
|
KeInitializeEvent(&deviceExtension->ManagementEvent, NotificationEvent, FALSE);
|
|
|
|
waitValue.QuadPart = -1 * 1000 * 1000 * 10;
|
|
|
|
KeWaitForSingleObject(&deviceExtension->ManagementEvent,Executive,KernelMode,FALSE,&waitValue);
|
|
|
|
ASSERT(InterlockedDecrement(&deviceExtension->ulPendingEvents) == 0);
|
|
|
|
//
|
|
// all the resident 1394 memory addresses's that we have, are
|
|
// now invalidated... So we need to free them and re-allocate
|
|
// them
|
|
|
|
Sbp2CleanDeviceExtension (deviceExtension->DeviceObject,FALSE);
|
|
|
|
Sbp2InitializeDeviceExtension(deviceExtension);
|
|
|
|
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
|
|
|
|
temp ++;
|
|
|
|
//
|
|
// Note: We get STATUS_REQUEST_ABORTED rather than
|
|
// STATUS_INVALID_GENERATION at passive level,
|
|
// so check for that instead
|
|
//
|
|
|
|
} while ((status == STATUS_REQUEST_ABORTED) &&
|
|
(temp <= 3));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitStartDevice;
|
|
}
|
|
}
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
if (deviceExtension->Exclusive & EXCLUSIVE_FLAG_ENABLE) {
|
|
|
|
status = Sbp2SetPasswordTransaction(
|
|
deviceExtension,
|
|
SBP2REQ_SET_PASSWORD_EXCLUSIVE
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
deviceExtension->Exclusive = EXCLUSIVE_FLAG_SET;
|
|
|
|
} else {
|
|
|
|
deviceExtension->Exclusive = EXCLUSIVE_FLAG_CLEAR;
|
|
}
|
|
|
|
Sbp2SetExclusiveValue(
|
|
deviceExtension->DeviceObject,
|
|
&deviceExtension->Exclusive
|
|
);
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// We are ready to receive and pass down requests, init the target's
|
|
// fetch agent. The value we write to it is not important
|
|
//
|
|
|
|
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,AGENT_RESET_REG | REG_WRITE_SYNC);
|
|
|
|
//
|
|
// enable unsolicited status reg
|
|
//
|
|
|
|
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,UNSOLICITED_STATUS_REG | REG_WRITE_SYNC);
|
|
|
|
CLEAR_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_STOPPED)
|
|
);
|
|
|
|
//
|
|
// register for idle detection
|
|
//
|
|
|
|
deviceExtension->IdleCounter = PoRegisterDeviceForIdleDetection(DeviceObject,
|
|
-1,
|
|
-1,
|
|
PowerDeviceD3);
|
|
|
|
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZING );
|
|
SET_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED);
|
|
|
|
//
|
|
// OK to register for bus reset notifications now
|
|
//
|
|
|
|
if (!Sbp2EnableBusResetNotification (deviceExtension, TRUE)) {
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
|
|
CleanupOrbList (deviceExtension, STATUS_REQUEST_ABORTED);
|
|
Sbp2ManagementTransaction (deviceExtension, TRANSACTION_LOGOUT);
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exitStartDevice;
|
|
}
|
|
|
|
enabledBusResetNotification = TRUE;
|
|
|
|
|
|
if (TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_SPC_CMD_SET)) {
|
|
|
|
//
|
|
// issue an Inquiry to the target...
|
|
//
|
|
|
|
status = Sbp2IssueInternalCommand (deviceExtension,SCSIOP_INQUIRY);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: StartDev: cfgRom devType=x%x, inq devType=x%x\n",
|
|
(deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F),
|
|
deviceExtension->InquiryData.DeviceType
|
|
));
|
|
|
|
} else if ((status == STATUS_DEVICE_DOES_NOT_EXIST) ||
|
|
(status == STATUS_DEVICE_BUSY)) {
|
|
|
|
//
|
|
// In win2k if the inquiry failed we'd just turn off the
|
|
// SPC_CMD_SET flag and trundle on like nothing happened.
|
|
//
|
|
// However, we found some devices would allow logins but
|
|
// nothing else, like a powered-down mactell hd which would
|
|
// allow us to login but fail all other requests. This
|
|
// really caused problems in win9x because Ntmap would
|
|
// get loaded, but not init'd correctly, and on subsequent
|
|
// re-plugs of any device we'd see trap 14's and the like.
|
|
// So, it really makes alot more sense to just nip this
|
|
// in the bud and fail the start if we get an error back
|
|
// from the inquiry that tells us (per Sbp2ScsiRequests())
|
|
// that the device has been removed or it timed out the 1st
|
|
// inquiry . DanKn, 7 Apr 2000
|
|
//
|
|
|
|
DEBUGPRINT1((
|
|
"\nSbp2Port: StartDev: ext=x%p, fatal INQUIRY err=x%x, " \
|
|
"log out\n",
|
|
deviceExtension,
|
|
status
|
|
));
|
|
|
|
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
|
|
status = STATUS_IO_DEVICE_ERROR;
|
|
goto exitStartDevice;
|
|
|
|
} else {
|
|
|
|
CLEAR_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_SPC_CMD_SET
|
|
);
|
|
|
|
DEBUGPRINT1((
|
|
"\nSbp2Port: StartDev: ext=x%p, non-fatal INQUIRY err=x%x\n",
|
|
deviceExtension,
|
|
status
|
|
));
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (deviceExtension->InquiryData.DeviceType != (deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)){
|
|
|
|
deviceExtension->InquiryData.DeviceType = (deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F);
|
|
DEBUGPRINT1(("\nSbp2StartDev: DeviceType mismatch, using one in ConfigRom %x\n",
|
|
(deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)));
|
|
}
|
|
|
|
//
|
|
// if this is a scanner or a printer we dont need to remain logged on..
|
|
//
|
|
|
|
if ((deviceExtension->InquiryData.DeviceType == PRINTER_DEVICE) ||
|
|
(deviceExtension->InquiryData.DeviceType == SCANNER_DEVICE)){
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
SET_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
|
|
CleanupOrbList(deviceExtension,STATUS_REQUEST_ABORTED);
|
|
|
|
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
|
|
}
|
|
|
|
} else if (deviceExtension->InquiryData.DeviceType == RBC_DEVICE) {
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// retrieve the RBC device mode page
|
|
//
|
|
|
|
status = Sbp2IssueInternalCommand(deviceExtension,SCSIOP_MODE_SENSE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DEBUGPRINT1(("\nSbp2StartDev: Failed to retrieve RBC mode page\n"));
|
|
goto exitStartDevice;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
exitStartDevice:
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
ULONG errorId = __LINE__ ;
|
|
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceObject,sizeof(IO_ERROR_LOG_PACKET));
|
|
|
|
if(errorLogEntry != NULL) {
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_DRIVER_ERROR;
|
|
errorLogEntry->UniqueErrorValue = errorId;
|
|
errorLogEntry->FinalStatus = status;
|
|
errorLogEntry->DumpDataSize = 0;
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
}
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: StartDev: FAILED, status=x%x\n",
|
|
status
|
|
));
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_DEVICE_FAILED)
|
|
);
|
|
|
|
if (enabledBusResetNotification) {
|
|
|
|
Sbp2EnableBusResetNotification (deviceExtension, FALSE);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!SystemIsNT) {
|
|
|
|
DeviceObject->Flags |= DO_POWER_PAGABLE;
|
|
|
|
} else {
|
|
|
|
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
|
|
}
|
|
}
|
|
|
|
} else if (deviceExtension->Type == SBP2_FDO){
|
|
|
|
//
|
|
// Bus driver FDO start device
|
|
// retrieve parameters from the registry, if present
|
|
//
|
|
|
|
fdoExtension->MaxClassTransferSize = SBP2_MAX_TRANSFER_SIZE;
|
|
DEBUGPRINT2(("Sbp2Port: StartDev: maxXferSize=x%x\n", fdoExtension->MaxClassTransferSize ));
|
|
|
|
fdoExtension->DevicePowerState = PowerDeviceD0;
|
|
fdoExtension->SystemPowerState = PowerSystemWorking;
|
|
|
|
deviceExtension->DeviceFlags=DEVICE_FLAG_INITIALIZED;
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2PreAllocateLists(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes all the single linked workhorse lists plus lookasides. Only called from AddDevice or after
|
|
a REMOVE -> START
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension = Sbp2 driver's extension
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
ULONG cnt ;
|
|
PIRBIRP packet;
|
|
NTSTATUS status;
|
|
PADDRESS_FIFO statusFifoElement ;
|
|
PSTATUS_FIFO_BLOCK statusFifo;
|
|
PASYNC_REQUEST_CONTEXT context;
|
|
|
|
|
|
//
|
|
// initialize all interlocked lists
|
|
//
|
|
|
|
SET_FLAG(
|
|
DeviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_INITIALIZING | DEVICE_FLAG_STOPPED |
|
|
DEVICE_FLAG_PNP_STOPPED)
|
|
);
|
|
|
|
InitializeListHead(&DeviceExtension->PendingOrbList);
|
|
|
|
// BUGBUG: Some of these should be changed to lookaside lists
|
|
ExInitializeSListHead(&DeviceExtension->FreeContextListHead);
|
|
ExInitializeSListHead(&DeviceExtension->BusRequestIrpIrbListHead);
|
|
ExInitializeSListHead(&DeviceExtension->StatusFifoListHead);
|
|
|
|
// init bus request context pool
|
|
ExInitializeNPagedLookasideList( &DeviceExtension->BusRequestContextPool,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
sizeof(REQUEST_CONTEXT),
|
|
'2pbs',
|
|
0
|
|
);
|
|
|
|
KeInitializeSpinLock(&DeviceExtension->OrbListSpinLock);
|
|
KeInitializeSpinLock(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
KeInitializeSpinLock(&DeviceExtension->StatusFifoLock);
|
|
KeInitializeSpinLock(&DeviceExtension->FreeContextLock);
|
|
KeInitializeSpinLock(&DeviceExtension->BusRequestLock);
|
|
|
|
|
|
//
|
|
// alloc the irb/irp and context slists
|
|
//
|
|
|
|
for (cnt = 0; cnt < MAX_ORB_LIST_DEPTH; cnt++) {
|
|
|
|
packet = ExAllocatePoolWithTag (NonPagedPool,sizeof(IRBIRP),'2pbs');
|
|
|
|
if (!packet) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
packet->Irb = ExAllocatePoolWithTag (NonPagedPool,sizeof(IRB),'2pbs');
|
|
|
|
if (!packet->Irb) {
|
|
|
|
ExFreePool(packet);
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
packet->Irp = IoAllocateIrp (DeviceExtension->LowerDeviceObject->StackSize,FALSE);
|
|
|
|
if (!packet->Irp) {
|
|
|
|
ExFreePool(packet->Irb);
|
|
ExFreePool(packet);
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
ExInterlockedPushEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
|
|
&packet->ListPointer,
|
|
&DeviceExtension->BusRequestLock);
|
|
}
|
|
|
|
//
|
|
// status FIFO list
|
|
//
|
|
|
|
cnt = (sizeof(ADDRESS_FIFO)+sizeof(STATUS_FIFO_BLOCK))*NUM_PREALLOCATED_STATUS_FIFO_ELEMENTS;
|
|
|
|
DeviceExtension->StatusFifoBase = \
|
|
(PASYNC_REQUEST_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,cnt,'2pbs');
|
|
|
|
if (DeviceExtension->StatusFifoBase == NULL) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
for (cnt = 0; cnt < (NUM_PREALLOCATED_STATUS_FIFO_ELEMENTS - 1); cnt++) {
|
|
|
|
statusFifoElement = (PADDRESS_FIFO) ((PUCHAR)DeviceExtension->StatusFifoBase + \
|
|
cnt * (sizeof(ADDRESS_FIFO)+sizeof(STATUS_FIFO_BLOCK)));
|
|
|
|
statusFifo = (PSTATUS_FIFO_BLOCK) ((PUCHAR)statusFifoElement + sizeof(ADDRESS_FIFO));
|
|
|
|
//
|
|
// make Mdl for this status fifo Element
|
|
//
|
|
|
|
statusFifoElement->FifoMdl = IoAllocateMdl(statusFifo,sizeof(STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
|
|
|
|
if (statusFifoElement->FifoMdl == NULL) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool (statusFifoElement->FifoMdl);
|
|
|
|
ExInterlockedPushEntrySList(&DeviceExtension->StatusFifoListHead,
|
|
&statusFifoElement->FifoList,
|
|
&DeviceExtension->StatusFifoLock);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the async request contexts (including page tables)
|
|
//
|
|
|
|
cnt = sizeof (ASYNC_REQUEST_CONTEXT) * MAX_ORB_LIST_DEPTH;
|
|
|
|
DeviceExtension->AsyncContextBase = (PASYNC_REQUEST_CONTEXT)
|
|
ExAllocatePoolWithTag (NonPagedPool, cnt, '2pbs');
|
|
|
|
if (DeviceExtension->AsyncContextBase == NULL) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
RtlZeroMemory (DeviceExtension->AsyncContextBase, cnt);
|
|
|
|
AllocateIrpAndIrb (DeviceExtension, &packet);
|
|
|
|
if (!packet) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
for (cnt = 0; cnt < MAX_ORB_LIST_DEPTH; cnt++) {
|
|
|
|
context = DeviceExtension->AsyncContextBase + cnt;
|
|
|
|
context->Tag = SBP2_ASYNC_CONTEXT_TAG;
|
|
|
|
//
|
|
// Initialize the timeout DPC and timer
|
|
//
|
|
|
|
KeInitializeDpc(
|
|
&context->TimerDpc,
|
|
Sbp2RequestTimeoutDpc,
|
|
DeviceExtension
|
|
);
|
|
|
|
KeInitializeTimer (&context->Timer);
|
|
|
|
|
|
//
|
|
// Alloc and/or map a page table
|
|
//
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
|
|
|
|
packet->Irb->u.AllocateAddressRange.nLength = PAGE_SIZE;
|
|
packet->Irb->u.AllocateAddressRange.fulNotificationOptions =
|
|
NOTIFY_FLAGS_NEVER;
|
|
packet->Irb->u.AllocateAddressRange.fulAccessType =
|
|
ACCESS_FLAGS_TYPE_READ;
|
|
|
|
packet->Irb->u.AllocateAddressRange.fulFlags =
|
|
ALLOCATE_ADDRESS_FLAGS_USE_COMMON_BUFFER;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback = NULL;
|
|
packet->Irb->u.AllocateAddressRange.Context = NULL;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
|
|
|
|
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
|
|
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
|
|
|
|
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
|
|
packet->Irb->u.AllocateAddressRange.DeviceExtension = DeviceExtension;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Mdl =
|
|
context->PageTableContext.AddressContext.RequestMdl;
|
|
|
|
packet->Irb->u.AllocateAddressRange.MaxSegmentSize =
|
|
(SBP2_MAX_DIRECT_BUFFER_SIZE) / 2;
|
|
|
|
packet->Irb->u.AllocateAddressRange.p1394AddressRange =(PADDRESS_RANGE)
|
|
&context->PageTableContext.AddressContext.Address;
|
|
|
|
status = Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DeAllocateIrpAndIrb (DeviceExtension, packet);
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
|
|
//
|
|
// Common buffer allocations get an mdl *back* from the
|
|
// bus/port driver, need to retrieve a corresponding VA
|
|
//
|
|
|
|
context->PageTableContext.AddressContext.RequestMdl =
|
|
packet->Irb->u.AllocateAddressRange.Mdl;
|
|
|
|
context->PageTableContext.PageTable = MmGetMdlVirtualAddress(
|
|
packet->Irb->u.AllocateAddressRange.Mdl
|
|
);
|
|
|
|
context->PageTableContext.AddressContext.AddressHandle =
|
|
packet->Irb->u.AllocateAddressRange.hAddressRange;
|
|
context->PageTableContext.AddressContext.Address.BusAddress.NodeId =
|
|
DeviceExtension->InitiatorAddressId;
|
|
|
|
context->PageTableContext.MaxPages = SBP2_NUM_PAGE_TABLE_ENTRIES;
|
|
|
|
|
|
//
|
|
// add this context to the linked list
|
|
//
|
|
|
|
ExInterlockedPushEntrySList(
|
|
&DeviceExtension->FreeContextListHead,
|
|
&context->LookasideList,
|
|
&DeviceExtension->FreeContextLock
|
|
);
|
|
}
|
|
|
|
DeAllocateIrpAndIrb (DeviceExtension, packet);
|
|
|
|
|
|
//
|
|
// initialize the mdl used for quadlet requests to the port driver..
|
|
//
|
|
|
|
DeviceExtension->ReservedMdl = IoAllocateMdl(
|
|
&DeviceExtension->Reserved,
|
|
sizeof(QUADLET),
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if (!DeviceExtension->ReservedMdl) {
|
|
|
|
goto Sbp2PreAllocateLists_error;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool (DeviceExtension->ReservedMdl);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
Sbp2PreAllocateLists_error:
|
|
|
|
Sbp2CleanDeviceExtension (DeviceExtension->DeviceObject, TRUE);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2InitializeDeviceExtension(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes all the data structures in our device extension, allocates appropriate 1394 addresses and workhorse
|
|
Irps. It also creates a FreeList with pre-allocated contexts and command ORBs.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension = Sbp2 driver's extension
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
KIRQL cIrql;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
|
|
PASYNC_REQUEST_CONTEXT context, oldContext;
|
|
|
|
|
|
|
|
if (DeviceExtension->DeviceFlags & DEVICE_FLAG_REMOVED) {
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
InitializeListHead(&DeviceExtension->PendingOrbList);
|
|
|
|
DeviceExtension->NextContextToFree = NULL;
|
|
|
|
DeviceExtension->OrbListDepth = 0;
|
|
DeviceExtension->CurrentKey = 0;
|
|
|
|
//
|
|
// Get information volatile between bus resets
|
|
//
|
|
|
|
status = Sbp2UpdateNodeInformation (DeviceExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
|
|
|
|
//
|
|
// get 1394 data transfer information
|
|
//
|
|
|
|
status = Sbp2GetControllerInfo (DeviceExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// allocate a status block for the task ORB and a Management ORB
|
|
//
|
|
|
|
if (DeviceExtension->TaskOrbStatusContext.AddressHandle == NULL) {
|
|
|
|
status = AllocateAddressForStatus(deviceObject,
|
|
&DeviceExtension->TaskOrbStatusContext,
|
|
TASK_STATUS_BLOCK);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
}
|
|
|
|
if (DeviceExtension->ManagementOrbStatusContext.AddressHandle == NULL) {
|
|
|
|
status = AllocateAddressForStatus(deviceObject,
|
|
&DeviceExtension->ManagementOrbStatusContext,
|
|
MANAGEMENT_STATUS_BLOCK);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
}
|
|
|
|
if (DeviceExtension->GlobalStatusContext.AddressHandle == NULL) {
|
|
|
|
//
|
|
// setup the status FIFO list with the bus driver
|
|
//
|
|
|
|
status = AllocateAddressForStatus(deviceObject,
|
|
&DeviceExtension->GlobalStatusContext,
|
|
CMD_ORB_STATUS_BLOCK);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
}
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
if (DeviceExtension->PasswordOrbStatusContext.AddressHandle == NULL) {
|
|
|
|
status = AllocateAddressForStatus( deviceObject,
|
|
&DeviceExtension->PasswordOrbStatusContext,
|
|
PASSWORD_STATUS_BLOCK
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
}
|
|
|
|
DeviceExtension->PasswordOrbContext.DeviceObject = deviceObject;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Allocate a dummy,task, management ORBs and a login response ,which are going to be reused through out the drivers life...
|
|
//
|
|
|
|
DeviceExtension->TaskOrbContext.DeviceObject = deviceObject;
|
|
DeviceExtension->ManagementOrbContext.DeviceObject = deviceObject;
|
|
DeviceExtension->LoginRespContext.DeviceObject = deviceObject;
|
|
DeviceExtension->QueryLoginRespContext.DeviceObject = deviceObject;
|
|
|
|
KeInitializeEvent(&DeviceExtension->ManagementEvent,SynchronizationEvent, FALSE);
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
// kevent for password orb context
|
|
KeInitializeEvent(
|
|
&DeviceExtension->PasswordEvent,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
#endif
|
|
|
|
if (DeviceExtension->CommonBufferContext.AddressHandle == NULL) {
|
|
|
|
status = AllocateSingle1394Address(
|
|
deviceObject,
|
|
NULL,
|
|
sizeof (*DeviceExtension->CommonBuffer),
|
|
ACCESS_FLAGS_TYPE_READ | ACCESS_FLAGS_TYPE_WRITE,
|
|
&DeviceExtension->CommonBufferContext
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
|
|
(PVOID) DeviceExtension->CommonBuffer =
|
|
DeviceExtension->CommonBufferContext.Reserved;
|
|
|
|
|
|
DeviceExtension->TaskOrb = &DeviceExtension->CommonBuffer->TaskOrb;
|
|
|
|
DeviceExtension->TaskOrbContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
|
|
DeviceExtension->ManagementOrb =
|
|
&DeviceExtension->CommonBuffer->ManagementOrb;
|
|
|
|
DeviceExtension->ManagementOrbContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
DeviceExtension->ManagementOrbContext.Address.BusAddress.Off_Low +=
|
|
(ULONG) ((PUCHAR) DeviceExtension->ManagementOrb -
|
|
(PUCHAR) DeviceExtension->CommonBuffer);
|
|
|
|
|
|
DeviceExtension->LoginResponse =
|
|
&DeviceExtension->CommonBuffer->LoginResponse;
|
|
|
|
DeviceExtension->LoginRespContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
DeviceExtension->LoginRespContext.Address.BusAddress.Off_Low +=
|
|
(ULONG) ((PUCHAR) DeviceExtension->LoginResponse -
|
|
(PUCHAR) DeviceExtension->CommonBuffer);
|
|
|
|
|
|
DeviceExtension->QueryLoginResponse =
|
|
&DeviceExtension->CommonBuffer->QueryLoginResponse;
|
|
|
|
DeviceExtension->QueryLoginRespContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
DeviceExtension->QueryLoginRespContext.Address.BusAddress.Off_Low +=
|
|
(ULONG) ((PUCHAR) DeviceExtension->QueryLoginResponse -
|
|
(PUCHAR) DeviceExtension->CommonBuffer);
|
|
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
DeviceExtension->PasswordOrb =
|
|
&DeviceExtension->CommonBuffer->PasswordOrb;
|
|
|
|
DeviceExtension->PasswordOrbContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
DeviceExtension->PasswordOrbContext.Address.BusAddress.Off_Low +=
|
|
(ULONG) ((PUCHAR) DeviceExtension->PasswordOrb -
|
|
(PUCHAR) DeviceExtension->CommonBuffer);
|
|
|
|
#endif
|
|
|
|
DeviceExtension->OrbPoolContext.Reserved =
|
|
DeviceExtension->CommonBuffer->CmdOrbs;
|
|
|
|
DeviceExtension->OrbPoolContext.Address.BusAddress =
|
|
DeviceExtension->CommonBufferContext.Address.BusAddress;
|
|
|
|
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_Low +=
|
|
(ULONG) ((PUCHAR) DeviceExtension->OrbPoolContext.Reserved -
|
|
(PUCHAR) DeviceExtension->CommonBuffer);
|
|
|
|
|
|
KeAcquireSpinLock (&DeviceExtension->OrbListSpinLock, &cIrql);
|
|
|
|
//
|
|
// Initialize our pool of contexts
|
|
//
|
|
|
|
for (i = 0, context = NULL; i < MAX_ORB_LIST_DEPTH; i++) {
|
|
|
|
//
|
|
// Mark this unused context as completed so if we had to
|
|
// free our freelist now (because we got a remove) we wouldn't
|
|
// try to complete its request
|
|
//
|
|
|
|
oldContext = context;
|
|
|
|
context = (PVOID) ExInterlockedPopEntrySList (&DeviceExtension->FreeContextListHead,
|
|
&DeviceExtension->FreeContextLock);
|
|
|
|
context = RETRIEVE_CONTEXT (context,LookasideList);
|
|
|
|
context->Flags |= ASYNC_CONTEXT_FLAG_COMPLETED;
|
|
|
|
//
|
|
// Create a linked list so we push all the entries later
|
|
//
|
|
|
|
context->OrbList.Blink = (PLIST_ENTRY) oldContext;
|
|
|
|
//
|
|
// Each command ORB gets a small piece of our continuous pool
|
|
// mapped into the 1394 memory space. The sizeof(PVOID) bytes
|
|
// before the cmdorb buffer are the pointer to its context.
|
|
//
|
|
|
|
context->CmdOrb = &DeviceExtension->CommonBuffer->CmdOrbs[i].Orb;
|
|
|
|
DeviceExtension->CommonBuffer->CmdOrbs[i].AsyncReqCtx = context;
|
|
|
|
context->CmdOrbAddress.BusAddress.Off_Low = \
|
|
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_Low +
|
|
(i * sizeof (ARCP_ORB)) + FIELD_OFFSET (ARCP_ORB, Orb);
|
|
|
|
context->CmdOrbAddress.BusAddress.Off_High = \
|
|
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_High;
|
|
|
|
context->CmdOrbAddress.BusAddress.NodeId = \
|
|
DeviceExtension->InitiatorAddressId;
|
|
}
|
|
|
|
//
|
|
// re-create the free list
|
|
//
|
|
|
|
while (context) {
|
|
|
|
oldContext = context;
|
|
|
|
ExInterlockedPushEntrySList(&DeviceExtension->FreeContextListHead,
|
|
&context->LookasideList,
|
|
&DeviceExtension->FreeContextLock);
|
|
|
|
context = (PASYNC_REQUEST_CONTEXT) oldContext->OrbList.Blink;
|
|
|
|
oldContext->OrbList.Blink = NULL;
|
|
}
|
|
|
|
|
|
KeReleaseSpinLock (&DeviceExtension->OrbListSpinLock,cIrql);
|
|
}
|
|
|
|
//
|
|
// Update the NodeId portion of the page table addr for each
|
|
// ASYNC_REQUEST_CONTEXT and for the login/queryLogin responses
|
|
//
|
|
|
|
for (i = 0; i < MAX_ORB_LIST_DEPTH; i++) {
|
|
|
|
context = DeviceExtension->AsyncContextBase + i;
|
|
|
|
context->PageTableContext.AddressContext.Address.BusAddress.NodeId =
|
|
DeviceExtension->InitiatorAddressId;
|
|
}
|
|
|
|
DeviceExtension->LoginRespContext.Address.BusAddress.NodeId =
|
|
DeviceExtension->InitiatorAddressId;
|
|
|
|
DeviceExtension->QueryLoginRespContext.Address.BusAddress.NodeId =
|
|
DeviceExtension->InitiatorAddressId;
|
|
|
|
|
|
//
|
|
// Finally, allocate a dummy addr that we can easily free & realloc
|
|
// to re-enable phyical addr filters after bus resets
|
|
//
|
|
|
|
if (DeviceExtension->DummyContext.AddressHandle == NULL) {
|
|
|
|
status = AllocateSingle1394Address(
|
|
deviceObject,
|
|
&DeviceExtension->Dummy,
|
|
sizeof(DeviceExtension->Dummy),
|
|
ACCESS_FLAGS_TYPE_READ | ACCESS_FLAGS_TYPE_WRITE,
|
|
&DeviceExtension->DummyContext
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto exitInit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Done
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: InitDevExt: ext=x%p\n", DeviceExtension));
|
|
|
|
exitInit:
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Sbp2CleanDeviceExtension(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
BOOLEAN FreeLists
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when we get a remove, so it will free all used pool and all the resident Irps.
|
|
It wil also free our FreeList of contexts and any complete any pending IO requests
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension = Sbp2 driver's extension
|
|
FreeLists - TRUE means we cleanup EVERYTHING including our lookaside lists
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PFDO_DEVICE_EXTENSION fdoExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
KIRQL cIrql;
|
|
PADDRESS_FIFO statusFifoElement;
|
|
ULONG i;
|
|
BOOLEAN valid = FALSE;
|
|
PIRBIRP packet;
|
|
|
|
//
|
|
// there are two types of cleanups. One for the PDO and one for the FDO(alot simpler)
|
|
//
|
|
|
|
if (deviceExtension->Type == SBP2_PDO) {
|
|
|
|
//
|
|
// make sure that this PDO is something in our list and that we have NOT deleted
|
|
// it already....
|
|
//
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
|
|
|
|
if (fdoExtension->DeviceList[i].DeviceObject == DeviceObject) {
|
|
|
|
valid = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!valid) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED) ){
|
|
|
|
//
|
|
// stop the timer for any pending management requests
|
|
//
|
|
|
|
KeCancelTimer (&deviceExtension->DeviceManagementTimer);
|
|
|
|
//
|
|
// We have a list of requests pending, clean it up
|
|
// The reset/logout has automatically made the target to discard any requests
|
|
//
|
|
|
|
CleanupOrbList (deviceExtension, STATUS_REQUEST_ABORTED);
|
|
}
|
|
|
|
//
|
|
// after a bus reset we must reallocate at least one physical address to allow
|
|
// the ohci driver to re-enable the physical address filters
|
|
//
|
|
|
|
if (deviceExtension->DummyContext.AddressHandle != NULL) {
|
|
|
|
FreeAddressRange (deviceExtension,&deviceExtension->DummyContext);
|
|
}
|
|
|
|
if (FreeLists){
|
|
|
|
if (TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_INITIALIZED) ||
|
|
TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_INITIALIZING)){
|
|
|
|
FreeAddressRange(deviceExtension,&deviceExtension->TaskOrbStatusContext);
|
|
FreeAddressRange(deviceExtension,&deviceExtension->GlobalStatusContext);
|
|
#if PASSWORD_SUPPORT
|
|
FreeAddressRange(deviceExtension,&deviceExtension->PasswordOrbStatusContext);
|
|
#endif
|
|
FreeAddressRange(deviceExtension,&deviceExtension->ManagementOrbStatusContext);
|
|
|
|
if (deviceExtension->PowerDeferredIrp) {
|
|
|
|
deviceExtension->PowerDeferredIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest (deviceExtension->PowerDeferredIrp, IO_NO_INCREMENT);
|
|
deviceExtension->PowerDeferredIrp = NULL;
|
|
}
|
|
|
|
if (deviceExtension->DeferredPowerRequest) {
|
|
|
|
deviceExtension->DeferredPowerRequest->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest(deviceExtension->DeferredPowerRequest, IO_NO_INCREMENT);
|
|
deviceExtension->DeferredPowerRequest = NULL;
|
|
}
|
|
|
|
if (deviceExtension->UniSymLinkName.Buffer) {
|
|
|
|
IoDeleteSymbolicLink(&deviceExtension->UniSymLinkName);
|
|
RtlFreeUnicodeString(&deviceExtension->UniSymLinkName);
|
|
deviceExtension->UniSymLinkName.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// before we go any further, check if the device is physically removed
|
|
//
|
|
|
|
if (!TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED)) {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Cleanup: ext=x%p, not freeing ALL wkg sets, dev present\n", deviceExtension));
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Cleanup: ext=x%p, freeing ALL wkg sets\n", deviceExtension));
|
|
}
|
|
|
|
CLEAR_FLAG(deviceExtension->DeviceFlags, (DEVICE_FLAG_INITIALIZED | DEVICE_FLAG_INITIALIZING));
|
|
|
|
//
|
|
// OK to free common buffer if device is going away
|
|
//
|
|
|
|
FreeAddressRange(deviceExtension,&deviceExtension->CommonBufferContext);
|
|
|
|
deviceExtension->OrbPoolContext.Reserved = NULL;
|
|
|
|
//
|
|
// Free all the page tables & async context buffer
|
|
//
|
|
|
|
if (deviceExtension->AsyncContextBase != NULL) {
|
|
|
|
for (i = 0; i < MAX_ORB_LIST_DEPTH; i++) {
|
|
|
|
PASYNC_REQUEST_CONTEXT context;
|
|
|
|
|
|
context = deviceExtension->AsyncContextBase + i;
|
|
|
|
if (context->PageTableContext.PageTable != NULL) {
|
|
|
|
//
|
|
// Common buffer, we didn't alloc the mdl,
|
|
// so zero the field to prevent our free'ing it
|
|
//
|
|
|
|
context->PageTableContext.AddressContext.
|
|
RequestMdl = NULL;
|
|
|
|
FreeAddressRange(
|
|
deviceExtension,
|
|
&context->PageTableContext.AddressContext
|
|
);
|
|
}
|
|
}
|
|
|
|
ExFreePool (deviceExtension->AsyncContextBase);
|
|
deviceExtension->AsyncContextBase = NULL;
|
|
}
|
|
|
|
//
|
|
// free pool for status fifo list
|
|
//
|
|
|
|
if (deviceExtension->StatusFifoBase !=NULL ) {
|
|
|
|
statusFifoElement = (PVOID) ExInterlockedPopEntrySList (&deviceExtension->StatusFifoListHead,
|
|
&deviceExtension->StatusFifoLock);
|
|
while (statusFifoElement){
|
|
|
|
DEBUGPRINT3(("Sbp2Port: Cleanup: freeing statusFifo=x%p, fifoBase=x%p\n",
|
|
statusFifoElement,deviceExtension->StatusFifoBase));
|
|
|
|
IoFreeMdl (statusFifoElement->FifoMdl);
|
|
statusFifoElement = (PVOID) ExInterlockedPopEntrySList (&deviceExtension->StatusFifoListHead,
|
|
&deviceExtension->StatusFifoLock);
|
|
};
|
|
|
|
ExFreePool (deviceExtension->StatusFifoBase);
|
|
deviceExtension->StatusFifoBase = NULL;
|
|
}
|
|
|
|
//
|
|
// free the irb/irp and context slists
|
|
//
|
|
|
|
packet = (PIRBIRP) ExInterlockedPopEntrySList (&deviceExtension->BusRequestIrpIrbListHead,
|
|
&deviceExtension->BusRequestLock);
|
|
while (packet) {
|
|
|
|
ExFreePool(packet->Irb);
|
|
|
|
if (packet->Irp->Type == IO_TYPE_IRP) {
|
|
|
|
IoFreeIrp(packet->Irp);
|
|
}
|
|
|
|
ExFreePool(packet);
|
|
|
|
packet = (PIRBIRP) ExInterlockedPopEntrySList (&deviceExtension->BusRequestIrpIrbListHead,
|
|
&deviceExtension->BusRequestLock);
|
|
};
|
|
|
|
|
|
// delete our bus request context lookaside list
|
|
ExDeleteNPagedLookasideList(&deviceExtension->BusRequestContextPool);
|
|
|
|
if (deviceExtension->ReservedMdl) {
|
|
|
|
IoFreeMdl (deviceExtension->ReservedMdl);
|
|
deviceExtension->ReservedMdl = NULL;
|
|
}
|
|
|
|
// free the vendor id
|
|
if (deviceExtension->DeviceInfo->uniVendorId.Buffer) {
|
|
|
|
ExFreePool(deviceExtension->DeviceInfo->uniVendorId.Buffer);
|
|
deviceExtension->DeviceInfo->uniVendorId.Length = 0;
|
|
deviceExtension->DeviceInfo->uniVendorId.Buffer = NULL;
|
|
}
|
|
|
|
// free the model id
|
|
if (deviceExtension->DeviceInfo->uniModelId.Buffer) {
|
|
|
|
ExFreePool(deviceExtension->DeviceInfo->uniModelId.Buffer);
|
|
deviceExtension->DeviceInfo->uniModelId.Length = 0;
|
|
deviceExtension->DeviceInfo->uniModelId.Buffer = NULL;
|
|
}
|
|
|
|
// free the generic name
|
|
if (deviceExtension->DeviceInfo->uniGenericName.Buffer) {
|
|
|
|
ExFreePool(deviceExtension->DeviceInfo->uniGenericName.Buffer);
|
|
deviceExtension->DeviceInfo->uniGenericName.Length = 0;
|
|
deviceExtension->DeviceInfo->uniGenericName.Buffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension;
|
|
|
|
if (fdoExtension->Sbp2ObjectDirectory != NULL) {
|
|
|
|
ZwMakeTemporaryObject (fdoExtension->Sbp2ObjectDirectory);
|
|
ZwClose (fdoExtension->Sbp2ObjectDirectory);
|
|
fdoExtension->Sbp2ObjectDirectory = NULL;
|
|
}
|
|
|
|
if (TEST_FLAG(fdoExtension->DeviceFlags,DEVICE_FLAG_REMOVED)) {
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
SET_FLAG (fdoExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
|
|
}
|
|
|
|
if (fdoExtension->DeviceListSize != 0) {
|
|
|
|
//
|
|
// Disable bus reset notifications
|
|
//
|
|
|
|
AllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, &packet);
|
|
|
|
if (packet) {
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
|
|
packet->Irb->Flags = 0;
|
|
packet->Irb->u.BusResetNotification.fulFlags =
|
|
DEREGISTER_NOTIFICATION_ROUTINE;
|
|
|
|
Sbp2SendRequest(
|
|
(PDEVICE_EXTENSION) fdoExtension,
|
|
packet,
|
|
SYNC_1394_REQUEST
|
|
);
|
|
|
|
DeAllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, packet);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up any remaining PDO's
|
|
//
|
|
|
|
KeAcquireSpinLock (&fdoExtension->DeviceListLock,&cIrql);
|
|
|
|
for (; fdoExtension->DeviceListSize > 0; fdoExtension->DeviceListSize--) {
|
|
|
|
i = fdoExtension->DeviceListSize - 1;
|
|
|
|
if (fdoExtension->DeviceList[i].DeviceObject) {
|
|
|
|
deviceExtension =
|
|
fdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
|
|
|
|
DeviceObject = fdoExtension->DeviceList[i].DeviceObject;
|
|
|
|
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
|
|
|
|
if (Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
|
|
|
|
//
|
|
// Acquire the pdo's remove lock, start the queue
|
|
// cleanup, and and wait for io to complete. Then
|
|
// delete the device & continue.
|
|
//
|
|
|
|
IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
|
|
|
|
Sbp2StartNextPacketByKey (DeviceObject, 0);
|
|
|
|
KeLowerIrql (cIrql);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: CleanDevExt: walking fdo, wait for " \
|
|
"io compl pdo=x%p...\n",
|
|
DeviceObject
|
|
));
|
|
|
|
IoReleaseRemoveLockAndWait(
|
|
&deviceExtension->RemoveLock,
|
|
NULL
|
|
);
|
|
|
|
deviceExtension->Type = SBP2_PDO_DELETED;
|
|
|
|
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
|
|
|
|
IoDeleteDevice (DeviceObject);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: CleanDevExt: ............ io compl," \
|
|
" deleted pdo=x%p\n",
|
|
DeviceObject
|
|
));
|
|
|
|
KeAcquireSpinLock (&fdoExtension->DeviceListLock, &cIrql);
|
|
|
|
fdoExtension->DeviceList[i].DeviceObject = NULL;
|
|
|
|
} else {
|
|
|
|
KeAcquireSpinLock (&fdoExtension->DeviceListLock, &cIrql);
|
|
}
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[i].uniVendorId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniVendorId.Buffer);
|
|
fdoExtension->DeviceList[i].uniVendorId.Length = 0;
|
|
fdoExtension->DeviceList[i].uniVendorId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[i].uniModelId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniModelId.Buffer);
|
|
fdoExtension->DeviceList[i].uniModelId.Length = 0;
|
|
fdoExtension->DeviceList[i].uniModelId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[i].uniGenericName.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniGenericName.Buffer);
|
|
fdoExtension->DeviceList[i].uniGenericName.Length = 0;
|
|
fdoExtension->DeviceList[i].uniGenericName.Buffer = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2Unload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does nothing really...
|
|
|
|
Arguments:
|
|
|
|
DriverObject - the driver being unloaded
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
DEBUGPRINT1(("Sbp2Port: unloading\n\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2DeviceManagementTimeoutDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
{
|
|
ULONG i;
|
|
PDEVICE_EXTENSION pdoExtension;
|
|
PFDO_DEVICE_EXTENSION fdoExtension;
|
|
|
|
|
|
if (Dpc != &DeviceExtension->DeviceManagementTimeoutDpc) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED)) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RECONNECT)) {
|
|
|
|
//
|
|
// The flag indicates that a bus reset occured, and a reconnect never happened...
|
|
// OR that the device is realy hose so we reset it and we need to re-login
|
|
//
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: RECONNECT timeout, Ext=x%p, Flags=x%x, doing re-login\n",
|
|
DeviceExtension,
|
|
DeviceExtension->DeviceFlags
|
|
));
|
|
|
|
//
|
|
// all the resident 1394 memory addresses's that we have, are
|
|
// now invalidated... So we need to free them and re-allocate
|
|
// them
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
CLEAR_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RECONNECT);
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
//
|
|
// If device is marked STOPPED then a target reset was
|
|
// done and that affected all LUNs (spec sect 10.4.4).
|
|
// So if this is a multilun device try logins on each
|
|
// pdo as appropriate.
|
|
//
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION)
|
|
DeviceExtension->BusFdo->DeviceExtension;
|
|
|
|
if ((fdoExtension->DeviceListSize > 1) &&
|
|
|
|
TEST_FLAG (DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
|
|
|
|
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
|
|
|
|
pdoExtension = (PDEVICE_EXTENSION)
|
|
fdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
|
|
|
|
if (pdoExtension->DeviceObject ==
|
|
DeviceExtension->DeviceObject) {
|
|
|
|
// No need to update node info since no bus reset done
|
|
|
|
Sbp2ManagementTransaction(
|
|
pdoExtension,
|
|
TRANSACTION_LOGIN
|
|
);
|
|
|
|
continue;
|
|
}
|
|
|
|
KeAcquireSpinLockAtDpcLevel(
|
|
&pdoExtension->ExtensionDataSpinLock
|
|
);
|
|
|
|
if (TEST_FLAG(
|
|
pdoExtension->DeviceFlags,
|
|
DEVICE_FLAG_INITIALIZED
|
|
) &&
|
|
|
|
!TEST_FLAG(
|
|
pdoExtension->DeviceFlags,
|
|
DEVICE_FLAG_STOPPED | DEVICE_FLAG_RESET_IN_PROGRESS |
|
|
DEVICE_FLAG_REMOVED | DEVICE_FLAG_LOGIN_IN_PROGRESS |
|
|
DEVICE_FLAG_RECONNECT | DEVICE_FLAG_DEVICE_FAILED |
|
|
DEVICE_FLAG_SURPRISE_REMOVED
|
|
)) {
|
|
|
|
SET_FLAG(
|
|
pdoExtension->DeviceFlags,
|
|
(DEVICE_FLAG_STOPPED | DEVICE_FLAG_RESET_IN_PROGRESS)
|
|
);
|
|
|
|
KeReleaseSpinLockFromDpcLevel(
|
|
&pdoExtension->ExtensionDataSpinLock
|
|
);
|
|
|
|
CleanupOrbList (pdoExtension, STATUS_REQUEST_ABORTED);
|
|
|
|
// No need to update node info since no bus reset done
|
|
|
|
Sbp2ManagementTransaction(
|
|
pdoExtension,
|
|
TRANSACTION_LOGIN
|
|
);
|
|
|
|
} else {
|
|
|
|
KeReleaseSpinLockFromDpcLevel(
|
|
&pdoExtension->ExtensionDataSpinLock
|
|
);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
Sbp2UpdateNodeInformation (DeviceExtension);
|
|
Sbp2ManagementTransaction (DeviceExtension, TRANSACTION_LOGIN);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_LOGIN_IN_PROGRESS)) {
|
|
|
|
ULONG flags;
|
|
|
|
|
|
//
|
|
// the asynchronous login attempt timed out. This is bad news and means the
|
|
// device is not responding
|
|
//
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
flags = DeviceExtension->DeviceFlags;
|
|
|
|
CLEAR_FLAG(DeviceExtension->DeviceFlags,(DEVICE_FLAG_LOGIN_IN_PROGRESS | DEVICE_FLAG_RESET_IN_PROGRESS));
|
|
SET_FLAG(DeviceExtension->DeviceFlags, (DEVICE_FLAG_STOPPED | DEVICE_FLAG_DEVICE_FAILED));
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
//
|
|
// check if we had a power irp deferred.. If we did call startio to abort it..
|
|
//
|
|
|
|
if (DeviceExtension->DeferredPowerRequest) {
|
|
|
|
Sbp2StartIo(DeviceExtension->DeviceObject,DeviceExtension->DeferredPowerRequest);
|
|
DeviceExtension->DeferredPowerRequest = NULL;
|
|
}
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: LOGIN timeout, Ext=x%p, Flags=x%x, device stopped\n",
|
|
DeviceExtension,
|
|
flags
|
|
));
|
|
|
|
Sbp2StartNextPacketByKey (DeviceExtension->DeviceObject, 0);
|
|
|
|
IoInvalidateDeviceState(DeviceExtension->DeviceObject);
|
|
return;
|
|
}
|
|
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_RESET_IN_PROGRESS)) {
|
|
|
|
//
|
|
// the reset attempt has timed out
|
|
//
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: RESET timeout, Ext=x%p, Flags=x%x, ",
|
|
DeviceExtension,
|
|
DeviceExtension->DeviceFlags
|
|
));
|
|
|
|
if (!TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
|
|
|
|
//
|
|
// Second level of recovery, do a TARGET_RESET task function
|
|
//
|
|
|
|
DEBUGPRINT1(("doing target reset\n"));
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
SET_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
|
|
DeviceExtension->MaxOrbListDepth = max(MIN_ORB_LIST_DEPTH,DeviceExtension->MaxOrbListDepth/2);
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
CleanupOrbList(DeviceExtension,STATUS_REQUEST_ABORTED);
|
|
|
|
//
|
|
// we are close to timing out a reset, try a hard reset
|
|
//
|
|
|
|
Sbp2Reset (DeviceExtension->DeviceObject, TRUE);
|
|
return;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Third level of recovery. Do a hardware node reset
|
|
//
|
|
|
|
DEBUGPRINT1(("doing CMD_RESET and relogin.\n"));
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
|
|
DeviceExtension->Reserved = 0;
|
|
SET_FLAG(DeviceExtension->DeviceFlags, (DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT | DEVICE_FLAG_STOPPED));
|
|
|
|
DeviceExtension->DueTime.HighPart = -1;
|
|
DeviceExtension->DueTime.LowPart = SBP2_RELOGIN_DELAY;
|
|
KeSetTimer(&DeviceExtension->DeviceManagementTimer,DeviceExtension->DueTime, &DeviceExtension->DeviceManagementTimeoutDpc);
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
|
|
Sbp2AccessRegister(DeviceExtension,&DeviceExtension->Reserved,CORE_RESET_REG | REG_WRITE_ASYNC);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2RequestTimeoutDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Our Device object
|
|
Context - DeviceExtension
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIRP requestIrp = NULL;
|
|
PASYNC_REQUEST_CONTEXT current = NULL;
|
|
PASYNC_REQUEST_CONTEXT next = NULL;
|
|
LARGE_INTEGER Time;
|
|
|
|
#if DBG
|
|
|
|
ULONG xferLen;
|
|
UCHAR cdb[6];
|
|
|
|
#endif
|
|
|
|
//
|
|
// return if device is stopped, but since reset can occur while device is stopped
|
|
// thats why this check is ater the reset timing code
|
|
//
|
|
|
|
if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
|
|
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// search the linked list of contexts, to see which guy timed out
|
|
//
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->OrbListSpinLock);
|
|
|
|
next = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Flink,OrbList);
|
|
|
|
// see if the last status has the suspended state bit set...
|
|
if ((DeviceExtension->LastStatusBlock.AddressAndStatus.u.HighQuad.u.HighPart & STATUS_BLOCK_ENDOFLIST_BIT_MASK) &&
|
|
(next->Flags & ASYNC_CONTEXT_FLAG_TIMER_STARTED) &&
|
|
!(next->Flags & ASYNC_CONTEXT_FLAG_RANG_DOORBELL)) {
|
|
|
|
TRACE(TL_1394_INFO, ("GC: Pending Orb - Ring Doorbell."));
|
|
|
|
// set the flag...
|
|
SET_FLAG(next->Flags, ASYNC_CONTEXT_FLAG_RANG_DOORBELL);
|
|
|
|
Time.QuadPart = (-5*10*1000*1000); // 5 seconds
|
|
KeSetTimer(&next->Timer, Time, &next->TimerDpc);
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
|
|
|
|
// reset the timer to track this request...
|
|
// we still have a pending orb, but the device thinks its done.
|
|
// ring the doorbell...
|
|
Sbp2AccessRegister( DeviceExtension,
|
|
&DeviceExtension->Reserved,
|
|
DOORBELL_REG | REG_WRITE_ASYNC
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if (next->Flags & ASYNC_CONTEXT_FLAG_RANG_DOORBELL) {
|
|
|
|
CLEAR_FLAG(next->Flags, ASYNC_CONTEXT_FLAG_RANG_DOORBELL);
|
|
TRACE(TL_1394_INFO, ("Rang Doorbell - didn't work."));
|
|
}
|
|
|
|
do {
|
|
|
|
current = next;
|
|
if ((¤t->TimerDpc == Dpc) && (current->Flags & ASYNC_CONTEXT_FLAG_TIMER_STARTED)) {
|
|
|
|
if (TEST_FLAG(current->Flags,ASYNC_CONTEXT_FLAG_COMPLETED)) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: ReqTimeoutDpc: timeout, but req already compl!!\n" ));
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// this is the timed out request
|
|
// do an abort Task Set
|
|
//
|
|
|
|
CLEAR_FLAG(current->Flags,ASYNC_CONTEXT_FLAG_TIMER_STARTED);
|
|
|
|
KeCancelTimer(¤t->Timer);
|
|
|
|
#if DBG
|
|
xferLen = current->Srb->DataTransferLength;
|
|
cdb[0] = current->Srb->Cdb[0];
|
|
cdb[1] = current->Srb->Cdb[1];
|
|
cdb[2] = current->Srb->Cdb[2];
|
|
cdb[3] = current->Srb->Cdb[3];
|
|
cdb[4] = current->Srb->Cdb[4];
|
|
cdb[5] = current->Srb->Cdb[5];
|
|
#endif
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
|
|
|
|
Sbp2CreateRequestErrorLog(DeviceExtension->DeviceObject,current,STATUS_TIMEOUT);
|
|
|
|
if (!TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RESET_IN_PROGRESS)){
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: ReqTimeoutDpc: cdb=x%02x %02x %02x %02x %02x " \
|
|
"%02x, len=x%x\n",
|
|
cdb[0],
|
|
cdb[1],
|
|
cdb[2],
|
|
cdb[3],
|
|
cdb[4],
|
|
cdb[5],
|
|
xferLen
|
|
));
|
|
|
|
Sbp2Reset (DeviceExtension->DeviceObject, FALSE);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
next = (PASYNC_REQUEST_CONTEXT) current->OrbList.Flink;
|
|
|
|
} while ( current != RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Blink,OrbList));
|
|
|
|
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2Reset(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
BOOLEAN HardReset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to implement SBP2 high level recovery mechanisms. It will issue an ABORT_TASK_SET if HardReset == FALSE
|
|
otherswise it will issue a RESET_TARGET. Its all done asynchronously and out timer DPC will track the requests
|
|
to check if they timed out...
|
|
|
|
Arguments:
|
|
|
|
DeviceObject= Sbp2 driver's device object
|
|
HardReset = Type of recovery to perform, TRUE is a target reset, FALSE is an abort task set
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
KIRQL oldIrql;
|
|
NTSTATUS status;
|
|
#if DBG
|
|
ULONG generation;
|
|
#endif
|
|
|
|
|
|
if ((deviceExtension->DeviceFlags & DEVICE_FLAG_REMOVED) ||
|
|
(deviceExtension->DeviceFlags & DEVICE_FLAG_RECONNECT)) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (HardReset == TRUE) {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Reset: ext=x%p, do target reset\n", deviceExtension ));
|
|
|
|
//
|
|
// Do a target reset
|
|
//
|
|
|
|
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&oldIrql);
|
|
|
|
deviceExtension->TaskOrbContext.TransactionType = TRANSACTION_TARGET_RESET;
|
|
deviceExtension->TaskOrb->OrbInfo.QuadPart = 0;
|
|
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= ORB_NOTIFY_BIT_MASK;
|
|
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= 0x00FF & TRANSACTION_TARGET_RESET;
|
|
|
|
deviceExtension->TaskOrb->OrbInfo.u.LowPart =
|
|
deviceExtension->LoginResponse->LengthAndLoginId.u.LowPart; // LOGIN ID
|
|
|
|
deviceExtension->TaskOrb->StatusBlockAddress.BusAddress =
|
|
deviceExtension->TaskOrbStatusContext.Address.BusAddress;
|
|
|
|
//
|
|
// endian conversion
|
|
//
|
|
|
|
octbswap (deviceExtension->TaskOrb->StatusBlockAddress);
|
|
|
|
deviceExtension->TaskOrb->OrbInfo.QuadPart =
|
|
bswap(deviceExtension->TaskOrb->OrbInfo.QuadPart);
|
|
|
|
//
|
|
// send the task ORB , mark start of reset/abort
|
|
//
|
|
|
|
deviceExtension->DeviceFlags |= DEVICE_FLAG_RESET_IN_PROGRESS;
|
|
|
|
//
|
|
// now set the timer to track this request
|
|
//
|
|
|
|
deviceExtension->DueTime.HighPart = -1;
|
|
deviceExtension->DueTime.LowPart = SBP2_HARD_RESET_TIMEOUT;
|
|
KeSetTimer(&deviceExtension->DeviceManagementTimer,deviceExtension->DueTime,&deviceExtension->DeviceManagementTimeoutDpc);
|
|
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
|
|
|
|
status = Sbp2AccessRegister(deviceExtension, &deviceExtension->TaskOrbContext.Address, MANAGEMENT_AGENT_REG | REG_WRITE_ASYNC);
|
|
|
|
if (status == STATUS_INVALID_GENERATION) {
|
|
|
|
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
|
|
#if DBG
|
|
//
|
|
// Check to see if perhaps we didn't get the reset
|
|
// notification we were expecting
|
|
//
|
|
|
|
generation = deviceExtension->CurrentGeneration;
|
|
|
|
status = Sbp2UpdateNodeInformation (deviceExtension);
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Reset: target reset error, sts=x%x, extGen=x%x, " \
|
|
"curGen=x%x\n",
|
|
status,
|
|
generation,
|
|
deviceExtension->CurrentGeneration
|
|
));
|
|
#endif
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&oldIrql);
|
|
|
|
SET_FLAG(deviceExtension->DeviceFlags, (DEVICE_FLAG_STOPPED | DEVICE_FLAG_DEVICE_FAILED));
|
|
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
|
|
|
|
//
|
|
// check if we had a power irp deferred.. If we did call startio to abort it..
|
|
//
|
|
|
|
if (deviceExtension->DeferredPowerRequest) {
|
|
|
|
Sbp2StartIo(deviceExtension->DeviceObject,deviceExtension->DeferredPowerRequest);
|
|
deviceExtension->DeferredPowerRequest = NULL;
|
|
}
|
|
|
|
Sbp2StartNextPacketByKey (deviceExtension->DeviceObject, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Reset: ext=x%p, do abort task set\n", deviceExtension ));
|
|
|
|
//
|
|
// Do an abort task set
|
|
//
|
|
|
|
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&oldIrql);
|
|
|
|
deviceExtension->TaskOrbContext.TransactionType = TRANSACTION_ABORT_TASK_SET;
|
|
deviceExtension->TaskOrb->OrbInfo.QuadPart = 0;
|
|
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= ORB_NOTIFY_BIT_MASK;
|
|
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= 0x00FF & TRANSACTION_ABORT_TASK_SET;
|
|
|
|
deviceExtension->TaskOrb->OrbInfo.u.LowPart =
|
|
deviceExtension->LoginResponse->LengthAndLoginId.u.LowPart; // LOGIN ID
|
|
|
|
deviceExtension->TaskOrb->StatusBlockAddress.BusAddress =
|
|
deviceExtension->TaskOrbStatusContext.Address.BusAddress;
|
|
|
|
//
|
|
// endian conversion
|
|
//
|
|
|
|
octbswap (deviceExtension->TaskOrb->StatusBlockAddress);
|
|
|
|
deviceExtension->TaskOrb->OrbInfo.QuadPart =
|
|
bswap (deviceExtension->TaskOrb->OrbInfo.QuadPart);
|
|
|
|
//
|
|
// send the task ORB , mark start of reset/abort
|
|
//
|
|
|
|
deviceExtension->DeviceFlags |= DEVICE_FLAG_RESET_IN_PROGRESS;
|
|
|
|
//
|
|
// now set the timer to track this request
|
|
//
|
|
|
|
deviceExtension->DueTime.HighPart = -1;
|
|
deviceExtension->DueTime.LowPart = SBP2_RESET_TIMEOUT;
|
|
KeSetTimer(&deviceExtension->DeviceManagementTimer,deviceExtension->DueTime,&deviceExtension->DeviceManagementTimeoutDpc);
|
|
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
|
|
|
|
Sbp2AccessRegister(deviceExtension, &deviceExtension->TaskOrbContext.Address, MANAGEMENT_AGENT_REG | REG_WRITE_ASYNC);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2DeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the device control dispatcher.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject
|
|
Irp
|
|
|
|
Return Value:
|
|
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
ULONG requiredSize;
|
|
|
|
if (deviceExtension->Type == SBP2_PDO) {
|
|
|
|
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
case IOCTL_STORAGE_QUERY_PROPERTY: {
|
|
//
|
|
// Validate the query
|
|
//
|
|
|
|
PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(STORAGE_PROPERTY_QUERY)) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
status = Sbp2QueryProperty(DeviceObject, Irp);
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
|
|
status = Sbp2_ScsiPassThrough(DeviceObject, Irp, FALSE);
|
|
break;
|
|
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
|
|
status = Sbp2_ScsiPassThrough(DeviceObject, Irp, TRUE);
|
|
break;
|
|
|
|
case IOCTL_SBP2_REQUEST:
|
|
|
|
status = Sbp2HandleApiRequest(deviceExtension, Irp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DEBUGPRINT3(("Sbp2Port: Sbp2DeviceControl: Irp Not Handled.\n" ));
|
|
status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Status =status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Status =status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2HandleApiRequest(
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSBP2_REQUEST sbp2Req;
|
|
NTSTATUS status;
|
|
|
|
|
|
status = IoAcquireRemoveLock (&DeviceExtension->RemoveLock, NULL);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
if (Irp->RequestorMode == KernelMode) {
|
|
|
|
sbp2Req = irpStack->Parameters.Others.Argument1;
|
|
|
|
} else { // UserMode
|
|
|
|
sbp2Req = Irp->AssociatedIrp.SystemBuffer;
|
|
}
|
|
|
|
if (sbp2Req == NULL) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: HandleApiReq: Invalid sbp2Req!"));
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto Exit_Sbp2HandleApiRequest;
|
|
}
|
|
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
switch (sbp2Req->RequestNumber) {
|
|
|
|
case SBP2_REQUEST_RETRIEVE_TEXT_LEAFS:
|
|
|
|
//
|
|
// Only allow kernel-mode requests of this type, since the
|
|
// RetrieveTextLeaf definition currently has us passing
|
|
// back a buf alloc'd via ExAllocPool - not something we
|
|
// want to hand back to user-mode.
|
|
//
|
|
|
|
if (Irp->RequestorMode == KernelMode) {
|
|
|
|
status = Sbp2Get1394ConfigInfo(
|
|
(PFDO_DEVICE_EXTENSION)
|
|
DeviceExtension->BusFdo->DeviceExtension,
|
|
sbp2Req
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
case SBP2_REQUEST_SET_PASSWORD:
|
|
|
|
if (sbp2Req->u.SetPassword.fulFlags == SBP2REQ_SET_PASSWORD_CLEAR) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: Setting Password to Clear\n"));
|
|
|
|
status = Sbp2SetPasswordTransaction(
|
|
DeviceExtension,
|
|
SBP2REQ_SET_PASSWORD_CLEAR
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DeviceExtension->Exclusive = EXCLUSIVE_FLAG_CLEAR;
|
|
}
|
|
|
|
} else if (sbp2Req->u.SetPassword.fulFlags ==
|
|
SBP2REQ_SET_PASSWORD_EXCLUSIVE) {
|
|
|
|
DEBUGPRINT1 (("Sbp2Port: HandleApiReq: set passwd to excl\n"));
|
|
|
|
status = Sbp2SetPasswordTransaction(
|
|
DeviceExtension,
|
|
SBP2REQ_SET_PASSWORD_EXCLUSIVE
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DeviceExtension->Exclusive = EXCLUSIVE_FLAG_SET;
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: HandleApiReq: set passwd, inval fl=x%x\n",
|
|
sbp2Req->u.SetPassword.fulFlags
|
|
));
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto Exit_Sbp2HandleApiRequest;
|
|
}
|
|
|
|
Sbp2SetExclusiveValue(
|
|
DeviceExtension->DeviceObject,
|
|
&DeviceExtension->Exclusive
|
|
);
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: HandleApiReq: set passwd sts=x%x\n",
|
|
status
|
|
));
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Exit_Sbp2HandleApiRequest:
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2CreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
create and close routine. This is called by the I/O system
|
|
when the device is opened or closed. The sbp2 driver will do login and logout on
|
|
create/close respectively
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object for this miniport
|
|
|
|
Irp - IRP involved.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
if (deviceExtension->Type == SBP2_PDO) {
|
|
|
|
if ((deviceExtension->InquiryData.DeviceType == PRINTER_DEVICE) ||
|
|
(deviceExtension->InquiryData.DeviceType == SCANNER_DEVICE)){
|
|
|
|
if (!(deviceExtension->DeviceFlags & DEVICE_FLAG_INITIALIZING)) {
|
|
|
|
status = IoAcquireRemoveLock(
|
|
&deviceExtension->RemoveLock,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
goto Sbp2CreateClose_CompleteReq;
|
|
}
|
|
|
|
switch (irpStack->MajorFunction) {
|
|
|
|
case IRP_MJ_CREATE:
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: OPEN_REQUEST, handle cound %d.\n", deviceExtension->HandleCount));
|
|
|
|
if (deviceExtension->DeviceFlags & DEVICE_FLAG_STOPPED) {
|
|
|
|
//
|
|
// do a login.
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: LOGIN.\n" ));
|
|
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
//
|
|
// make retry limit high for busy transactions
|
|
//
|
|
|
|
deviceExtension->Reserved = BUSY_TIMEOUT_SETTING;
|
|
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,CORE_BUSY_TIMEOUT_REG | REG_WRITE_SYNC);
|
|
|
|
//
|
|
// We are ready to receive and pass down requests, init the target's
|
|
// fetch agent.
|
|
//
|
|
|
|
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,AGENT_RESET_REG | REG_WRITE_ASYNC);
|
|
|
|
deviceExtension->DeviceFlags &= ~DEVICE_FLAG_STOPPED;
|
|
|
|
InterlockedIncrement(&deviceExtension->HandleCount);
|
|
}
|
|
|
|
} else {
|
|
|
|
InterlockedIncrement(&deviceExtension->HandleCount);
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
|
|
if (deviceExtension->HandleCount) {
|
|
|
|
InterlockedDecrement(&deviceExtension->HandleCount);
|
|
}
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: CLOSE_REQUEST, handle cound %d.\n", deviceExtension->HandleCount));
|
|
|
|
if (!(deviceExtension->DeviceFlags & (DEVICE_FLAG_REMOVED | DEVICE_FLAG_STOPPED)) &&
|
|
!deviceExtension->HandleCount) {
|
|
|
|
//
|
|
// Logout
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: LOGIN OUT.\n" ));
|
|
|
|
deviceExtension->DeviceFlags |= DEVICE_FLAG_STOPPED;
|
|
|
|
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
|
|
|
|
CleanupOrbList(deviceExtension,STATUS_REQUEST_ABORTED);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
}
|
|
} // device type check
|
|
|
|
} else if (deviceExtension->Type != SBP2_FDO) {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
Sbp2CreateClose_CompleteReq:
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, 0);
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2PnpDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the PNP requests (primarily for PDO's)
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies a pointer to the device object for this request.
|
|
|
|
Irp - Supplies the Irp making the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
KIRQL cIrql;
|
|
PULONG count;
|
|
NTSTATUS status;
|
|
UNICODE_STRING unicodeIdString;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
PFDO_DEVICE_EXTENSION fdoExtension;
|
|
|
|
#if DBG
|
|
|
|
const char * minorFuncs[] =
|
|
{
|
|
"START_DEV, ",
|
|
"QUERY_REMOVE_DEV, ",
|
|
"REMOVE_DEV, ",
|
|
"CANCEL_REMOVE_DEV, ",
|
|
"STOP_DEV, ",
|
|
"QUERY_STOP_DEV, ",
|
|
"CANCEL_STOP_DEV, ",
|
|
"QUERY_DEV_RELATIONS, ",
|
|
"QUERY_INTERFACE, ",
|
|
"QUERY_CAPABILITIES, ",
|
|
"QUERY_RESOURCES, ",
|
|
"QUERY_RESOURCE_REQS, ",
|
|
"QUERY_DEV_TEXT, ",
|
|
"FILTER_RESOURCE_REQS,",
|
|
"??, ", // 0xd (14)
|
|
"READ_CFG, ",
|
|
"WRITE_CFG, ",
|
|
"EJECT, ",
|
|
"SET_LOCK, ",
|
|
"QUERY_ID, ",
|
|
"QUERY_PNP_DEV_STATE, ",
|
|
"QUERY_BUS_INFO, ",
|
|
"DEV_USAGE_NOTIF, ",
|
|
"SURPRISE_REMOVAL, ",
|
|
"QUERY_LEG_BUS_INFO, " // 0x18
|
|
};
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Pnp: [x%02x] %s %sdoX=x%p, fl=x%x\n",
|
|
irpStack->MinorFunction,
|
|
(irpStack->MinorFunction <= 0x18 ?
|
|
minorFuncs[irpStack->MinorFunction] : minorFuncs[14]),
|
|
(deviceExtension->Type == SBP2_PDO ? "p" :
|
|
(deviceExtension->Type == SBP2_FDO ? "f" : "???")),
|
|
deviceExtension,
|
|
deviceExtension->DeviceFlags
|
|
));
|
|
|
|
#endif
|
|
|
|
//
|
|
// We may receive an IRP_MN_BUS_RESET before our AddDevice
|
|
// has completed. Check to make sure our DeviceObject is
|
|
// initialized before we allow processing of PNP Irps.
|
|
//
|
|
if (DeviceObject->Flags & DO_DEVICE_INITIALIZING) {
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return(STATUS_NO_SUCH_DEVICE);
|
|
}
|
|
|
|
switch (deviceExtension->Type) {
|
|
|
|
case SBP2_PDO:
|
|
|
|
break;
|
|
|
|
case SBP2_FDO:
|
|
|
|
return Sbp2FDOPnpDeviceControl (DeviceObject, Irp);
|
|
|
|
default:
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
|
|
DEBUGPRINT3((
|
|
"Sbp2Port: Pnp: ... Type = %x\n",
|
|
irpStack->Parameters.QueryDeviceRelations.Type
|
|
));
|
|
|
|
//
|
|
// Fill in the DeviceRelations array with this PDO,
|
|
// reference it, and return.
|
|
//
|
|
|
|
if (irpStack->Parameters.QueryDeviceRelations.Type !=
|
|
TargetDeviceRelation) {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
break;
|
|
}
|
|
|
|
if (Irp->IoStatus.Information) {
|
|
|
|
deviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
|
|
|
|
} else {
|
|
|
|
deviceRelations = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof (*deviceRelations)
|
|
);
|
|
|
|
if (!deviceRelations) {
|
|
|
|
Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
deviceRelations->Count = 0;
|
|
}
|
|
|
|
deviceRelations->Objects[deviceRelations->Count] = DeviceObject;
|
|
deviceRelations->Count++;
|
|
|
|
ObReferenceObject (DeviceObject);
|
|
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
{
|
|
PDEVICE_INFORMATION DeviceInfo = deviceExtension->DeviceInfo;
|
|
UNICODE_STRING uniRetString;
|
|
|
|
// assume success
|
|
status = STATUS_SUCCESS;
|
|
|
|
if ((irpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) ||
|
|
(irpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation)) {
|
|
|
|
status = Sbp2_BuildDeviceText( irpStack->Parameters.QueryDeviceText.DeviceTextType,
|
|
DeviceInfo,
|
|
&uniRetString
|
|
);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)uniRetString.Buffer;
|
|
TRACE(TL_PNP_INFO, ("DeviceText = %ws", uniRetString.Buffer));
|
|
}
|
|
else {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID:
|
|
{
|
|
PDEVICE_INFORMATION DeviceInfo = deviceExtension->DeviceInfo;
|
|
UNICODE_STRING uniRetString;
|
|
|
|
TRACE(TL_PNP_TRACE, ("PDO: IRP_MN_QUERY_ID"));
|
|
|
|
// assume success
|
|
status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR)NULL;
|
|
|
|
switch (irpStack->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryDeviceID:
|
|
TRACE(TL_PNP_TRACE, ("BusQueryDeviceID"));
|
|
|
|
// build our DeviceId
|
|
status = Sbp2_BuildDeviceId(DeviceInfo, &uniRetString);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to build DeviceId! = 0x%x", status));
|
|
}
|
|
else {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)uniRetString.Buffer;
|
|
TRACE(TL_PNP_TRACE, ("DeviceID = %ws", uniRetString.Buffer));
|
|
}
|
|
break; // BusQueryDeviceID
|
|
|
|
case BusQueryHardwareIDs:
|
|
TRACE(TL_PNP_TRACE, ("BusQueryHardwareIDs"));
|
|
|
|
// build our HardwareIds
|
|
status = Sbp2_BuildHardwareIds(DeviceInfo, &uniRetString);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to build HardwareIds! = 0x%x", status));
|
|
}
|
|
else {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)uniRetString.Buffer;
|
|
TRACE(TL_PNP_TRACE, ("HardwareIds = %ws", uniRetString.Buffer));
|
|
}
|
|
break; // BusQueryHardwareIDs
|
|
|
|
case BusQueryCompatibleIDs:
|
|
TRACE(TL_PNP_TRACE, ("BusQueryCompatibleIDs"));
|
|
|
|
// build our CompatIds
|
|
status = Sbp2_BuildCompatIds(DeviceInfo, &uniRetString);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
TRACE(TL_1394_ERROR, ("Failed to build CompatIds! = 0x%x", status));
|
|
}
|
|
else {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)uniRetString.Buffer;
|
|
TRACE(TL_PNP_TRACE, ("CompatIds = %ws", uniRetString.Buffer));
|
|
}
|
|
break; // BusQueryCompatibleIDs
|
|
|
|
case BusQueryInstanceID:
|
|
|
|
// if (BusExtension->Tag == BUS_DEVICE_TAG) {
|
|
|
|
TRACE(TL_PNP_TRACE, ("BusQueryInstanceID"));
|
|
|
|
// build our InstanceId
|
|
status = Sbp2_BuildInstanceId(DeviceInfo, &uniRetString);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
TRACE(TL_1394_ERROR, ("Failed to build InstanceId! = 0x%x", status));
|
|
}
|
|
else {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)uniRetString.Buffer;
|
|
TRACE(TL_PNP_TRACE, ("InstanceID = %ws", uniRetString.Buffer));
|
|
}
|
|
// }
|
|
// else {
|
|
//
|
|
// // let 1394bus deal with it...
|
|
// IoSkipCurrentIrpStackLocation(Irp);
|
|
// status = IoCallDriver(BusExtension->ParentDeviceObject, Irp);
|
|
// return(status); // default
|
|
// }
|
|
break; // BusQueryCompatibleIDs
|
|
|
|
default:
|
|
TRACE(TL_PNP_WARNING, ("Unsupported IRP_MN_QUERY_ID"));
|
|
|
|
// set status to avoid changing the current IoStatus
|
|
status = Irp->IoStatus.Status;
|
|
break; // default
|
|
} // switch
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
break; // IRP_MN_QUERY_ID
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
|
|
deviceCapabilities =
|
|
irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
//
|
|
// Settings consistent across all 1394 devices
|
|
//
|
|
|
|
deviceCapabilities->Removable = TRUE;
|
|
deviceCapabilities->UniqueID = TRUE;
|
|
deviceCapabilities->SilentInstall = TRUE;
|
|
|
|
//
|
|
// Settings for different types of devices. We are very
|
|
// familar with SCSI-variant devices and can make some
|
|
// good choices here, but for other devices we'll leave
|
|
// these choices up to the higher-level driver(s).
|
|
//
|
|
|
|
switch (deviceExtension->DeviceInfo->CmdSetId.QuadPart) {
|
|
|
|
case 0x10483:
|
|
case SCSI_COMMAND_SET_ID:
|
|
|
|
switch ((deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)) {
|
|
|
|
case PRINTER_DEVICE:
|
|
case SCANNER_DEVICE:
|
|
|
|
deviceCapabilities->RawDeviceOK = FALSE;
|
|
deviceCapabilities->SurpriseRemovalOK = TRUE;
|
|
break;
|
|
|
|
default:
|
|
|
|
deviceCapabilities->RawDeviceOK = TRUE;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
|
|
deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
|
|
deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
|
|
deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
|
|
deviceCapabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
|
|
deviceCapabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
|
|
|
|
deviceCapabilities->SystemWake = PowerSystemUnspecified;
|
|
deviceCapabilities->DeviceWake = PowerDeviceUnspecified;
|
|
deviceCapabilities->D1Latency = 1 * (1000 * 10); // 1 sec
|
|
deviceCapabilities->D2Latency = 1 * (1000 * 10); // 1
|
|
deviceCapabilities->D3Latency = 1 * (1000 * 10); // 1
|
|
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
break;
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
|
|
status = Sbp2StartDevice (DeviceObject);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
|
|
//
|
|
// Disable bus reset notifications
|
|
//
|
|
|
|
Sbp2EnableBusResetNotification (deviceExtension, FALSE);
|
|
|
|
|
|
//
|
|
// disable idle detection
|
|
//
|
|
|
|
PoRegisterDeviceForIdleDetection (DeviceObject, 0L, 0L, PowerDeviceD3);
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
|
|
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock, &cIrql);
|
|
|
|
if (!TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_STOPPED)
|
|
);
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION)
|
|
deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
ASSERT(!fdoExtension->ulWorkItemCount);
|
|
|
|
ExAcquireFastMutex(&fdoExtension->ResetMutex);
|
|
Sbp2ManagementTransaction (deviceExtension,TRANSACTION_LOGOUT);
|
|
ExReleaseFastMutex(&fdoExtension->ResetMutex);
|
|
|
|
Sbp2CleanDeviceExtension (DeviceObject,FALSE);
|
|
|
|
} else {
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_PNP_STOPPED);
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
}
|
|
|
|
Irp->IoStatus.Status = status = STATUS_SUCCESS;
|
|
|
|
ASSERT(!deviceExtension->ulPendingEvents);
|
|
ASSERT(!deviceExtension->ulInternalEventCount);
|
|
break;
|
|
|
|
case IRP_MN_BUS_RESET:
|
|
|
|
//
|
|
// Start of a PHY reset. We will re-connect asynchronously to the
|
|
// target when our callback is called, so this is ignored..
|
|
//
|
|
// After a bus reset is complete, the bus driver should call our
|
|
// BusResetNotification callback. When it does, we will attempt
|
|
// to reconnect. If the reconnect completion status callback,
|
|
// never fires, it means the following things:
|
|
//
|
|
// 1) The device never completed the RECONNECT, or
|
|
// 2) The device completed the reconnect but because our
|
|
// controlller was BUSY or hosed we didnt get it
|
|
//
|
|
// If 1 or 2 happens, the timeout DPC queued in our bus reset
|
|
// notification, should fire and attempt a relogin...
|
|
//
|
|
|
|
Irp->IoStatus.Status = status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
|
|
if (TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_DEVICE_FAILED)
|
|
) &&
|
|
|
|
!TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_RESET_IN_PROGRESS
|
|
)){
|
|
|
|
//
|
|
// Set DEVICE_FLAG_REPORTED_FAILED so the SURPRISE_REMOVE
|
|
// handler knows it didn't get called because of physical
|
|
// hardware removal
|
|
//
|
|
|
|
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_REPORTED_FAILED
|
|
);
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
|
|
//
|
|
// indicate our device is disabled due to a failure..
|
|
//
|
|
|
|
Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Pnp: QUERY_DEVICE_STATE, device FAILED!!!\n"
|
|
));
|
|
}
|
|
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
|
|
|
|
switch (irpStack->Parameters.UsageNotification.Type) {
|
|
|
|
case DeviceUsageTypePaging:
|
|
|
|
count = &deviceExtension->PagingPathCount;
|
|
break;
|
|
|
|
case DeviceUsageTypeHibernation:
|
|
|
|
count = &deviceExtension->HibernateCount;
|
|
break;
|
|
|
|
default:
|
|
|
|
count = NULL;
|
|
break;
|
|
}
|
|
|
|
if (count) {
|
|
|
|
//
|
|
// Send the irp down to see what everyone else thinks
|
|
//
|
|
|
|
status = Sbp2ForwardIrpSynchronous(deviceExtension->LowerDeviceObject, Irp);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
IoAdjustPagingPathCount(count, irpStack->Parameters.UsageNotification.InPath);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
break;
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
|
|
if (deviceExtension->PagingPathCount ||
|
|
deviceExtension->HibernateCount ||
|
|
deviceExtension->CrashDumpCount) {
|
|
|
|
status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
SET_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVE_PENDING);
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVE_PENDING);
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
|
|
|
|
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_PNP_STOPPED);
|
|
|
|
if (TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_SURPRISE_REMOVED
|
|
)) {
|
|
|
|
//
|
|
// We already cleaned up in SURPRISE_REMOVAL handler.
|
|
// Empty out the queue, wait for io to complete, then
|
|
// delete the device, complete the request, & return.
|
|
//
|
|
|
|
KeReleaseSpinLock(
|
|
&deviceExtension->ExtensionDataSpinLock,
|
|
cIrql
|
|
);
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
|
|
|
|
Sbp2StartNextPacketByKey (DeviceObject, 0);
|
|
|
|
KeLowerIrql (cIrql);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Pnp: wait for io compl pdo=x%p...\n",
|
|
DeviceObject
|
|
));
|
|
|
|
IoReleaseRemoveLockAndWait (&deviceExtension->RemoveLock, NULL);
|
|
|
|
deviceExtension->Type = SBP2_PDO_DELETED;
|
|
|
|
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
|
|
|
|
IoDeleteDevice (DeviceObject);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Pnp: ......... deleted pdo=x%p\n", DeviceObject
|
|
));
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
if (TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_REMOVE_PENDING
|
|
)) {
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
|
|
//
|
|
// If device is initialized & MgmtOrbCtx event is still around
|
|
// then do a log out
|
|
//
|
|
|
|
if (TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_INITIALIZED
|
|
)) {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Pnp: LOG OUT, since QUERY preceded RMV\n"
|
|
));
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION)
|
|
deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
ExAcquireFastMutex(&fdoExtension->ResetMutex);
|
|
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
|
|
ExReleaseFastMutex(&fdoExtension->ResetMutex);
|
|
}
|
|
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
|
|
CLEAR_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_REMOVE_PENDING
|
|
);
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
|
|
|
|
} else if (!TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_DEVICE_FAILED)
|
|
)){
|
|
|
|
//
|
|
// If no query has preceded and NO SUPRISE_REMOVAL has preceded
|
|
// this means we are running under win98, where physical device
|
|
// removals are only indicated by only MN_REMOVES being sent,
|
|
// with no QUERY_REMOVE prior to the remove.
|
|
//
|
|
|
|
if (deviceExtension->DeviceFlags ==
|
|
(DEVICE_FLAG_INITIALIZING | DEVICE_FLAG_STOPPED) &&
|
|
!SystemIsNT) {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Pnp: 9x REMOVE, don't delete dev\n"
|
|
));
|
|
|
|
deviceExtension->DeviceFlags =
|
|
DEVICE_FLAG_UNSTARTED_AND_REMOVED;
|
|
|
|
} else {
|
|
|
|
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
|
|
|
|
CLEAR_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT |
|
|
DEVICE_FLAG_LOGIN_IN_PROGRESS
|
|
);
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Pnp: Suprise removal, since QUERY " \
|
|
"did not precede REMOVE.\n"
|
|
));
|
|
}
|
|
}
|
|
|
|
CLEAR_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_CLAIMED);
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
|
|
if (!Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: Pnp: Double remove\n"));
|
|
}
|
|
|
|
//
|
|
// In all cases other than surprise removals, pdo's will get
|
|
// deleted by the fdo remove handler
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
break;
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL: {
|
|
|
|
//
|
|
// If device was reported failed (due to async login failure &
|
|
// IoInvalidateDeviceState) then just set REMOVED & PNP_STOPPED
|
|
// flags and clean up the device extension - we don't want to
|
|
// delete the pdo at this point.
|
|
//
|
|
// Otherwise, assume physical device removal occured, in which
|
|
// case we need to do our own cleanup & teardown right here
|
|
// because the dev stack will start disintegrating.
|
|
//
|
|
// ISSUE: Per AdriaO, another case where we can get a
|
|
// SURPRISE_REMOVAL is if a START fails *after* a STOP
|
|
// - at any point in this pdo's stack! Not sure how to
|
|
// tell whether or not this is the case if it's not
|
|
// SBP2PORT that failed the START, so leaving that case
|
|
// as is for now. DanKn, 04-Jun-2001
|
|
//
|
|
|
|
BOOLEAN reportedMissing;
|
|
|
|
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock, &cIrql);
|
|
|
|
if (TEST_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_REPORTED_FAILED
|
|
)) {
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_PNP_STOPPED)
|
|
);
|
|
|
|
reportedMissing = FALSE;
|
|
|
|
} else {
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_SURPRISE_REMOVED |
|
|
DEVICE_FLAG_PNP_STOPPED)
|
|
);
|
|
|
|
reportedMissing = TRUE;
|
|
}
|
|
|
|
CLEAR_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
(DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT |
|
|
DEVICE_FLAG_LOGIN_IN_PROGRESS | DEVICE_FLAG_REPORTED_FAILED)
|
|
);
|
|
|
|
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
|
|
|
|
Sbp2CleanDeviceExtension (DeviceObject, TRUE);
|
|
|
|
if (reportedMissing) {
|
|
|
|
Sbp2HandleRemove (DeviceObject);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
|
|
//
|
|
// PnP walks up the device tree looking for the FILE_CHAR flags,
|
|
// and stops when it finds a node marked Removable. Since our pdo's
|
|
// are marked Removable, PnP won't make it to a BUS1394 PDO, so we
|
|
// need to propagate the FILE_CHAR flags here.
|
|
//
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION)
|
|
deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
DeviceObject->Characteristics |=
|
|
(FILE_CHARACTERISTICS_REMOVAL_POLICY_MASK &
|
|
fdoExtension->Pdo->Characteristics);
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This is the bottom of the stack, complete the request
|
|
//
|
|
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2FDOPnpDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the PNP requests for FDO's
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies a pointer to the device object for this request.
|
|
|
|
Irp - Supplies the Irp making the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = IoAcquireRemoveLock(&fdoExtension->RemoveLock, NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
|
|
DEBUGPRINT3((
|
|
"Sbp2Port: Pnp: ... Type = %x\n",
|
|
irpStack->Parameters.QueryDeviceRelations.Type
|
|
));
|
|
|
|
if (irpStack->Parameters.QueryDeviceRelations.Type != BusRelations) {
|
|
|
|
break;
|
|
}
|
|
|
|
deviceRelations = ExAllocatePool(
|
|
PagedPool,
|
|
sizeof (*deviceRelations) +
|
|
(SBP2_MAX_LUNS_PER_NODE * sizeof (PDEVICE_OBJECT))
|
|
);
|
|
|
|
if (!deviceRelations) {
|
|
|
|
DEBUGPRINT1 (("Sbp2Port: Pnp: devRels alloc failed!!\n"));
|
|
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return (STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
status = Sbp2CreateDeviceRelations (fdoExtension, deviceRelations);
|
|
Irp->IoStatus.Status = status;
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
|
|
deviceCapabilities =
|
|
irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
deviceCapabilities->SurpriseRemovalOK = TRUE;
|
|
|
|
break;
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
|
|
KeInitializeEvent (&event, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
Sbp2FdoRequestCompletionRoutine,
|
|
(PVOID) &event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
|
|
|
|
if(!NT_SUCCESS(Irp->IoStatus.Status) && (status != STATUS_PENDING)) {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
} else {
|
|
|
|
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
status = Sbp2StartDevice (DeviceObject);
|
|
}
|
|
|
|
IoReleaseRemoveLock(&fdoExtension->RemoveLock, NULL);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
|
|
KeInitializeEvent (&event, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
Sbp2FdoRequestCompletionRoutine,
|
|
(PVOID) &event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
|
|
|
|
if (!NT_SUCCESS (Irp->IoStatus.Status) && status != STATUS_PENDING) {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
} else {
|
|
|
|
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
//
|
|
// do FDO cleanup..
|
|
//
|
|
|
|
IoReleaseRemoveLockAndWait(&fdoExtension->RemoveLock, NULL);
|
|
|
|
if (Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
|
|
|
|
ASSERT(!fdoExtension->ulBusResetMutexCount);
|
|
ASSERT(!fdoExtension->ulWorkItemCount);
|
|
|
|
IoDetachDevice (fdoExtension->LowerDeviceObject);
|
|
IoDeleteDevice (DeviceObject);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
|
|
Irp->IoStatus.Information |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
IoReleaseRemoveLock(&fdoExtension->RemoveLock, NULL);
|
|
|
|
//
|
|
// Pass the irp down the stack
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2HandleRemove(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PFDO_DEVICE_EXTENSION fdoExtension;
|
|
KIRQL cIrql;
|
|
ULONG i,j;
|
|
PIRBIRP packet;
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
if (!TEST_FLAG (deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVED)) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// now we need to remove ourselves from the DeviceList, the sbp2 FDO keeps of its
|
|
// children...
|
|
// then we re-condense the list..
|
|
//
|
|
|
|
KeAcquireSpinLock (&fdoExtension->DeviceListLock,&cIrql);
|
|
|
|
if (fdoExtension->DeviceListSize > 1) {
|
|
|
|
DEBUGPRINT1(("\'Sbp2Cleanup, condensing PDO list\n"));
|
|
|
|
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
|
|
|
|
if (fdoExtension->DeviceList[i].DeviceObject == DeviceObject) {
|
|
|
|
//
|
|
// free the model descriptor only if its not the same as the FDOs
|
|
// this only happens in the multi-lu case
|
|
//
|
|
|
|
if (fdoExtension->DeviceList[i].uniVendorId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniVendorId.Buffer);
|
|
fdoExtension->DeviceList[i].uniVendorId.Length = 0;
|
|
fdoExtension->DeviceList[i].uniVendorId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[i].uniModelId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniModelId.Buffer);
|
|
fdoExtension->DeviceList[i].uniModelId.Length = 0;
|
|
fdoExtension->DeviceList[i].uniModelId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[i].uniGenericName.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[i].uniGenericName.Buffer);
|
|
fdoExtension->DeviceList[i].uniGenericName.Length = 0;
|
|
fdoExtension->DeviceList[i].uniGenericName.Buffer = NULL;
|
|
}
|
|
|
|
//
|
|
// we found our place in the list. Remove us and re-condense the list
|
|
//
|
|
|
|
for (j = i; j < fdoExtension->DeviceListSize; j++) {
|
|
|
|
if ((j + 1) < fdoExtension->DeviceListSize) {
|
|
|
|
fdoExtension->DeviceList[j] = fdoExtension->DeviceList[j+1];
|
|
|
|
//
|
|
// Change the (pdo)DevExt->DeviceInfo to point at
|
|
// the next postion in the device list
|
|
//
|
|
|
|
deviceExtension = fdoExtension->DeviceList[j].
|
|
DeviceObject->DeviceExtension;
|
|
|
|
deviceExtension->DeviceInfo =
|
|
&fdoExtension->DeviceList[j];
|
|
}
|
|
}
|
|
|
|
fdoExtension->DeviceListSize--;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if (fdoExtension->DeviceList[0].DeviceObject == DeviceObject) {
|
|
|
|
if (fdoExtension->DeviceList[0].uniVendorId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[0].uniVendorId.Buffer);
|
|
fdoExtension->DeviceList[0].uniVendorId.Length = 0;
|
|
fdoExtension->DeviceList[0].uniVendorId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[0].uniModelId.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[0].uniModelId.Buffer);
|
|
fdoExtension->DeviceList[0].uniModelId.Length = 0;
|
|
fdoExtension->DeviceList[0].uniModelId.Buffer = NULL;
|
|
}
|
|
|
|
if (fdoExtension->DeviceList[0].uniGenericName.Buffer) {
|
|
|
|
ExFreePool(fdoExtension->DeviceList[0].uniGenericName.Buffer);
|
|
fdoExtension->DeviceList[0].uniGenericName.Length = 0;
|
|
fdoExtension->DeviceList[0].uniGenericName.Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
fdoExtension->DeviceList[0].DeviceObject = NULL;
|
|
fdoExtension->DeviceListSize = 0;
|
|
|
|
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED);
|
|
}
|
|
|
|
if (fdoExtension->DeviceListSize == 0) {
|
|
|
|
//
|
|
// all our children have been deleted, set our FDO to be inactive
|
|
// so it can not re create PDOs qhen it receives a QDR.
|
|
// The reaosn is that if our PDOS are all removed, we dont support
|
|
// dynamic changes ot the crom, which would then warrant us being
|
|
// able to eject PDOs again.
|
|
//
|
|
|
|
SET_FLAG(fdoExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
|
|
|
|
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
|
|
|
|
//
|
|
// Disable bus reset notifications
|
|
//
|
|
|
|
AllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, &packet);
|
|
|
|
if (packet) {
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
|
|
packet->Irb->Flags = 0;
|
|
packet->Irb->u.BusResetNotification.fulFlags = DEREGISTER_NOTIFICATION_ROUTINE;
|
|
|
|
Sbp2SendRequest(
|
|
(PDEVICE_EXTENSION) fdoExtension,
|
|
packet,
|
|
SYNC_1394_REQUEST
|
|
);
|
|
|
|
DeAllocateIrpAndIrb((PDEVICE_EXTENSION)fdoExtension,packet);
|
|
}
|
|
|
|
fdoExtension->NumPDOsStarted = 0;
|
|
|
|
} else {
|
|
|
|
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2FdoRequestCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT Event
|
|
)
|
|
|
|
{
|
|
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2CreateDeviceRelations(
|
|
IN PFDO_DEVICE_EXTENSION FdoExtension,
|
|
IN PDEVICE_RELATIONS DeviceRelations
|
|
)
|
|
{
|
|
ULONG i;
|
|
NTSTATUS status;
|
|
ULONG instanceNum;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// LUNS are static in the Config Rom. so if our DeviceListSize >0, that objetc
|
|
// has been seen before
|
|
//
|
|
|
|
DeviceRelations->Count = 0;
|
|
|
|
status = Sbp2Get1394ConfigInfo (FdoExtension, NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ExFreePool (DeviceRelations);
|
|
return status;
|
|
}
|
|
|
|
if (TEST_FLAG (FdoExtension->DeviceFlags,DEVICE_FLAG_STOPPED)) {
|
|
|
|
ExFreePool(DeviceRelations);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
for (i = 0; i < FdoExtension->DeviceListSize; i++) {
|
|
|
|
if (!FdoExtension->DeviceList[i].DeviceObject) {
|
|
|
|
instanceNum = 0;
|
|
|
|
do {
|
|
|
|
status = Sbp2CreatePdo (FdoExtension,&FdoExtension->DeviceList[i],instanceNum++);
|
|
|
|
} while (status == STATUS_OBJECT_NAME_COLLISION);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DEBUGPRINT1(("\'Sbp2CreateDeviceRelations, Failed to create PDO \n"));
|
|
|
|
ExFreePool (DeviceRelations);
|
|
return status;
|
|
}
|
|
|
|
DeviceRelations->Objects[DeviceRelations->Count] = FdoExtension->DeviceList[i].DeviceObject;
|
|
DeviceRelations->Count++;
|
|
ObReferenceObject (FdoExtension->DeviceList[i].DeviceObject);
|
|
|
|
} else {
|
|
|
|
//
|
|
// On NT we always add existing pdo's to the dev relations list.
|
|
//
|
|
// On 9x, we only add pdo's to the list whose DevFlags field
|
|
// is non-zero. If we see a pdo with a zero DevFlags field
|
|
// then that means it was never started (likely for lack of
|
|
// a driver), and we don't want to re-indicate it to the caller.
|
|
// The pdo will eventually get deleted when cleaning up the fdo.
|
|
//
|
|
|
|
if (!SystemIsNT) {
|
|
|
|
PDEVICE_EXTENSION pdoExtension;
|
|
|
|
|
|
pdoExtension = (PDEVICE_EXTENSION)
|
|
FdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
|
|
|
|
if (pdoExtension->DeviceFlags &
|
|
DEVICE_FLAG_UNSTARTED_AND_REMOVED) {
|
|
|
|
ASSERT(pdoExtension->DeviceFlags == DEVICE_FLAG_UNSTARTED_AND_REMOVED);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: CreateDevRelations: excluding ext=x%x\n",
|
|
pdoExtension
|
|
));
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
DeviceRelations->Objects[DeviceRelations->Count] =
|
|
FdoExtension->DeviceList[i].DeviceObject;
|
|
DeviceRelations->Count++;
|
|
ObReferenceObject (FdoExtension->DeviceList[i].DeviceObject);
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// code below ported from scsiport
|
|
//
|
|
|
|
NTSTATUS
|
|
Sbp2SystemControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles only the WMI related requests. It mostly passes everything down
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies a pointer to the device object for this request.
|
|
|
|
Irp - Supplies the Irp making the request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
if (deviceExtension->Type == SBP2_FDO) {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: WmiCtl: irp=x%p not handled, passing it down\n", Irp));
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
return (IoCallDriver(deviceExtension->LowerDeviceObject, Irp));
|
|
|
|
} else {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* ******************************* POWER MANAGEMENT ********************************/
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2PowerControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine receives the various Power messages
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
PFDO_DEVICE_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PIO_COMPLETION_ROUTINE complRoutine;
|
|
KIRQL cIrql;
|
|
NTSTATUS status;
|
|
POWER_STATE State;
|
|
UCHAR minorFunction;
|
|
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: %sExt=x%p, irp=x%p, minor=x%x\n",
|
|
(deviceExtension->Type == SBP2_FDO ? "fdo" : "pdo"),
|
|
deviceExtension,
|
|
Irp,
|
|
irpStack->MinorFunction
|
|
));
|
|
|
|
switch (deviceExtension->Type) {
|
|
|
|
case SBP2_PDO:
|
|
|
|
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: pdoExt=x%p REMOVED!\n",
|
|
deviceExtension
|
|
));
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
switch ((minorFunction = irpStack->MinorFunction)) {
|
|
|
|
case IRP_MN_SET_POWER:
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Power: Type = %d, State = %d\n",
|
|
irpStack->Parameters.Power.Type,irpStack->Parameters.Power.State.DeviceState));
|
|
|
|
State = irpStack->Parameters.Power.State;
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
BOOLEAN sendDIrp = FALSE;
|
|
|
|
|
|
//
|
|
// make up a device state to correspond to a system state
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Power: sys power chg from %x to %x\n",deviceExtension->SystemPowerState,State));
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
|
|
if (State.SystemState >= PowerSystemShutdown) {
|
|
|
|
//
|
|
// dont do anything for shutdown
|
|
//
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Power: sys shutdown, ignoring\n"));
|
|
deviceExtension->SystemPowerState = State.SystemState;
|
|
|
|
} else if ((deviceExtension->SystemPowerState == PowerSystemWorking) &&
|
|
(State.SystemState != PowerSystemWorking)){
|
|
|
|
deviceExtension->SystemPowerState = State.SystemState;
|
|
|
|
if (deviceExtension->DevicePowerState != PowerDeviceD3) {
|
|
|
|
//
|
|
// Powering down
|
|
//
|
|
|
|
State.DeviceState = PowerDeviceD3;
|
|
sendDIrp = TRUE;
|
|
}
|
|
|
|
} else if (State.SystemState == PowerSystemWorking) {
|
|
|
|
deviceExtension->SystemPowerState = State.SystemState;
|
|
|
|
if (deviceExtension->DevicePowerState != PowerDeviceD0) {
|
|
|
|
//
|
|
// Powering up - check for an absent fdo
|
|
//
|
|
|
|
fdoExtension =
|
|
deviceExtension->BusFdo->DeviceExtension;
|
|
|
|
if (TEST_FLAG(
|
|
fdoExtension->DeviceFlags,
|
|
DEVICE_FLAG_ABSENT_ON_POWER_UP
|
|
)) {
|
|
|
|
SET_FLAG(
|
|
deviceExtension->DeviceFlags,
|
|
DEVICE_FLAG_ABSENT_ON_POWER_UP
|
|
);
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Power: dev absent, failing\n"
|
|
));
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
|
|
} else {
|
|
|
|
State.DeviceState = PowerDeviceD0;
|
|
sendDIrp = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
|
|
|
|
if (sendDIrp) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: ext=x%p send D irp for state %d\n",
|
|
deviceExtension,
|
|
State
|
|
));
|
|
|
|
IoMarkIrpPending (Irp);
|
|
|
|
status = PoRequestPowerIrp(
|
|
DeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
State,
|
|
Sbp2PdoDIrpCompletion,
|
|
Irp,
|
|
NULL);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
irpStack->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Power: ext=x%p PoReqPowerIrp err=x%x\n",
|
|
deviceExtension,
|
|
status
|
|
));
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return status;
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT2(("Sbp2Port: Power: dev power chg from %x to %x\n",deviceExtension->DevicePowerState,State));
|
|
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
|
|
deviceExtension->DevicePowerState = State.DeviceState;
|
|
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_WAIT_WAKE:
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
case IRP_MN_QUERY_POWER:
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
if ((minorFunction == IRP_MN_SET_POWER) &&
|
|
(State.DeviceState == PowerDeviceD0)) {
|
|
|
|
//
|
|
// restart our queue if we had to queue something while powering up
|
|
//
|
|
// ISSUE: This may be bad - there is already some logic in
|
|
// SBP2SCSI.C to restart the queue on power up, i.e.
|
|
// the UNLOCK_QUEUE handler. For now i am at least
|
|
// limiting this to SET_POWER irps when state is D0
|
|
// DanKn 02-Jun-2001
|
|
//
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
|
|
|
|
Sbp2StartNextPacketByKey(
|
|
DeviceObject,
|
|
deviceExtension->CurrentKey
|
|
);
|
|
|
|
KeLowerIrql (cIrql);
|
|
}
|
|
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
|
|
return (status);
|
|
|
|
case SBP2_FDO:
|
|
|
|
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension;
|
|
|
|
complRoutine = NULL;
|
|
|
|
if (irpStack->MinorFunction == IRP_MN_SET_POWER) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: Type = %d, State = %d\n",
|
|
irpStack->Parameters.Power.Type,
|
|
irpStack->Parameters.Power.State.DeviceState
|
|
));
|
|
|
|
if (irpStack->Parameters.Power.Type == SystemPowerState) {
|
|
|
|
State = irpStack->Parameters.Power.State;
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: sys power chg from %x to %x\n",
|
|
fdoExtension->SystemPowerState,
|
|
State
|
|
));
|
|
|
|
if (State.SystemState >= PowerSystemShutdown) {
|
|
|
|
//
|
|
// Shutdown (setting state here, the assumption being
|
|
// that we're shutting down regardless of the
|
|
// completion status of this request)
|
|
//
|
|
|
|
fdoExtension->SystemPowerState = State.SystemState;
|
|
|
|
} else if ((fdoExtension->SystemPowerState ==
|
|
PowerSystemWorking) &&
|
|
|
|
(State.SystemState != PowerSystemWorking)) {
|
|
|
|
//
|
|
// Power down. If DevPowerState != D3 then send
|
|
// a D irp first (when that completes successfully
|
|
// we'll continue with the S irp), else just
|
|
// set the completion routine so we can update
|
|
// the system state field in our extension on
|
|
// successful completion of this S irp.
|
|
//
|
|
|
|
if (fdoExtension->DevicePowerState != PowerDeviceD3) {
|
|
|
|
//
|
|
// Power down, send a D irp first
|
|
//
|
|
|
|
IoMarkIrpPending (Irp);
|
|
|
|
fdoExtension->SystemPowerIrp = Irp;
|
|
|
|
State.DeviceState = PowerDeviceD3;
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: Power: ext=x%p sending D irp for state %x\n",
|
|
deviceExtension,
|
|
State
|
|
));
|
|
|
|
status = PoRequestPowerIrp(
|
|
fdoExtension->Pdo,
|
|
IRP_MN_SET_POWER,
|
|
State,
|
|
Sbp2FdoDIrpCompletion,
|
|
fdoExtension,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: Power: ext=x%p PoReqPowerIrp err=x%x\n",
|
|
fdoExtension,
|
|
status
|
|
));
|
|
|
|
irpStack->Control &= ~SL_PENDING_RETURNED;
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status;
|
|
|
|
} else {
|
|
|
|
complRoutine = Sbp2FdoSIrpCompletion;
|
|
}
|
|
|
|
} else if (State.SystemState == PowerSystemWorking) {
|
|
|
|
//
|
|
// Power up. Set the completion routine so we
|
|
// follow up with a D irp or update the system
|
|
// state field in our extension on successful
|
|
// completion of this S irp.
|
|
//
|
|
|
|
complRoutine = Sbp2FdoSIrpCompletion;
|
|
}
|
|
}
|
|
}
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
if (complRoutine) {
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
Sbp2FdoSIrpCompletion,
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
return (PoCallDriver (deviceExtension->LowerDeviceObject, Irp));
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
PoStartNextPowerIrp (Irp);
|
|
IoCompleteRequest (Irp,IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2PdoDIrpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PIRP SIrp,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(deviceExtension->Type == SBP2_PDO);
|
|
|
|
if (SIrp) {
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (SIrp);
|
|
SYSTEM_POWER_STATE state = irpStack->Parameters.Power.State.SystemState;
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: PdoDIrpCompl: ext=x%p, sIrp=x%p, state=%d, status=x%x\n",
|
|
deviceExtension,
|
|
SIrp,
|
|
PowerState.DeviceState,
|
|
IoStatus->Status
|
|
));
|
|
|
|
SIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
PoStartNextPowerIrp (SIrp);
|
|
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
|
|
IoCompleteRequest (SIrp, IO_NO_INCREMENT);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2FdoSIrpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Unused
|
|
)
|
|
{
|
|
KIRQL cIrql;
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
POWER_STATE state;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
state = irpStack->Parameters.Power.State;
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: FdoSIrpCompl: fdoExt=x%p, status=x%x, state=%d\n",
|
|
fdoExtension,
|
|
status,
|
|
state
|
|
));
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
if ((status == STATUS_NO_SUCH_DEVICE) &&
|
|
(state.SystemState == PowerSystemWorking)) {
|
|
|
|
//
|
|
// Controller (i.e. pc card) was ejected while powered down
|
|
//
|
|
|
|
SET_FLAG(
|
|
fdoExtension->DeviceFlags,
|
|
DEVICE_FLAG_ABSENT_ON_POWER_UP
|
|
);
|
|
}
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If we're completing a power up S irp then see if we have
|
|
// to follow up with a power up D irp
|
|
//
|
|
|
|
if ((state.SystemState == PowerSystemWorking) &&
|
|
(fdoExtension->DevicePowerState != PowerDeviceD0)) {
|
|
|
|
fdoExtension->SystemPowerIrp = Irp;
|
|
|
|
state.DeviceState = PowerDeviceD0;
|
|
|
|
DEBUGPRINT1(("Sbp2Port: FdoSIrpCompl: sending D irp...\n"));
|
|
|
|
status = PoRequestPowerIrp(
|
|
fdoExtension->Pdo,
|
|
IRP_MN_SET_POWER,
|
|
state,
|
|
Sbp2FdoDIrpCompletion,
|
|
fdoExtension,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: FdoSIrpCompl: ERROR! fdoExt=x%p, D irp sts=x%x\n",
|
|
fdoExtension,
|
|
status
|
|
));
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp (Irp);
|
|
return status;
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
//
|
|
// Update appropriate XxxPowerState extension fields
|
|
//
|
|
|
|
if ((fdoExtension->SystemPowerState == PowerSystemWorking) &&
|
|
(state.SystemState != PowerSystemWorking)) {
|
|
|
|
//
|
|
// Power down (might not have sent a D irp but it doesn't
|
|
// hurt to overwrite the DevicePowerState field anyway)
|
|
//
|
|
|
|
fdoExtension->SystemPowerState = state.SystemState;
|
|
fdoExtension->DevicePowerState = PowerDeviceD3;
|
|
|
|
} else if (state.SystemState == PowerSystemWorking) {
|
|
|
|
//
|
|
// Power up
|
|
//
|
|
|
|
fdoExtension->SystemPowerState = PowerSystemWorking;
|
|
}
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2FdoDIrpCompletion(
|
|
IN PDEVICE_OBJECT TargetDeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PFDO_DEVICE_EXTENSION FdoExtension,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
{
|
|
PIRP sIrp = FdoExtension->SystemPowerIrp;
|
|
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: FdoDIrpCompl: ext=x%p, status=x%x\n",
|
|
FdoExtension,
|
|
IoStatus->Status
|
|
));
|
|
|
|
FdoExtension->SystemPowerIrp = NULL;
|
|
|
|
if (NT_SUCCESS (IoStatus->Status)) {
|
|
|
|
if (PowerState.DeviceState == PowerDeviceD0) {
|
|
|
|
//
|
|
// Power up, update the XxxPowerState extension fields &
|
|
// complete the s irp
|
|
//
|
|
|
|
FdoExtension->SystemPowerState = PowerSystemWorking;
|
|
FdoExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Power down, forward the s irp
|
|
//
|
|
|
|
PoStartNextPowerIrp (sIrp);
|
|
IoCopyCurrentIrpStackLocationToNext (sIrp);
|
|
PoCallDriver (FdoExtension->LowerDeviceObject, sIrp);
|
|
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Propagate the error to the S irp & complete it
|
|
//
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: FdoDIrpCompl: ERROR! fdoExt=x%p, D irp status=x%x\n",
|
|
FdoExtension,
|
|
IoStatus->Status
|
|
));
|
|
|
|
sIrp->IoStatus.Status = IoStatus->Status;
|
|
}
|
|
|
|
PoStartNextPowerIrp (sIrp);
|
|
IoCompleteRequest (sIrp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Sbp2EnableBusResetNotification(
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
BOOLEAN Enable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine serializes the enabling/disabling of the bus reset
|
|
notification routine for a set of related PDOs (1 or more).
|
|
Enables bus reset notifications for the first device to start, and
|
|
disables bus reset notifications when the last started device stops.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies a pointer to the device extension for this request.
|
|
|
|
StartDevice - Whether we are processing a START_DEVICE or (implicitly)
|
|
a STOP_DEVICE request.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - yay or nay
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN result = TRUE;
|
|
PIRBIRP packet;
|
|
LARGE_INTEGER waitValue;
|
|
PFDO_DEVICE_EXTENSION fdoExtension;
|
|
|
|
|
|
fdoExtension = DeviceExtension->BusFdo->DeviceExtension;
|
|
|
|
ASSERT(InterlockedIncrement(&fdoExtension->ulBusResetMutexCount) == 1);
|
|
|
|
waitValue.QuadPart = -3 * 1000 * 1000 * 10; // 3 seconds
|
|
|
|
KeWaitForSingleObject(
|
|
&fdoExtension->EnableBusResetNotificationMutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&waitValue
|
|
);
|
|
|
|
ASSERT(InterlockedDecrement(&fdoExtension->ulBusResetMutexCount) == 0);
|
|
|
|
if (Enable) {
|
|
|
|
fdoExtension->NumPDOsStarted++;
|
|
|
|
if (fdoExtension->NumPDOsStarted > 1) {
|
|
|
|
goto releaseMutex;
|
|
}
|
|
|
|
} else {
|
|
|
|
fdoExtension->NumPDOsStarted--;
|
|
|
|
if (fdoExtension->NumPDOsStarted > 0) {
|
|
|
|
goto releaseMutex;
|
|
}
|
|
}
|
|
|
|
AllocateIrpAndIrb (DeviceExtension, &packet);
|
|
|
|
if (packet) {
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
|
|
packet->Irb->Flags = 0;
|
|
|
|
if (Enable) {
|
|
|
|
packet->Irb->u.BusResetNotification.fulFlags =
|
|
REGISTER_NOTIFICATION_ROUTINE;
|
|
packet->Irb->u.BusResetNotification.ResetRoutine =
|
|
(PBUS_BUS_RESET_NOTIFICATION) Sbp2BusResetNotification;
|
|
packet->Irb->u.BusResetNotification.ResetContext =
|
|
fdoExtension;
|
|
|
|
} else {
|
|
|
|
packet->Irb->u.BusResetNotification.fulFlags =
|
|
DEREGISTER_NOTIFICATION_ROUTINE;
|
|
}
|
|
|
|
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
|
|
|
|
DeAllocateIrpAndIrb (DeviceExtension,packet);
|
|
|
|
} else {
|
|
|
|
if (Enable) {
|
|
|
|
fdoExtension->NumPDOsStarted--;
|
|
}
|
|
|
|
result = FALSE;
|
|
}
|
|
|
|
releaseMutex:
|
|
|
|
KeReleaseMutex (&fdoExtension->EnableBusResetNotificationMutex, FALSE);
|
|
|
|
return result;
|
|
}
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildDeviceId(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniDeviceId
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Create the DeviceId
|
|
//
|
|
uniDeviceId->Length = 0;
|
|
uniDeviceId->MaximumLength = DEVICE_NAME_MAX_CHARS*3;
|
|
uniDeviceId->Buffer = ExAllocatePool(PagedPool, uniDeviceId->MaximumLength);
|
|
|
|
if (!uniDeviceId->Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniDeviceId->Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildDeviceId;
|
|
}
|
|
RtlZeroMemory(uniDeviceId->Buffer, uniDeviceId->MaximumLength);
|
|
|
|
// Format: SBP2\\<VendorName>&<ModelName>&LUN<#>
|
|
if ((DeviceInfo->uniVendorId.Buffer) && (DeviceInfo->uniModelId.Buffer)) {
|
|
|
|
swprintf( uniDeviceId->Buffer,
|
|
L"SBP2\\%ws&%ws&LUN%x",
|
|
DeviceInfo->uniVendorId.Buffer,
|
|
DeviceInfo->uniModelId.Buffer,
|
|
DeviceInfo->Lun.u.LowPart
|
|
);
|
|
}
|
|
else {
|
|
|
|
swprintf( uniDeviceId->Buffer,
|
|
L"SBP2\\UNKNOWN VENDOR&UNKNOWN MODEL&LUN%x",
|
|
DeviceInfo->Lun.u.LowPart
|
|
);
|
|
}
|
|
|
|
Exit_Sbp2_BuildDeviceId:
|
|
|
|
return(ntStatus);
|
|
} // Sbp2_BuildDeviceId
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildHardwareIds(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniHardwareIds
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
UNICODE_STRING uniLunNumber;
|
|
UNICODE_STRING uniCmdSetId;
|
|
|
|
PAGED_CODE();
|
|
|
|
// init our unicodes in case of error...
|
|
uniLunNumber.Buffer = NULL;
|
|
uniCmdSetId.Buffer = NULL;
|
|
|
|
//
|
|
// Create uniLunNumber
|
|
//
|
|
uniLunNumber.Length = 0;
|
|
uniLunNumber.MaximumLength = DEVICE_NAME_MAX_CHARS;
|
|
uniLunNumber.Buffer = ExAllocatePool(PagedPool, uniLunNumber.MaximumLength);
|
|
|
|
if (!uniLunNumber.Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniLunNumber.Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildHardwareIds;
|
|
}
|
|
RtlZeroMemory(uniLunNumber.Buffer, uniLunNumber.MaximumLength);
|
|
|
|
RtlIntegerToUnicodeString(DeviceInfo->Lun.u.LowPart, 16, &uniLunNumber);
|
|
|
|
//
|
|
// Create uniCmdSetId
|
|
//
|
|
uniCmdSetId.Length = 0;
|
|
uniCmdSetId.MaximumLength = DEVICE_NAME_MAX_CHARS;
|
|
uniCmdSetId.Buffer = ExAllocatePool(PagedPool, uniCmdSetId.MaximumLength);
|
|
|
|
if (!uniCmdSetId.Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniCmdSetId.Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildHardwareIds;
|
|
}
|
|
RtlZeroMemory(uniCmdSetId.Buffer, uniCmdSetId.MaximumLength);
|
|
|
|
RtlIntegerToUnicodeString(DeviceInfo->CmdSetId.QuadPart, 16, &uniCmdSetId);
|
|
|
|
//
|
|
// Create the HardwareIds
|
|
//
|
|
uniHardwareIds->Length = 0;
|
|
uniHardwareIds->MaximumLength = DEVICE_NAME_MAX_CHARS*5;
|
|
uniHardwareIds->Buffer = ExAllocatePool(PagedPool, uniHardwareIds->MaximumLength);
|
|
|
|
if (!uniHardwareIds->Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniHardwareIds->Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildHardwareIds;
|
|
}
|
|
RtlZeroMemory(uniHardwareIds->Buffer, uniHardwareIds->MaximumLength);
|
|
|
|
// 1. SBP2\<Vendor>&<Model>&CmdSetId<number,base16>&Gen<dev type, ie. Disk>
|
|
|
|
// BASE: SBP2
|
|
RtlAppendUnicodeToString(uniHardwareIds, BASE_SBP2_DEVICE_NAME);
|
|
|
|
// VendorName and ModelName
|
|
if ((DeviceInfo->uniVendorId.Buffer) && (DeviceInfo->uniModelId.Buffer)) {
|
|
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniVendorId);
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniModelId);
|
|
}
|
|
else {
|
|
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"UNKNOWN VENDOR&UNKNOWN MODEL");
|
|
}
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
|
|
// CmdSetId
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"CmdSetId");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &uniCmdSetId);
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
|
|
// GenericName
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniGenericName);
|
|
|
|
uniHardwareIds->Length += sizeof(WCHAR);
|
|
|
|
// 2. SBP2\<Vendor>&<Model>&CmdSetId<number,base16>
|
|
|
|
// BASE: SBP2
|
|
RtlAppendUnicodeToString(uniHardwareIds, BASE_SBP2_DEVICE_NAME);
|
|
|
|
// VendorName and ModelName
|
|
if ((DeviceInfo->uniVendorId.Buffer) && (DeviceInfo->uniModelId.Buffer)) {
|
|
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniVendorId);
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniModelId);
|
|
}
|
|
else {
|
|
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"UNKNOWN VENDOR&UNKNOWN MODEL");
|
|
}
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
|
|
// CmdSetId
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"CmdSetId");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &uniCmdSetId);
|
|
|
|
uniHardwareIds->Length += sizeof(WCHAR);
|
|
|
|
// 3. SBP2\<Vendor>&<Model>&LUN<number,base16>
|
|
|
|
// BASE: SBP2
|
|
RtlAppendUnicodeToString(uniHardwareIds, BASE_SBP2_DEVICE_NAME);
|
|
|
|
// VendorName and ModelName
|
|
if ((DeviceInfo->uniVendorId.Buffer) && (DeviceInfo->uniModelId.Buffer)) {
|
|
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniVendorId);
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniModelId);
|
|
}
|
|
else {
|
|
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"UNKNOWN VENDOR&UNKNOWN MODEL");
|
|
}
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"&");
|
|
|
|
// LunNumber
|
|
RtlAppendUnicodeToString(uniHardwareIds, L"LUN");
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &uniLunNumber);
|
|
|
|
uniHardwareIds->Length += sizeof(WCHAR);
|
|
|
|
// 4. SBP2\Gen<dev type, i.e. Disk>
|
|
|
|
// BASE: SBP2
|
|
RtlAppendUnicodeToString(uniHardwareIds, BASE_SBP2_DEVICE_NAME);
|
|
|
|
// GenericName
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniGenericName);
|
|
|
|
uniHardwareIds->Length += sizeof(WCHAR);
|
|
|
|
// 5. Gen<dev type, i.e Disk>
|
|
|
|
// GenericName
|
|
RtlAppendUnicodeStringToString(uniHardwareIds, &DeviceInfo->uniGenericName);
|
|
|
|
Exit_Sbp2_BuildHardwareIds:
|
|
|
|
if (uniLunNumber.Buffer)
|
|
ExFreePool(uniLunNumber.Buffer);
|
|
|
|
if (uniCmdSetId.Buffer)
|
|
ExFreePool(uniCmdSetId.Buffer);
|
|
|
|
return(ntStatus);
|
|
} // Sbp2_BuildHardwareIds
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildCompatIds(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniCompatIds
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Create the CompatIds
|
|
//
|
|
uniCompatIds->Length = 0;
|
|
uniCompatIds->MaximumLength = DEVICE_NAME_MAX_CHARS;
|
|
uniCompatIds->Buffer = ExAllocatePool(PagedPool, uniCompatIds->MaximumLength);
|
|
|
|
if (!uniCompatIds->Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniCompatIds->Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildCompatIds;
|
|
}
|
|
RtlZeroMemory(uniCompatIds->Buffer, uniCompatIds->MaximumLength);
|
|
|
|
// Format: SBP2\\<CmdSetSpecId,base10>&<CmdSetId,base10>&<Lun,base10>
|
|
|
|
swprintf( uniCompatIds->Buffer,
|
|
L"SBP2\\%d&%d&%d",
|
|
DeviceInfo->CmdSetSpecId.QuadPart,
|
|
DeviceInfo->CmdSetId.QuadPart,
|
|
(ULONG)(DeviceInfo->Lun.u.HighPart & 0x001F) // huh?
|
|
);
|
|
|
|
Exit_Sbp2_BuildCompatIds:
|
|
|
|
return(ntStatus);
|
|
} // Sbp2_BuildCompatIds
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildInstanceId(
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniInstanceId
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Create the InstanceId
|
|
//
|
|
uniInstanceId->Length = 0;
|
|
uniInstanceId->MaximumLength = UNIQUE_ID_MAX_CHARS;
|
|
uniInstanceId->Buffer = ExAllocatePool(PagedPool, uniInstanceId->MaximumLength);
|
|
|
|
if (!uniInstanceId->Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniInstanceId->Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildInstanceId;
|
|
}
|
|
RtlZeroMemory(uniInstanceId->Buffer, uniInstanceId->MaximumLength);
|
|
|
|
swprintf( uniInstanceId->Buffer,
|
|
L"%08x%08x",
|
|
bswap(DeviceInfo->ConfigRom->CR_Node_UniqueID[0]),
|
|
bswap(DeviceInfo->ConfigRom->CR_Node_UniqueID[1])
|
|
);
|
|
|
|
Exit_Sbp2_BuildInstanceId:
|
|
|
|
return(ntStatus);
|
|
} // Sbp2_BuildInstanceId
|
|
|
|
NTSTATUS
|
|
Sbp2_BuildDeviceText(
|
|
IN DEVICE_TEXT_TYPE TextType,
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
IN OUT PUNICODE_STRING uniDeviceText
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Create the DeviceText
|
|
//
|
|
uniDeviceText->Length = 0;
|
|
uniDeviceText->MaximumLength = DEVICE_NAME_MAX_CHARS*3;
|
|
uniDeviceText->Buffer = ExAllocatePool(PagedPool, uniDeviceText->MaximumLength);
|
|
|
|
if (!uniDeviceText->Buffer) {
|
|
|
|
TRACE(TL_PNP_ERROR, ("Failed to allocate uniDeviceText->Buffer"));
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2_BuildDeviceText;
|
|
}
|
|
RtlZeroMemory(uniDeviceText->Buffer, uniDeviceText->MaximumLength);
|
|
|
|
if (TextType == DeviceTextDescription) {
|
|
|
|
if ((DeviceInfo->uniVendorId.Buffer) && (DeviceInfo->uniModelId.Buffer)) {
|
|
|
|
swprintf( uniDeviceText->Buffer,
|
|
L"%ws %ws IEEE 1394 SBP2 Device",
|
|
DeviceInfo->uniVendorId.Buffer,
|
|
DeviceInfo->uniModelId.Buffer
|
|
);
|
|
}
|
|
else {
|
|
|
|
swprintf( uniDeviceText->Buffer,
|
|
L"UNKNOWN VENDOR AND MODEL IEEE 1394 SBP2 Device"
|
|
);
|
|
}
|
|
}
|
|
else if (TextType == DeviceTextLocationInformation) {
|
|
|
|
swprintf( uniDeviceText->Buffer,
|
|
L"LUN %d",
|
|
DeviceInfo->Lun.u.LowPart
|
|
);
|
|
}
|
|
|
|
Exit_Sbp2_BuildDeviceText:
|
|
|
|
return(ntStatus);
|
|
} // Sbp2_BuildDeviceText
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2ForwardIrpSynchronous(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PIRP newIrp;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(DeviceObject);
|
|
|
|
newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
|
|
|
if (newIrp)
|
|
{
|
|
PIO_STACK_LOCATION currentIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PIO_STACK_LOCATION newIrpSp = IoGetNextIrpStackLocation(newIrp);
|
|
|
|
KEVENT event;
|
|
|
|
RtlMoveMemory (newIrpSp, currentIrpSp, sizeof(IO_STACK_LOCATION));
|
|
newIrp->IoStatus = Irp->IoStatus;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
IoSetCompletionRoutine(newIrp, Sbp2PortForwardIrpSynchronousCompletionRoutine, &event, TRUE, TRUE, TRUE);
|
|
|
|
ntStatus = IoCallDriver (DeviceObject, newIrp);
|
|
|
|
if (ntStatus == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
ntStatus = newIrp->IoStatus.Status;
|
|
|
|
IoFreeIrp(newIrp);
|
|
}
|
|
else
|
|
{
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2PortForwardIrpSynchronousCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PKEVENT event = Context;
|
|
|
|
KeSetEvent(event, EVENT_INCREMENT, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|