Windows2003-3790/drivers/storage/sbp2port/sbp2port.c
2020-09-30 16:53:55 +02:00

5588 lines
161 KiB
C

/*++
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 ((&current->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(&current->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;
}