Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1897 lines
47 KiB

/*++
Copyright (C) Microsoft Corporation, 1997 - 2001
Module Name:
util.c
Abstract:
Utility functions for the SBP-2 port driver
Author:
George Chrysanthakopoulos January-1997
Environment:
Kernel mode
Revision History :
--*/
#include "sbp2port.h"
VOID
AllocateIrpAndIrb(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRBIRP *Packet
)
{
PIRBIRP pkt;
if (DeviceExtension->Type == SBP2_PDO) {
*Packet = (PIRBIRP) ExInterlockedPopEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
&DeviceExtension->BusRequestLock);
} else {
*Packet = NULL;
}
if (*Packet == NULL) {
//
// run out , allocate a new one
//
pkt = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRBIRP),'2pbs');
if (pkt) {
pkt->Irb = NULL;
pkt->Irb = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRB),'2pbs');
if (!pkt->Irb) {
ExFreePool(pkt);
return;
}
pkt->Irp = NULL;
pkt->Irp = IoAllocateIrp(DeviceExtension->LowerDeviceObject->StackSize,FALSE);
if (!pkt->Irp) {
ExFreePool(pkt->Irb);
ExFreePool(pkt);
return;
}
DEBUGPRINT3((
"Sbp2Port: AllocPkt: %sdo, new irp=x%p, irb=x%p\n",
(DeviceExtension->Type == SBP2_PDO ? "p" : "f"),
pkt->Irp,
pkt->Irb
));
} else {
return;
}
*Packet = pkt;
}
pkt = *Packet;
}
VOID
DeAllocateIrpAndIrb(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRBIRP Packet
)
{
if (DeviceExtension->Type == SBP2_PDO) {
ExInterlockedPushEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
&Packet->ListPointer,
&DeviceExtension->BusRequestLock);
} else {
IoFreeIrp(Packet->Irp);
ExFreePool(Packet->Irb);
ExFreePool(Packet);
}
}
NTSTATUS
AllocateSingle1394Address(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Buffer,
IN ULONG Length,
IN ULONG AccessType,
IN OUT PADDRESS_CONTEXT Context
)
/*++
Routine Description:
A wrapper to the bus driver AllocateAddressRange call, for Async Requests
or ORB's that dont use callbacks.
Arguments:
DeviceObject - Sbp2 device object
Buffer - Data buffer to mapped to 1394 address space
Length - Size of buffer in bytes
AccessType - 1394 bus access to allocated range
Address - Returned Address, from 1394 address space
AddressHanle - Handle associated with the 1394 address
RequestMedl - Mdl associated with this range
Return Value:
NTSTATUS
--*/
{
ULONG finalTransferMode;
PIRBIRP packet;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
AllocateIrpAndIrb (deviceExtension, &packet);
if (!packet) {
return STATUS_INSUFFICIENT_RESOURCES;
}
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
packet->Irb->Flags = 0;
packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
packet->Irb->u.AllocateAddressRange.nLength = Length;
packet->Irb->u.AllocateAddressRange.fulAccessType = AccessType;
packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_NEVER;
packet->Irb->u.AllocateAddressRange.Callback = NULL;
packet->Irb->u.AllocateAddressRange.Context = NULL;
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
if (Buffer) {
packet->Irb->u.AllocateAddressRange.fulFlags = 0;
Context->RequestMdl = IoAllocateMdl (Buffer, Length, FALSE, FALSE, NULL);
if (!Context->RequestMdl) {
DeAllocateIrpAndIrb (deviceExtension,packet);
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool (Context->RequestMdl);
packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
} else {
packet->Irb->u.AllocateAddressRange.fulFlags =
ALLOCATE_ADDRESS_FLAGS_USE_COMMON_BUFFER;
packet->Irb->u.AllocateAddressRange.Mdl = NULL;
}
status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
if (NT_SUCCESS(status)) {
Context->AddressHandle =
packet->Irb->u.AllocateAddressRange.hAddressRange;
Context->Address.BusAddress.NodeId =
deviceExtension->InitiatorAddressId;
if (!Buffer) {
//
// For common buffers we get an mdl *back* from the
// bus/port driver, & need to retrieve a corresponding VA
//
Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl;
Context->Reserved = MmGetMdlVirtualAddress (Context->RequestMdl);
}
}
DeAllocateIrpAndIrb (deviceExtension, packet);
return status;
}
NTSTATUS
AllocateAddressForStatus(
IN PDEVICE_OBJECT DeviceObject,
IN PADDRESS_CONTEXT Context,
IN UCHAR StatusType
)
/*++
Routine Description:
A wrapper to 1394 bus IOCTL AllocateAddressRange for status blocks that
need a Callback notification when the device access the 1394 range...
Arguments:
DeviceObject - Device Object for the sbp2 driver
ADDRESS_CONTEXT - Mini Context for an individual 1394 request
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIRBIRP packet = NULL;
AllocateIrpAndIrb (deviceExtension,&packet);
if (!packet) {
return STATUS_INSUFFICIENT_RESOURCES;
}
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
packet->Irb->Flags = 0;
packet->Irb->u.AllocateAddressRange.nLength = sizeof(STATUS_FIFO_BLOCK);
packet->Irb->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_TYPE_WRITE;
packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_AFTER_WRITE;
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
packet->Irb->u.AllocateAddressRange.fulFlags = 0;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
switch (StatusType) {
case TASK_STATUS_BLOCK:
packet->Irb->u.AllocateAddressRange.Callback = Sbp2TaskOrbStatusCallback;
Context->RequestMdl = IoAllocateMdl(&deviceExtension->TaskOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
if (!Context->RequestMdl) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitAllocateAddress;
}
break;
case MANAGEMENT_STATUS_BLOCK:
packet->Irb->u.AllocateAddressRange.Callback = Sbp2ManagementOrbStatusCallback;
Context->RequestMdl = IoAllocateMdl(&deviceExtension->ManagementOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
if (!Context->RequestMdl) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitAllocateAddress;
}
break;
case CMD_ORB_STATUS_BLOCK:
//
// setup the FIFO list that will receive the status blocks
//
packet->Irb->u.AllocateAddressRange.Callback = Sbp2GlobalStatusCallback;
Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl = NULL;
packet->Irb->u.AllocateAddressRange.FifoSListHead = &deviceExtension->StatusFifoListHead;
packet->Irb->u.AllocateAddressRange.FifoSpinLock = &deviceExtension->StatusFifoLock;
break;
#if PASSWORD_SUPPORT
case PASSWORD_STATUS_BLOCK:
packet->Irb->u.AllocateAddressRange.Callback =
Sbp2SetPasswordOrbStatusCallback;
Context->RequestMdl = IoAllocateMdl(
&deviceExtension->PasswordOrbStatusBlock,
sizeof(STATUS_FIFO_BLOCK),
FALSE,
FALSE,
NULL
);
if (!Context->RequestMdl) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitAllocateAddress;
}
break;
#endif
}
if (Context->RequestMdl) {
MmBuildMdlForNonPagedPool(Context->RequestMdl);
}
packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
packet->Irb->u.AllocateAddressRange.Context = Context;
packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE)&Context->Address;
status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
if (NT_SUCCESS(status)) {
//
// Setup the address context for the status block
//
Context->AddressHandle = packet->Irb->u.AllocateAddressRange.hAddressRange;
Context->DeviceObject = DeviceObject;
Context->Address.BusAddress.NodeId = deviceExtension->InitiatorAddressId;
}
exitAllocateAddress:
DeAllocateIrpAndIrb (deviceExtension, packet);
return status;
}
VOID
CleanupOrbList(
PDEVICE_EXTENSION DeviceExtension,
NTSTATUS CompletionStatus
)
/*++
Routine Description:
This routine will free a linked list of RequestContexts
and will also free the 1394 addresses associated with the
buffers in the context. If the DEVICE_FLAG_RECONNECT i set
instead of completing pending irps, it will requeue them...
Arguments:
DeviceExtension - Device Extension of the sbp2 device
CompletionSTATUS - If one of the linked requests is not completed,
complete it with this status
Return Value:
None
--*/
{
PIRP requestIrp;
PASYNC_REQUEST_CONTEXT currentListItem;
PASYNC_REQUEST_CONTEXT lastItem,nextItem;
KIRQL oldIrql;
//
// Go through the linked list, complete its original Irp and
// free all the associated memory and 1394 resources...
// Since this function is called when we get a REMOVE irp,
// all irps will be terminated with error status
//
KeAcquireSpinLock(&DeviceExtension->OrbListSpinLock,&oldIrql);
if (DeviceExtension->NextContextToFree) {
FreeAsyncRequestContext(DeviceExtension,DeviceExtension->NextContextToFree);
DeviceExtension->NextContextToFree = NULL;
}
if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
//
// nothing to do
//
KeReleaseSpinLock (&DeviceExtension->OrbListSpinLock,oldIrql);
return;
} else {
nextItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Flink,OrbList);
lastItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Blink,OrbList);
InitializeListHead(&DeviceExtension->PendingOrbList);
KeReleaseSpinLock(&DeviceExtension->OrbListSpinLock,oldIrql);
}
//
// Qe have essentially detached this pending context list from
// the main list so we can now free it without holding the lock
// and allowing other requests to be processed.
//
do {
currentListItem = nextItem;
nextItem = (PASYNC_REQUEST_CONTEXT) currentListItem->OrbList.Flink;
if (!TEST_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED)) {
SET_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED);
CLEAR_FLAG(currentListItem->Flags, ASYNC_CONTEXT_FLAG_TIMER_STARTED);
Sbp2_SCSI_RBC_Conversion (currentListItem); // unwind MODE_SENSE hacks
KeCancelTimer(&currentListItem->Timer);
requestIrp =(PIRP)currentListItem->Srb->OriginalRequest;
requestIrp->IoStatus.Status = CompletionStatus;
switch (CompletionStatus) {
case STATUS_DEVICE_DOES_NOT_EXIST:
currentListItem->Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
break;
case STATUS_REQUEST_ABORTED:
currentListItem->Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
break;
case STATUS_IO_TIMEOUT:
currentListItem->Srb->SrbStatus = SRB_STATUS_TIMEOUT;
break;
default:
currentListItem->Srb->SrbStatus = SRB_STATUS_ERROR;
break;
}
if (requestIrp->Type == IO_TYPE_IRP) {
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_RECONNECT)) {
Sbp2StartPacket(
DeviceExtension->DeviceObject,
requestIrp,
&currentListItem->Srb->QueueSortKey
);
//
// free everything related to this request
//
currentListItem->Srb = NULL;
FreeAsyncRequestContext (DeviceExtension, currentListItem);
} else {
//
// free everything related to this request
//
currentListItem->Srb = NULL;
FreeAsyncRequestContext (DeviceExtension, currentListItem);
DEBUGPRINT2(("Sbp2Port: CleanupOrbList: aborted irp x%p compl\n", requestIrp));
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
IoCompleteRequest (requestIrp, IO_NO_INCREMENT);
}
}
} else {
//
// free everything related to this request
//
FreeAsyncRequestContext (DeviceExtension, currentListItem);
}
} while (lastItem != currentListItem); // while loop
return;
}
VOID
FreeAddressRange(
IN PDEVICE_EXTENSION DeviceExtension,
IN PADDRESS_CONTEXT Context
)
/*++
Routine Description:
1394 BUS IOCTL call for freeing an address range.
Arguments:
DeviceExtension - Pointer to sbp2 deviceExtension.
context - address context
Return Value:
NTSTATUS
--*/
{
PIRBIRP packet ;
if (Context->AddressHandle == NULL) {
return;
}
AllocateIrpAndIrb (DeviceExtension, &packet);
if (!packet) {
return;
}
//
// FreeAddressRange is synchronous call
//
packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
packet->Irb->Flags = 0;
//
// We always free one address handle even it refers to multiple
// 1394 addresses. The mdl associated with the original Allocate
// is freed by the port driver.
//
packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
packet->Irb->u.FreeAddressRange.pAddressRange = &Context->AddressHandle;
if (Context->RequestMdl) {
if (Context == &DeviceExtension->CommonBufferContext) {
Context->RequestMdl = NULL; // common buffer, we didn't alloc mdl
} else {
packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length =
(USHORT) MmGetMdlByteCount(Context->RequestMdl);
}
} else if (Context == (PADDRESS_CONTEXT) &DeviceExtension->GlobalStatusContext) {
packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length = sizeof(STATUS_FIFO_BLOCK);
}
packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
if ((KeGetCurrentIrql() >= DISPATCH_LEVEL) && !Context->Address.BusAddress.Off_High) {
PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
(*routine) (DeviceExtension->HostRoutineAPI.Context,packet->Irb);
} else {
//
// dont care about the status of this op
//
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
}
Context->AddressHandle = NULL;
if (Context->RequestMdl) {
IoFreeMdl (Context->RequestMdl);
Context->RequestMdl = NULL;
}
DeAllocateIrpAndIrb (DeviceExtension, packet);
}
VOID
Free1394DataMapping(
PDEVICE_EXTENSION DeviceExtension,
PASYNC_REQUEST_CONTEXT Context
)
{
PIRBIRP packet ;
if (Context->DataMappingHandle == NULL) {
return;
}
AllocateIrpAndIrb (DeviceExtension, &packet);
if (!packet) {
return;
}
//
// Free the data buffer's 1394 address range
//
packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
packet->Irb->Flags = 0;
packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) NULL;
packet->Irb->u.FreeAddressRange.pAddressRange = &Context->DataMappingHandle;
packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
(*routine) (DeviceExtension->HostRoutineAPI.Context, packet->Irb);
} else {
//
// dont care about the status of this op
//
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
}
if (Context->PartialMdl) {
IoFreeMdl (Context->PartialMdl);
Context->PartialMdl = NULL;
}
Context->DataMappingHandle = NULL;
DeAllocateIrpAndIrb (DeviceExtension, packet);
}
ULONG
FreeAsyncRequestContext(
PDEVICE_EXTENSION DeviceExtension,
PASYNC_REQUEST_CONTEXT Context
)
/*++
Routine Description:
This routine will free a single RequestContext and will cleanup all
its buffers and 1394 ranges, ONLY of the device is marked as STOPPED.
Otherwise it will add the context to the FreeList, so it can be reused
later one by another request. This way we are drastically speeding up
each request.
Arguments:
DeviceExtension - Device Extension of the sbp2 device
Context - Context to freed or returned to FreeList
Return Value:
None - The result of the decrement of DeviceExtension->OrbListDepth
--*/
{
//
// This ORB can now be freed along with its data descriptor,
// page tables and context
//
if (!Context || (Context->Tag != SBP2_ASYNC_CONTEXT_TAG)) {
DEBUGPRINT2((
"Sbp2Port: FreeAsyncReqCtx: attempt to push freed ctx=x%p\n",
Context
));
ASSERT(FALSE);
return 0;
}
ASSERT(Context->Srb == NULL);
if (Context->DataMappingHandle) {
Free1394DataMapping(DeviceExtension,Context);
ASSERT(Context->DataMappingHandle==NULL);
}
//
// Re-initiliaze this context so it can be reused
// This context is still part on our FreeAsyncContextPool
// All we have to do is initialize some flags, so next time
// we try to retrieve it, we think its empty
//
Context->Flags |= ASYNC_CONTEXT_FLAG_COMPLETED;
Context->Tag = 0;
if (Context->OriginalSrb) {
ExFreePool(Context->OriginalSrb);
Context->OriginalSrb = NULL;
}
DEBUGPRINT3(("Sbp2Port: FreeAsyncReqCtx: push ctx=x%p on free list\n",Context));
ExInterlockedPushEntrySList(&DeviceExtension->FreeContextListHead,
&Context->LookasideList,
&DeviceExtension->FreeContextLock);
return InterlockedDecrement (&DeviceExtension->OrbListDepth);
}
NTSTATUS
Sbp2SendRequest(
PDEVICE_EXTENSION DeviceExtension,
PIRBIRP RequestPacket,
ULONG TransferMode
)
/*++
Routine Description:
Function used to send requests to the 1394 bus driver. It attaches
a completion routine to each request it sends down, and it also wraps
them in a small context, so we can track their completion
Arguments:
DeviceExtension - Sbp2 device extension
Irp - Irp to send to the bus driver
Irb - Bus driver packet, in the Irp
TransferMode - Indicates if we want ot send this request synchronously
or asynchronously
FinalTransferMode - Indicates whether the request was sent synchronously
or asynchronously
Return Value:
NTSTATUS
--*/
{
ULONG originalTransferMode = TransferMode;
NTSTATUS status;
PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
PREQUEST_CONTEXT requestContext = NULL;
PIO_STACK_LOCATION nextIrpStack;
if (DeviceExtension->Type == SBP2_PDO) {
//
// if device is removed, dont send any requests down
//
if (TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_REMOVED) &&
(RequestPacket->Irb->FunctionNumber != REQUEST_FREE_ADDRESS_RANGE)) {
return STATUS_UNSUCCESSFUL;
}
//
// get a context for this request, from our pool
//
requestContext = ExAllocateFromNPagedLookasideList(&DeviceExtension->BusRequestContextPool);
} else {
requestContext = ExAllocatePool (NonPagedPool,sizeof(REQUEST_CONTEXT));
}
if (!requestContext) {
DEBUGPRINT2((
"Sbp2Port: SendReq: ERROR, couldn't allocate bus req ctx\n"
));
return STATUS_INSUFFICIENT_RESOURCES;
}
if (TransferMode == SYNC_1394_REQUEST) {
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
//
// Since we can't block at this level, we will have to do the
// synch request asynchronously
//
TransferMode = ASYNC_SYNC_1394_REQUEST;
requestContext->Complete = 0;
} else {
KeInitializeEvent(
&requestContext->Event,
NotificationEvent,
FALSE
);
}
}
requestContext->DeviceExtension = DeviceExtension;
requestContext->RequestType = TransferMode;
if (TransferMode == SYNC_1394_REQUEST){
requestContext->Packet = NULL;
} else {
requestContext->Packet = RequestPacket;
}
nextIrpStack = IoGetNextIrpStackLocation (RequestPacket->Irp);
nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
nextIrpStack->Parameters.Others.Argument1 = RequestPacket->Irb;
IoSetCompletionRoutine(RequestPacket->Irp,
Sbp2RequestCompletionRoutine,
requestContext,
TRUE,
TRUE,
TRUE
);
status = IoCallDriver(
DeviceExtension->LowerDeviceObject,
RequestPacket->Irp
);
if (status == STATUS_INVALID_GENERATION) {
DEBUGPRINT1(("Sbp2Port: SendReq: Bus drv ret'd invalid generation\n"));
RequestPacket->Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
}
if (originalTransferMode == SYNC_1394_REQUEST ) {
if (TransferMode == SYNC_1394_REQUEST) {
if (status == STATUS_PENDING) {
//
// < DISPATCH_LEVEL so wait on an event
//
KeWaitForSingleObject(
&requestContext->Event,
Executive,
KernelMode,
FALSE,
NULL
);
}
} else { // ASYNC_SYNC_1394_REQUEST
//
// >= DISPATCH_LEVEL so we can't wait, do the nasty...
//
volatile ULONG *pComplete = &requestContext->Complete;
while (*pComplete == 0);
status = RequestPacket->Irp->IoStatus.Status;
}
//
// Free the context (the Irp.Irb will be returnd by the caller)
//
if (DeviceExtension->Type == SBP2_PDO) {
ExFreeToNPagedLookasideList(&DeviceExtension->BusRequestContextPool, requestContext);
} else {
ExFreePool (requestContext);
}
return RequestPacket->Irp->IoStatus.Status;
}
return status;
}
NTSTATUS
Sbp2RequestCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PREQUEST_CONTEXT Context
)
/*++
Routine Description:
Completion routine used for all requests to 1394 bus driver
Arguments:
DriverObject - Pointer to driver object created by system.
Irp - Irp that just completed
Event - Event we'll signal to say Irp is done
Return Value:
None.
--*/
{
ASSERT(Context!=NULL);
ASSERT(Context->DeviceExtension);
if (Context->RequestType == SYNC_1394_REQUEST) {
//
// Synch request completion (either synch, or synch at DPC)
//
KeSetEvent (&Context->Event, IO_NO_INCREMENT, FALSE);
} else if (Context->RequestType == ASYNC_1394_REQUEST) {
//
// Asynchronous request completion, so do any necessary
// post-processing & return the context and the Irp/Irb
// to the free lists.
//
if (Context->Packet) {
switch (Context->Packet->Irb->FunctionNumber) {
case REQUEST_ASYNC_READ:
case REQUEST_ASYNC_WRITE:
if (Context->Packet->Irb->u.AsyncWrite.nNumberOfBytesToWrite ==
sizeof(OCTLET)) {
IoFreeMdl (Context->Packet->Irb->u.AsyncRead.Mdl);
Context->Packet->Irb->u.AsyncRead.Mdl = NULL;
}
break;
}
DeAllocateIrpAndIrb (Context->DeviceExtension, Context->Packet);
}
if (Context->DeviceExtension->Type == SBP2_PDO) {
ExFreeToNPagedLookasideList(&Context->DeviceExtension->BusRequestContextPool, Context);
} else {
ExFreePool (Context);
}
} else { // ASYNC_SYNC_1394_REQUEST
//
// Just set the Complete flag to unblock Sbp2SendRequest
//
Context->Complete = 1;
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
Sbp2CreateRequestErrorLog(
IN PDEVICE_OBJECT DeviceObject,
IN PASYNC_REQUEST_CONTEXT Context,
IN NTSTATUS Status
)
{
PIO_ERROR_LOG_PACKET errorLogEntry;
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
DeviceObject,
sizeof(IO_ERROR_LOG_PACKET) + sizeof(ORB_NORMAL_CMD)
);
if (errorLogEntry) {
switch (Status) {
case STATUS_DEVICE_POWER_FAILURE:
errorLogEntry->ErrorCode = IO_ERR_NOT_READY;
break;
case STATUS_INSUFFICIENT_RESOURCES:
errorLogEntry->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
break;
case STATUS_TIMEOUT:
errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
break;
case STATUS_DEVICE_PROTOCOL_ERROR:
errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
break;
case STATUS_INVALID_PARAMETER:
case STATUS_INVALID_DEVICE_REQUEST:
errorLogEntry->ErrorCode = IO_ERR_INVALID_REQUEST;
break;
case STATUS_REQUEST_ABORTED:
errorLogEntry->ErrorCode = IO_ERR_RESET;
break;
default:
errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
break;
}
errorLogEntry->SequenceNumber = 0;
errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
errorLogEntry->RetryCount = 0;
errorLogEntry->UniqueErrorValue = 0;
errorLogEntry->FinalStatus = Status;
if (Context) {
errorLogEntry->DumpDataSize = sizeof(ORB_NORMAL_CMD);
RtlCopyMemory(&(errorLogEntry->DumpData[0]),Context->CmdOrb,sizeof(ORB_NORMAL_CMD));
} else {
errorLogEntry->DumpDataSize = 0;
}
IoWriteErrorLogEntry(errorLogEntry);
DEBUGPRINT2((
"Sbp2Port: ErrorLog: dev=x%p, status=x%x, ctx=x%p\n",
DeviceObject,
Status,
Context
));
} else {
DEBUGPRINT2 (("Sbp2Port: ErrorLog: failed to allocate log entry\n"));
}
}
NTSTATUS
CheckStatusResponseValue(
IN PSTATUS_FIFO_BLOCK StatusBlock
)
/*++
Routine Description:
It checks the status block result bits and maps the errors to
NT status errors
Arguments:
DeviceExtension - Sbp2 device extension
ManagementStatus - If true then we check the management orb status
Return Value:
NTSTATUS
++*/
{
NTSTATUS status;
UCHAR resp;
USHORT statusFlags = StatusBlock->AddressAndStatus.u.HighQuad.u.HighPart;
if (statusFlags & STATUS_BLOCK_UNSOLICITED_BIT_MASK) {
//
// The unsolicited bit is set, which means this status is
// not related to anything...
//
return STATUS_NOT_FOUND;
}
resp = ((statusFlags & STATUS_BLOCK_RESP_MASK) >> 12);
switch (resp) {
case 0:
//
// Request complete, check sbp_status field for more info
//
switch ((statusFlags & STATUS_BLOCK_SBP_STATUS_MASK)) {
case 0x00: // no additional status to report
status = STATUS_SUCCESS;
break;
case 0x01: // request type not supported
case 0x02: // speed not supported
case 0x03: // page size not supported
status = STATUS_NOT_SUPPORTED;
break;
case 0x04: // access denied
case 0x05: // LUN not supported
status = STATUS_ACCESS_DENIED;
break;
case 0x08: // resource unavailable
status = STATUS_INSUFFICIENT_RESOURCES;
break;
case 0x09: // function rejected
status = STATUS_ILLEGAL_FUNCTION;
break;
case 0x0a: // login id not recognized
status = STATUS_TRANSACTION_INVALID_ID;
break;
default:
status = STATUS_UNSUCCESSFUL;
break;
}
break;
case 1:
//
// Transport failure, check the redefined sbp-status field
// for serial-bus errors
//
resp = statusFlags & 0x0F;
switch (resp) {
case 0x02: // time out
case 0x0C: // conflict error
case 0x0D: // data error
status = STATUS_DEVICE_PROTOCOL_ERROR;
break;
case 0x04: // busy retry limit exceeded
case 0x05: // busy retry limit exceeded
case 0x06: // busy retry limit exceeded
status = STATUS_DEVICE_BUSY;
break;
case 0x0E: // type error
status = STATUS_INVALID_PARAMETER;
break;
case 0x0F: // address error
status = STATUS_INVALID_ADDRESS;
break;
default:
status = STATUS_UNSUCCESSFUL;
break;
}
break;
case 2: // illegal request
status = STATUS_ILLEGAL_FUNCTION;
break;
default: // case 3:, vendor dependent
status = STATUS_UNSUCCESSFUL; // ISSUE: dankn, 02-Aug-2001
break;
}
return status;
}
VOID
Sbp2StartNextPacketByKey(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG Key
)
/*++
Routine Description:
This routine was lifted from the Io sources
(IopStartNextPacketByKey), and duplicated/modifed here for
two reasons: 1) we got tired of hitting the queue-not-busy assert
in KeRemoveXxx, and 2) we needed a way to prevent stack-blowing
recursion, for example, arising from a bunch of requests sent to
a stopped device (all failed in StartIo, which calls this func).
These routines were originally designed with the idea that there
would only be one outstanding request at a time, but this driver
can have multiple outstanding requests, and it frequently ends up
making redundant calls to XxStartNextPacket(ByKey), which result
in the aforementioned assert.
Rolling our own version of this also allows us to get rid the
the cancel overhead, since we do not (currently) support cancels.
Arguments:
DeviceObject - Pointer to device object itself
Key - Specifics the Key used to remove the entry from the queue
Return Value:
None
--*/
{
PIRP irp;
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
DeviceObject->DeviceExtension;
PKDEVICE_QUEUE_ENTRY packet;
//
// Increment the StartNextPacketCount, and if result is != 1
// then just return because we don't want to worry about
// recursion & blowing the stack. The instance of this
// function that caused the SNPCount 0 to 1 transition
// will eventually make another pass through the loop below
// on this instance's behalf.
//
if (InterlockedIncrement (&deviceExtension->StartNextPacketCount) != 1) {
return;
}
do {
//
// Attempt to remove the indicated packet according to the key
// from the device queue. If one is found, then process it.
//
packet = Sbp2RemoveByKeyDeviceQueueIfBusy(
&DeviceObject->DeviceQueue,
Key
);
if (packet) {
irp = CONTAINING_RECORD (packet,IRP,Tail.Overlay.DeviceQueueEntry);
Sbp2StartIo (DeviceObject, irp);
}
} while (InterlockedDecrement (&deviceExtension->StartNextPacketCount));
}
VOID
Sbp2StartPacket(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PULONG Key OPTIONAL
)
/*++
Routine Description:
(See routine description for Sbp2StartNextPacketByKey)
Arguments:
DeviceObject - Pointer to device object itself
Irp - I/O Request Packet which should be started on the device
Return Value:
None
--*/
{
KIRQL oldIrql;
BOOLEAN inserted;
PLIST_ENTRY nextEntry;
PKDEVICE_QUEUE queue = &DeviceObject->DeviceQueue;
PKDEVICE_QUEUE_ENTRY queueEntry = &Irp->Tail.Overlay.DeviceQueueEntry,
queueEntry2;
//
// Raise the IRQL of the processor to dispatch level for synchronization
//
KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
KeAcquireSpinLockAtDpcLevel (&queue->Lock);
if (Key) {
//
// Insert the specified device queue entry in the device queue at the
// position specified by the sort key if the device queue is busy.
// Otherwise set the device queue busy an don't insert the device
// queue entry.
//
queueEntry->SortKey = *Key;
if (queue->Busy == TRUE) {
inserted = TRUE;
nextEntry = queue->DeviceListHead.Flink;
while (nextEntry != &queue->DeviceListHead) {
queueEntry2 = CONTAINING_RECORD(
nextEntry,
KDEVICE_QUEUE_ENTRY,
DeviceListEntry
);
if (*Key < queueEntry2->SortKey) {
break;
}
nextEntry = nextEntry->Flink;
}
nextEntry = nextEntry->Blink;
InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
} else {
queue->Busy = TRUE;
inserted = FALSE;
}
} else {
//
// Insert the specified device queue entry at the end of the device
// queue if the device queue is busy. Otherwise set the device queue
// busy and don't insert the device queue entry.
//
if (queue->Busy == TRUE) {
inserted = TRUE;
InsertTailList(
&queue->DeviceListHead,
&queueEntry->DeviceListEntry
);
} else {
queue->Busy = TRUE;
inserted = FALSE;
}
}
queueEntry->Inserted = inserted;
KeReleaseSpinLockFromDpcLevel (&queue->Lock);
//
// If the packet was not inserted into the queue, then this request is
// now the current packet for this device. Indicate so by storing its
// address in the current IRP field, and begin processing the request.
//
if (!inserted) {
//
// Invoke the driver's start I/O routine to get the request going
// on the device
//
Sbp2StartIo (DeviceObject, Irp);
}
//
// Restore the IRQL back to its value upon entry to this function before
// returning to the caller
//
KeLowerIrql (oldIrql);
}
PKDEVICE_QUEUE_ENTRY
Sbp2RemoveByKeyDeviceQueueIfBusy(
IN PKDEVICE_QUEUE DeviceQueue,
IN ULONG SortKey
)
/*++
Routine Description:
This routine was lifted directly from Ke sources
(KeRemoveByKeyDeviceQueueIfBusy) to allow this driver to maintain
WDM compatibility, since the Ke API does not exist on Win9x or Win2k.
N.B. This function can only be called from DISPATCH_LEVEL.
Arguments:
DeviceQueue - Supplies a pointer to a control object of type device queue.
SortKey - Supplies the sort key by which the position to remove the device
queue entry is to be determined.
Return Value:
A NULL pointer is returned if the device queue is empty. Otherwise a
pointer to a device queue entry is returned.
--*/
{
PLIST_ENTRY nextEntry;
PKDEVICE_QUEUE_ENTRY queueEntry;
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
//
// Lock specified device queue.
//
KeAcquireSpinLockAtDpcLevel (&DeviceQueue->Lock);
//
// If the device queue is busy, then attempt to remove an entry from
// the queue using the sort key. Otherwise, set the device queue not
// busy.
//
if (DeviceQueue->Busy != FALSE) {
if (IsListEmpty (&DeviceQueue->DeviceListHead) != FALSE) {
DeviceQueue->Busy = FALSE;
queueEntry = NULL;
} else {
nextEntry = DeviceQueue->DeviceListHead.Flink;
while (nextEntry != &DeviceQueue->DeviceListHead) {
queueEntry = CONTAINING_RECORD(
nextEntry,
KDEVICE_QUEUE_ENTRY,
DeviceListEntry
);
if (SortKey <= queueEntry->SortKey) {
break;
}
nextEntry = nextEntry->Flink;
}
if (nextEntry != &DeviceQueue->DeviceListHead) {
RemoveEntryList (&queueEntry->DeviceListEntry);
} else {
nextEntry = RemoveHeadList (&DeviceQueue->DeviceListHead);
queueEntry = CONTAINING_RECORD(
nextEntry,
KDEVICE_QUEUE_ENTRY,
DeviceListEntry
);
}
queueEntry->Inserted = FALSE;
}
} else {
queueEntry = NULL;
}
//
// Unlock specified device queue and return address of device queue
// entry.
//
KeReleaseSpinLockFromDpcLevel (&DeviceQueue->Lock);
return queueEntry;
}
BOOLEAN
Sbp2InsertByKeyDeviceQueue(
PKDEVICE_QUEUE DeviceQueue,
PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
ULONG SortKey
)
/*++
Routine Description:
(Again, stolen from Ke src to maintain consistent use of spinlocks.)
This function inserts a device queue entry into the specified device
queue according to a sort key. If the device is not busy, then it is
set busy and the entry is not placed in the device queue. Otherwise
the specified entry is placed in the device queue at a position such
that the specified sort key is greater than or equal to its predecessor
and less than its successor.
N.B. This function can only be called from DISPATCH_LEVEL.
Arguments:
DeviceQueue - Supplies a pointer to a control object of type device queue.
DeviceQueueEntry - Supplies a pointer to a device queue entry.
SortKey - Supplies the sort key by which the position to insert the device
queue entry is to be determined.
Return Value:
If the device is not busy, then a value of FALSE is returned. Otherwise a
value of TRUE is returned.
--*/
{
BOOLEAN inserted;
PLIST_ENTRY nextEntry;
PKDEVICE_QUEUE queue = DeviceQueue;
PKDEVICE_QUEUE_ENTRY queueEntry = DeviceQueueEntry,
queueEntry2;
KeAcquireSpinLockAtDpcLevel (&queue->Lock);
//
// Insert the specified device queue entry in the device queue at the
// position specified by the sort key if the device queue is busy.
// Otherwise set the device queue busy an don't insert the device
// queue entry.
//
queueEntry->SortKey = SortKey;
if (queue->Busy == TRUE) {
inserted = TRUE;
nextEntry = queue->DeviceListHead.Flink;
while (nextEntry != &queue->DeviceListHead) {
queueEntry2 = CONTAINING_RECORD(
nextEntry,
KDEVICE_QUEUE_ENTRY,
DeviceListEntry
);
if (SortKey < queueEntry2->SortKey) {
break;
}
nextEntry = nextEntry->Flink;
}
nextEntry = nextEntry->Blink;
InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
} else {
queue->Busy = TRUE;
inserted = FALSE;
}
KeReleaseSpinLockFromDpcLevel (&queue->Lock);
return inserted;
}
#if PASSWORD_SUPPORT
NTSTATUS
Sbp2GetExclusiveValue(
IN PDEVICE_OBJECT PhysicalDeviceObject,
OUT PULONG Exclusive
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE RootHandle = NULL;
UNICODE_STRING uniTempName;
// set default value...
*Exclusive = EXCLUSIVE_FLAG_CLEAR;
uniTempName.Buffer = NULL;
ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&RootHandle
);
if (!NT_SUCCESS(ntStatus)) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Sbp2GetExclusiveValue;
}
uniTempName.Length = 0;
uniTempName.MaximumLength = 128;
uniTempName.Buffer = ExAllocatePool(
NonPagedPool,
uniTempName.MaximumLength
);
if (!uniTempName.Buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Sbp2GetExclusiveValue;
}
{
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
ULONG KeyLength;
ULONG ResultLength;
KeyLength = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (ULONG);
KeyInfo = ExAllocatePool (NonPagedPool, KeyLength);
if (KeyInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Sbp2GetExclusiveValue;
}
RtlZeroMemory(uniTempName.Buffer, uniTempName.MaximumLength);
uniTempName.Length = 0;
RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
ntStatus = ZwQueryValueKey( RootHandle,
&uniTempName,
KeyValuePartialInformation,
KeyInfo,
KeyLength,
&ResultLength
);
if (NT_SUCCESS(ntStatus)) {
*Exclusive = *((PULONG) &KeyInfo->Data);
DEBUGPRINT1 (("Sbp2Port: GetExclVal: excl=x%x\n", *Exclusive));
} else {
DEBUGPRINT1((
"Sbp2Port: GetExclVal: QueryValueKey err=x%x\n",
ntStatus
));
}
ExFreePool (KeyInfo);
}
Exit_Sbp2GetExclusiveValue:
if (RootHandle) {
ZwClose (RootHandle);
}
if (uniTempName.Buffer) {
ExFreePool (uniTempName.Buffer);
}
return ntStatus;
}
NTSTATUS
Sbp2SetExclusiveValue(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PULONG Exclusive
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE RootHandle = NULL;
UNICODE_STRING uniTempName;
uniTempName.Buffer = NULL;
ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&RootHandle
);
if (!NT_SUCCESS(ntStatus)) {
goto Exit_Sbp2SetExclusiveValue;
}
uniTempName.Length = 0;
uniTempName.MaximumLength = 128;
uniTempName.Buffer = ExAllocatePool(
NonPagedPool,
uniTempName.MaximumLength
);
if (!uniTempName.Buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_Sbp2SetExclusiveValue;
}
RtlZeroMemory (uniTempName.Buffer, uniTempName.MaximumLength);
uniTempName.Length = 0;
RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
ntStatus = ZwSetValueKey( RootHandle,
&uniTempName,
0,
REG_DWORD,
Exclusive,
sizeof(ULONG)
);
if (!NT_SUCCESS(ntStatus)) {
DEBUGPRINT1(("Sbp2Port: SetExclVal: SetValueKey err=x%x\n", ntStatus));
*Exclusive = 0;
}
else {
DEBUGPRINT1(("Sbp2Port: SetExclVal: excl=x%x\n", *Exclusive));
}
Exit_Sbp2SetExclusiveValue:
if (RootHandle) {
ZwClose(RootHandle);
}
if (uniTempName.Buffer) {
ExFreePool(uniTempName.Buffer);
}
return ntStatus;
}
#endif