1084 lines
35 KiB
C
1084 lines
35 KiB
C
|
#define FCT_ID 0x0120
|
|||
|
|
|||
|
#include <ntddk.h>
|
|||
|
#include <ntddtape.h> // tape device driver I/O control codes
|
|||
|
#include "common.h"
|
|||
|
#include "q117.h"
|
|||
|
#include "protos.h"
|
|||
|
#include "frb.h"
|
|||
|
|
|||
|
#ifdef FRB_PROCESSOR
|
|||
|
//#define far
|
|||
|
#define IORequest_DEF
|
|||
|
#define WINDOWS_H
|
|||
|
|
|||
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
|||
|
#define MIN(a,b) ((a) > (b) ? (b) : (a))
|
|||
|
|
|||
|
/***********************/
|
|||
|
|
|||
|
|
|||
|
#define MAX_IO_PENDING 20
|
|||
|
|
|||
|
typedef struct _BUF_POOL {
|
|||
|
LIST_ENTRY BufListEntry;
|
|||
|
SEGMENT_BUFFER BufferInfo;
|
|||
|
} BUF_POOL, *PBUF_POOL;
|
|||
|
|
|||
|
typedef struct _IO_POOL {
|
|||
|
LIST_ENTRY IoListEntry;
|
|||
|
ULONG Signature;
|
|||
|
USHORT DataSize;
|
|||
|
CMSIOFLAGS Flags;
|
|||
|
PBUF_POOL BufferPool;
|
|||
|
PVOID OriginalData;
|
|||
|
PIRP Irp;
|
|||
|
IO_REQUEST drv_request;
|
|||
|
BOOLEAN InIoCompleteList;
|
|||
|
} IO_POOL, *PIO_POOL;
|
|||
|
|
|||
|
/************************ Globals *******************************************/
|
|||
|
LIST_ENTRY topIoFreePool; // Free pool of I/O requests
|
|||
|
LIST_ENTRY topIoActive; // I/O requests pending in lower level driver
|
|||
|
LIST_ENTRY topIoComplete; // I/O requests completed but GetCmdResult not processed
|
|||
|
LIST_ENTRY topBufFreePool;
|
|||
|
LIST_ENTRY topBufActive;
|
|||
|
LIST_ENTRY topIoPending; // Request the user made but could not be processed
|
|||
|
// until resources are freed
|
|||
|
BOOLEAN adi_Opened;
|
|||
|
PBUF_POOL bufPool;
|
|||
|
PIO_POOL ioPool;
|
|||
|
KSPIN_LOCK poolLock;
|
|||
|
|
|||
|
void cms_ClearActive(void);
|
|||
|
|
|||
|
void *CMSWTAPE_C_MapFlat(void *vmptr, long vmid);
|
|||
|
|
|||
|
#define IOCTL_NEEDS_BUFFER 1
|
|||
|
#define IOCTL_COPY_BUFFER_IN 2
|
|||
|
#define IOCTL_COPY_BUFFER_OUT 4
|
|||
|
|
|||
|
NTSTATUS cms_IoCompletionRoutine (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_POOL IoPoolEntry
|
|||
|
);
|
|||
|
int cms_ProcessAsyncRequest(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
int cms_GetCmdResult(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
void cms_CompleteRequest(
|
|||
|
PIO_POOL IoPool,
|
|||
|
IN PIRP Irp,
|
|||
|
NTSTATUS CompletionStatus,
|
|||
|
BOOLEAN belayCompletion
|
|||
|
);
|
|||
|
void cms_InitPools(
|
|||
|
PQ117_CONTEXT Context
|
|||
|
);
|
|||
|
dStatus cms_SendAbortRequest(
|
|||
|
PIO_POOL IoPoolEntry,
|
|||
|
PQ117_CONTEXT Context
|
|||
|
);
|
|||
|
|
|||
|
#ifndef NOCODELOCK
|
|||
|
#pragma alloc_text(PAGEQICH, cms_IoCompletionRoutine)
|
|||
|
#pragma alloc_text(PAGEQICH, cms_ProcessAsyncRequest)
|
|||
|
#pragma alloc_text(PAGEQICH, cms_CompleteRequest)
|
|||
|
#pragma alloc_text(PAGEQICH, cms_GetCmdResult)
|
|||
|
#pragma alloc_text(PAGEQICH, cms_InitPools)
|
|||
|
#pragma alloc_text(PAGEQICH, cms_SendAbortRequest)
|
|||
|
#endif
|
|||
|
|
|||
|
#define DEBUG_LEVEL1 ((ULONG)0x10000000)
|
|||
|
#define DEBUG_LEVEL2 ((ULONG)0x20000000)
|
|||
|
#define DEBUG_LEVEL3 ((ULONG)0x40000000)
|
|||
|
#define DEBUG_LEVEL4 ((ULONG)0x80000000)
|
|||
|
|
|||
|
/*
|
|||
|
// Note that the user's output buffer is stored in the UserBuffer field
|
|||
|
// and the user's input buffer is stored in the SystemBuffer field.
|
|||
|
//
|
|||
|
|
|||
|
struct {
|
|||
|
ULONG OutputBufferLength;
|
|||
|
ULONG InputBufferLength;
|
|||
|
ULONG IoControlCode;
|
|||
|
PVOID Type3InputBuffer;
|
|||
|
} DeviceIoControl;
|
|||
|
*/
|
|||
|
|
|||
|
cms_IoCtl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
PQ117_CONTEXT context;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
PBUF_POOL buf;
|
|||
|
void *client_data;
|
|||
|
PIO_POOL ior;
|
|||
|
int req_size;
|
|||
|
dStatus ret_val;
|
|||
|
int data_size;
|
|||
|
int IoControlCode;
|
|||
|
struct KernelRequest *UserRequest;
|
|||
|
int outlen;
|
|||
|
BOOLEAN forcePending;
|
|||
|
PSEGMENT_BUFFER bufInfo;
|
|||
|
KIRQL old_irql;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
|
|||
|
context = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
#if DBG
|
|||
|
kdi_debug_level |= DEBUG_LEVEL4;
|
|||
|
#endif
|
|||
|
|
|||
|
UserRequest = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
IoControlCode =
|
|||
|
(irpStack->Parameters.DeviceIoControl.IoControlCode >>
|
|||
|
IOCTL_CMS_IOCTL_SHIFT) & 0xff;
|
|||
|
// outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|||
|
// inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|||
|
outlen = 0;
|
|||
|
buf = NULL;
|
|||
|
ret_val = 0;
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: received ioctl %x\n",IoControlCode));
|
|||
|
if (adi_Opened == FALSE && IoControlCode != XXX_adi_OpenDriver) {
|
|||
|
ret_val = ERROR_ENCODE(ERR_INVALID_REQUEST, FCT_ID, 1);
|
|||
|
return q117ConvertStatus(DeviceObject, ret_val);
|
|||
|
}
|
|||
|
|
|||
|
switch(IoControlCode) {
|
|||
|
case XXX_adi_SendDriverCmd:
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_SendDriver received cmd %x\n",UserRequest->hdr.driver_cmd));
|
|||
|
|
|||
|
client_data = UserRequest->hdr.cmd_buffer_ptr;
|
|||
|
data_size = UserRequest->prefix.data_size;
|
|||
|
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
forcePending = !IsListEmpty(&topIoPending);
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
switch(UserRequest->hdr.driver_cmd) {
|
|||
|
case CMD_SELECT_DEVICE:
|
|||
|
case CMD_DESELECT_DEVICE:
|
|||
|
//
|
|||
|
// Keep track of the selected state (so close will de-select
|
|||
|
// if needed. NOTE: falls through
|
|||
|
//
|
|||
|
context->DeviceSelected = (UserRequest->hdr.driver_cmd == CMD_SELECT_DEVICE);
|
|||
|
|
|||
|
case CMD_REPORT_DEVICE_CFG:
|
|||
|
case CMD_REPORT_DEVICE_INFO:
|
|||
|
case CMD_LOCATE_DEVICE:
|
|||
|
case CMD_LOAD_TAPE:
|
|||
|
case CMD_UNLOAD_TAPE:
|
|||
|
case CMD_SET_SPEED:
|
|||
|
case CMD_REPORT_STATUS:
|
|||
|
case CMD_SET_TAPE_PARMS:
|
|||
|
case CMD_RETENSION:
|
|||
|
case CMD_ISSUE_DIAGNOSTIC:
|
|||
|
case CMD_ABORT:
|
|||
|
case CMD_DELETE_DRIVE:
|
|||
|
if (data_size) {
|
|||
|
ret_val = ERROR_ENCODE(ERR_INVALID_REQUEST, FCT_ID, 2);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case CMD_FORMAT:
|
|||
|
break;
|
|||
|
|
|||
|
case CMD_READ:
|
|||
|
case CMD_READ_RAW:
|
|||
|
case CMD_READ_HEROIC:
|
|||
|
case CMD_READ_VERIFY:
|
|||
|
case CMD_WRITE:
|
|||
|
case CMD_WRITE_DELETED_MARK:
|
|||
|
if (((DeviceIO *)&UserRequest->hdr)->number > 0x20) {
|
|||
|
ret_val = ERROR_ENCODE(ERR_INVALID_REQUEST, FCT_ID, 3);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (ret_val) {
|
|||
|
return q117ConvertStatus(DeviceObject, ret_val);
|
|||
|
}
|
|||
|
|
|||
|
if (data_size && !forcePending) {
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
if (!IsListEmpty(&topBufFreePool)) {
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
buf = (PBUF_POOL)RemoveHeadList(&topBufFreePool);
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
//
|
|||
|
// Validate user's buffer address is within users
|
|||
|
// address space
|
|||
|
//
|
|||
|
ret_val = ERR_NO_ERR;
|
|||
|
if ((((ULONG)(client_data) + (data_size)) < (ULONG)(client_data)) ||
|
|||
|
(((ULONG)(client_data) + (data_size)) >= (ULONG)MM_USER_PROBE_ADDRESS) || \
|
|||
|
((ULONG)(client_data) < (ULONG)MM_LOWEST_USER_ADDRESS)) {
|
|||
|
ret_val = ERROR_ENCODE(ERR_INVALID_ADDRESS, FCT_ID, 2);
|
|||
|
}
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: Allocated Buffer %x (%x %x)\n",
|
|||
|
buf, buf->BufferInfo.logical, buf->BufferInfo.physical));
|
|||
|
|
|||
|
if (UserRequest->prefix.flags == IoctlMemoryRead && !ret_val) {
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
RtlMoveMemory(
|
|||
|
buf->BufferInfo.logical,
|
|||
|
client_data,
|
|||
|
data_size);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
DbgPrint("WARNING: input buffer out of bounds\n");
|
|||
|
ret_val = ERROR_ENCODE(ERR_INVALID_ADDRESS, FCT_ID, 3);
|
|||
|
ntStatus = GetExceptionCode();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
forcePending = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
if (ret_val == ERR_NO_ERR) {
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
if (!IsListEmpty(&topIoFreePool)) {
|
|||
|
ior = (PIO_POOL)RemoveHeadList(&topIoFreePool);
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
//
|
|||
|
// Get the pertinent information from the user buffer
|
|||
|
//
|
|||
|
req_size = MIN(irpStack->Parameters.DeviceIoControl.InputBufferLength-sizeof(struct _KRNPREFIX),
|
|||
|
UserRequest->prefix.req_size);
|
|||
|
req_size = MIN(req_size, sizeof(ior->drv_request.x));
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: ior: %x request size : %x,%x,%x data:%x\n",ior, req_size,UserRequest->prefix.req_size,irpStack->Parameters.DeviceIoControl.InputBufferLength-sizeof(struct _KRNPREFIX),data_size));
|
|||
|
memcpy(&ior->drv_request, &UserRequest->hdr, req_size);
|
|||
|
|
|||
|
//
|
|||
|
// Save all of the necessary information
|
|||
|
//
|
|||
|
ior->DataSize = data_size;
|
|||
|
ior->Flags = UserRequest->prefix.flags;
|
|||
|
ior->InIoCompleteList = FALSE;
|
|||
|
ior->OriginalData = ior->drv_request.x.adi_hdr.cmd_buffer_ptr;
|
|||
|
ior->Irp = Irp;
|
|||
|
ior->BufferPool = buf;
|
|||
|
|
|||
|
if (buf) {
|
|||
|
|
|||
|
//
|
|||
|
// If we are using a buffer, fix up adi request with
|
|||
|
// our buffer
|
|||
|
//
|
|||
|
ior->drv_request.x.adi_hdr.cmd_buffer_ptr = buf->BufferInfo.logical;
|
|||
|
bufInfo = &buf->BufferInfo;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Request does not have a buffer, so zero the appropriate
|
|||
|
// fields
|
|||
|
//
|
|||
|
ior->drv_request.x.adi_hdr.cmd_buffer_ptr = NULL;
|
|||
|
bufInfo = NULL;
|
|||
|
}
|
|||
|
//
|
|||
|
// Now Try to queue the entry to the driver, or store
|
|||
|
// on pending queue.
|
|||
|
//
|
|||
|
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
|
|||
|
if (ret_val == ERR_NO_ERR) {
|
|||
|
|
|||
|
if (!forcePending || UserRequest->hdr.driver_cmd == CMD_ABORT) {
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: Queuing as %x\n",ior));
|
|||
|
|
|||
|
//
|
|||
|
// Put the buffer (if any) and the requst
|
|||
|
// on the active list
|
|||
|
//
|
|||
|
if (buf) {
|
|||
|
InsertTailList(&topBufActive, &buf->BufListEntry);
|
|||
|
}
|
|||
|
InsertTailList(&topIoActive, &ior->IoListEntry);
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
|
|||
|
//
|
|||
|
// Process command (command could be complete
|
|||
|
// before it returnes from the routine so
|
|||
|
// we can't look at the Irp from this point
|
|||
|
// forward).
|
|||
|
//
|
|||
|
if (UserRequest->hdr.driver_cmd == CMD_ABORT) {
|
|||
|
|
|||
|
//
|
|||
|
// Process aborts separately
|
|||
|
//
|
|||
|
ret_val = cms_SendAbortRequest(ior, context);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Process standard driver command
|
|||
|
//
|
|||
|
ret_val = q117ReqIO(&ior->drv_request, bufInfo, cms_IoCompletionRoutine, ior, context );
|
|||
|
}
|
|||
|
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
|
|||
|
if (ret_val == ERR_NO_ERR) {
|
|||
|
|
|||
|
//
|
|||
|
// Return IO_PENDING to caller
|
|||
|
//
|
|||
|
ret_val = ERROR_ENCODE(ERR_OP_PENDING_COMPLETION, FCT_ID, 1);
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_SendDriver setting pending\n"));
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Remove Entry from active list
|
|||
|
//
|
|||
|
RemoveEntryList(&ior->IoListEntry);
|
|||
|
if (buf)
|
|||
|
RemoveEntryList(&buf->BufListEntry);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (buf) {
|
|||
|
DbgPrint("ERROR: Puting item on pending queue when not need.\n");
|
|||
|
}
|
|||
|
InsertTailList(&topIoPending, &ior->IoListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Return IO_PENDING to caller
|
|||
|
//
|
|||
|
ret_val = ERROR_ENCODE(ERR_OP_PENDING_COMPLETION, FCT_ID, 2);
|
|||
|
IoMarkIrpPending(Irp);
|
|||
|
CheckedDump(DEBUG_LEVEL2,("cms_IoCtl: XXX_adi_SendDriver setting pending and adding to pending queue\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ret_val != ERR_NO_ERR && ERROR_DECODE(ret_val) != ERR_OP_PENDING_COMPLETION) {
|
|||
|
|
|||
|
DbgPrint("cms_IoCtl: XXX_adi_SendDriver had error\n");
|
|||
|
|
|||
|
//
|
|||
|
// Clean up
|
|||
|
//
|
|||
|
if (buf) {
|
|||
|
InsertHeadList(&topBufFreePool, &buf->BufListEntry);
|
|||
|
}
|
|||
|
InsertHeadList(&topIoFreePool, &ior->IoListEntry);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (buf) {
|
|||
|
InsertHeadList(&topBufFreePool, &buf->BufListEntry);
|
|||
|
}
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_IoCtl: XXX_adi_SendDriver no buffer available\n"));
|
|||
|
ret_val = ERROR_ENCODE(ERR_NO_MEMORY, FCT_ID, 1);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case XXX_adi_GetCmdResult:
|
|||
|
//
|
|||
|
// Update the user's buffer information, and queue any new requests
|
|||
|
//
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_GetCmdResult called\n"));
|
|||
|
outlen = cms_GetCmdResult(DeviceObject, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case XXX_adi_GetAsyncStatus:
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_GetAsyncStatus called\n"));
|
|||
|
outlen = cms_ProcessAsyncRequest(DeviceObject, Irp);
|
|||
|
break;
|
|||
|
|
|||
|
case XXX_adi_OpenDriver:
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_OpenDriver called\n"));
|
|||
|
adi_Opened = TRUE;
|
|||
|
cms_InitPools(context);
|
|||
|
break;
|
|||
|
case XXX_adi_CloseDriver:
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCtl: XXX_adi_CloseDriver called\n"));
|
|||
|
if (adi_Opened) {
|
|||
|
adi_Opened = FALSE;
|
|||
|
//q117ClearQueue(context);
|
|||
|
cms_ClearActive();
|
|||
|
ExFreePool(ioPool);
|
|||
|
ExFreePool(bufPool);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
Irp->IoStatus.Information = outlen;
|
|||
|
|
|||
|
return q117ConvertStatus(DeviceObject, ret_val);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We are now in the KDI's service thread's context, so
|
|||
|
// quickly update the user info and complete the request.
|
|||
|
// The less we do here the better since we could be in
|
|||
|
// an inter-segment gap and we could drop out of streaming.
|
|||
|
//
|
|||
|
NTSTATUS cms_IoCompletionRoutine (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_POOL IoPoolEntry
|
|||
|
)
|
|||
|
{
|
|||
|
IN PIRP myIrp;
|
|||
|
PQ117_CONTEXT context;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
dStatus status;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
KIRQL old_irql;
|
|||
|
|
|||
|
|
|||
|
ntStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
|
|||
|
myIrp = IoPoolEntry->Irp;
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(myIrp);
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_IoCompletionRoutine: Received %x irp:%x devobj: %x \n",IoPoolEntry,myIrp,DeviceObject));
|
|||
|
|
|||
|
//
|
|||
|
// I/O manager does not set DeviceObject, so we'll just do that now
|
|||
|
//
|
|||
|
DeviceObject = irpStack->DeviceObject;
|
|||
|
|
|||
|
context = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Clean up the lower level requests
|
|||
|
//
|
|||
|
if (IoPoolEntry->drv_request.x.adi_hdr.driver_cmd == CMD_ABORT) {
|
|||
|
//
|
|||
|
// signal successful abort
|
|||
|
//
|
|||
|
CheckedDump(DEBUG_LEVEL1,("CMD_ABORT Acknowledged\n"));
|
|||
|
IoPoolEntry->drv_request.x.adi_hdr.status = ERR_NO_ERR;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
status = q117WaitIO(&IoPoolEntry->drv_request, FALSE, context);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// remove entry from IoActive list
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, &old_irql);
|
|||
|
RemoveEntryList(&IoPoolEntry->IoListEntry);
|
|||
|
KeReleaseSpinLock(&poolLock, old_irql);
|
|||
|
|
|||
|
//
|
|||
|
// Let app unblock (sets done event in IRP) and adds IoPoolEntry
|
|||
|
// to the complete queue for processing by GetCmdResult.
|
|||
|
//
|
|||
|
cms_CompleteRequest(IoPoolEntry, myIrp, ntStatus, FALSE);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// GetCmdResult is processed in the User's Thread Context.
|
|||
|
// Therefore, we have access to all of the buffers without having
|
|||
|
// to lock them down.
|
|||
|
//
|
|||
|
cms_GetCmdResult(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
struct KernelRequest *userRequest;
|
|||
|
PQ117_CONTEXT context;
|
|||
|
IN PIO_POOL IoPoolEntry;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
PIO_POOL ioPending;
|
|||
|
PSEGMENT_BUFFER buf;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
KIRQL currentIrql;
|
|||
|
dStatus status;
|
|||
|
|
|||
|
//
|
|||
|
// Get our device context
|
|||
|
//
|
|||
|
context = DeviceObject->DeviceExtension;
|
|||
|
userRequest = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
ntStatus = STATUS_SUCCESS;
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now validate the user's request (so we don't panic the kernel
|
|||
|
// we need to use exception handling)
|
|||
|
//
|
|||
|
if (userRequest->prefix.Signature == CMSIOCTL_SIGNATURE) {
|
|||
|
IoPoolEntry = userRequest->prefix.InternalInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Now make sure user's data is correct
|
|||
|
//
|
|||
|
try {
|
|||
|
if (IoPoolEntry->Signature != CMSIOCTL_SIGNATURE) {
|
|||
|
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
DbgPrint("ERROR: signature on user request did not match\n");
|
|||
|
}
|
|||
|
if (IoPoolEntry->InIoCompleteList == FALSE) {
|
|||
|
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
DbgPrint("ERROR: buffer not in io complete list\n");
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
DbgPrint("ERROR: signature on user request did not match\n");
|
|||
|
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
}
|
|||
|
if (NT_SUCCESS(ntStatus)) {
|
|||
|
//
|
|||
|
// Make sure it's in the pending queue
|
|||
|
//
|
|||
|
// NOT NOW (needs coded)
|
|||
|
}
|
|||
|
} else {
|
|||
|
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(ntStatus)) {
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_GetCmdResult: Received %x irp:%x devobj: %x \n",IoPoolEntry,Irp,DeviceObject));
|
|||
|
|
|||
|
//
|
|||
|
// If we allocated a buffer, update the user with the buffer
|
|||
|
// contents, and either free the buffer, or queue a waiting
|
|||
|
// request that needs this buffer
|
|||
|
//
|
|||
|
if (IoPoolEntry->BufferPool) {
|
|||
|
|
|||
|
if (userRequest->prefix.flags == IoctlMemoryWrite && userRequest->hdr.cmd_buffer_ptr) {
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_GetCmdResult: Updating user buffer %x %x\n",
|
|||
|
IoPoolEntry->BufferPool, IoPoolEntry->BufferPool->BufferInfo.logical));
|
|||
|
|
|||
|
//
|
|||
|
// Make sure data is accessable to the user
|
|||
|
//
|
|||
|
status == ERR_NO_ERR;
|
|||
|
|
|||
|
try {
|
|||
|
//
|
|||
|
// Copy the contents of our DMA alligned buffer into
|
|||
|
// the user buffer
|
|||
|
//
|
|||
|
RtlMoveMemory(
|
|||
|
IoPoolEntry->OriginalData,
|
|||
|
IoPoolEntry->BufferPool->BufferInfo.logical,
|
|||
|
IoPoolEntry->DataSize);
|
|||
|
|
|||
|
}
|
|||
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
DbgPrint("WARNING: output buffer out of bounds\n");
|
|||
|
status = ERROR_ENCODE(ERR_INTERNAL_ERROR, FCT_ID, 3);
|
|||
|
ntStatus = GetExceptionCode();
|
|||
|
|
|||
|
}
|
|||
|
if (status) {
|
|||
|
//
|
|||
|
// Notify user of the failure.
|
|||
|
//
|
|||
|
userRequest->hdr.status = status;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we are protected from the completion routines
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
|
|||
|
if (IsListEmpty(&topIoPending)) {
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_GetCmdResult: freeing buffer pool %x\n",IoPoolEntry->BufferPool));
|
|||
|
//
|
|||
|
// remove buffer from the active queue and put on inactive list
|
|||
|
//
|
|||
|
|
|||
|
RemoveEntryList(&(IoPoolEntry->BufferPool->BufListEntry));
|
|||
|
InsertTailList(&topBufFreePool, &IoPoolEntry->BufferPool->BufListEntry);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Remove the pending I/O request and process
|
|||
|
//
|
|||
|
|
|||
|
ioPending = (void *)RemoveHeadList(&topIoPending);
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
CheckedDump(DEBUG_LEVEL2,("cms_GetCmdResult: re-using buffer pool %x for %x\n",IoPoolEntry->BufferPool, ioPending));
|
|||
|
|
|||
|
if (ioPending->DataSize) {
|
|||
|
|
|||
|
//
|
|||
|
// Just re-use the buffer we are currently processing
|
|||
|
//
|
|||
|
buf = &IoPoolEntry->BufferPool->BufferInfo;
|
|||
|
ioPending->drv_request.x.adi_hdr.cmd_buffer_ptr = buf->logical;
|
|||
|
ioPending->BufferPool = IoPoolEntry->BufferPool;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// It should not be possible to get here. Since items
|
|||
|
// are only stored in the pending list if there are
|
|||
|
// no buffers available. Since the pending list
|
|||
|
// is only processed by the User's thread, we should
|
|||
|
// not have a race condition on the pending queue.
|
|||
|
//
|
|||
|
DbgPrint("ERROR: topIoPending buffer does not have data??????\n");
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = ERR_NO_ERR;
|
|||
|
if (ioPending->Flags == IoctlMemoryRead) {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure data is accessable to the user
|
|||
|
//
|
|||
|
status = ERR_NO_ERR;
|
|||
|
try {
|
|||
|
|
|||
|
RtlMoveMemory(
|
|||
|
buf->logical,
|
|||
|
ioPending->OriginalData,
|
|||
|
ioPending->DataSize);
|
|||
|
|
|||
|
}
|
|||
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
DbgPrint("WARNING: input buffer out of bounds\n");
|
|||
|
|
|||
|
status = ERROR_ENCODE(ERR_INVALID_ADDRESS, FCT_ID, 4);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!status) {
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_GetCmdResult: Queuing as %x\n",ioPending));
|
|||
|
status = q117ReqIO(&ioPending->drv_request, buf, cms_IoCompletionRoutine, ioPending, context );
|
|||
|
}
|
|||
|
|
|||
|
if (status) {
|
|||
|
|
|||
|
//
|
|||
|
// Fail the request
|
|||
|
//
|
|||
|
ioPending->drv_request.x.adi_hdr.status = status;
|
|||
|
cms_CompleteRequest(ioPending, ioPending->Irp, STATUS_SUCCESS, FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// put item in active list for lower level driver
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
InsertTailList(&topIoActive,&ioPending->IoListEntry);
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now scan through, and queue all pending non-buffer requests
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
while (!IsListEmpty(&topIoPending)) {
|
|||
|
|
|||
|
ioPending = (void *)RemoveHeadList(&topIoPending);
|
|||
|
|
|||
|
if (ioPending->DataSize) {
|
|||
|
|
|||
|
//
|
|||
|
// We found a request we can't process, so put
|
|||
|
// it back and stop.
|
|||
|
//
|
|||
|
InsertHeadList(&topIoPending, &ioPending->IoListEntry);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We don't want to be at raised IRQL when we are
|
|||
|
// queueing the request (this must be done at PASSIVE_LEVEL)
|
|||
|
// So, release the spin lock, and queue the request
|
|||
|
//
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_GetCmdResult: Queuing as %x\n",ioPending));
|
|||
|
|
|||
|
status = q117ReqIO(&ioPending->drv_request, NULL, cms_IoCompletionRoutine, ioPending, context );
|
|||
|
if (status) {
|
|||
|
|
|||
|
//
|
|||
|
// Fail the request
|
|||
|
//
|
|||
|
ioPending->drv_request.x.adi_hdr.status = status;
|
|||
|
cms_CompleteRequest(ioPending, ioPending->Irp, STATUS_SUCCESS, FALSE);
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
//
|
|||
|
// Request is now in progress, so put it on the
|
|||
|
// Pending queue
|
|||
|
//
|
|||
|
InsertTailList(&topIoActive,&ioPending->IoListEntry);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update user info (belay completion routine (done by caller))
|
|||
|
//
|
|||
|
cms_CompleteRequest(IoPoolEntry, Irp, ntStatus, TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// put the item into the free pool
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Remove io request from topIoComplete queue
|
|||
|
//
|
|||
|
RemoveEntryList(&IoPoolEntry->IoListEntry);
|
|||
|
IoPoolEntry->InIoCompleteList = FALSE;
|
|||
|
|
|||
|
InsertTailList(&topIoFreePool, &IoPoolEntry->IoListEntry);
|
|||
|
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Setup return data, and status
|
|||
|
//
|
|||
|
return irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|||
|
}
|
|||
|
|
|||
|
void cms_CompleteRequest(
|
|||
|
PIO_POOL IoPoolEntry,
|
|||
|
IN PIRP Irp,
|
|||
|
NTSTATUS CompletionStatus,
|
|||
|
BOOLEAN belayCompletion
|
|||
|
)
|
|||
|
{
|
|||
|
struct KernelRequest *UserReply;
|
|||
|
KIRQL currentIrql;
|
|||
|
LONG len;
|
|||
|
PIO_STACK_LOCATION irpStack;
|
|||
|
|
|||
|
UserReply = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
len = MIN((irpStack->Parameters.DeviceIoControl.OutputBufferLength-
|
|||
|
sizeof(struct _KRNPREFIX)),
|
|||
|
sizeof(IoPoolEntry->drv_request.x));
|
|||
|
|
|||
|
//
|
|||
|
// set the buffer pointer back the way it was
|
|||
|
//
|
|||
|
IoPoolEntry->drv_request.x.adi_hdr.cmd_buffer_ptr = IoPoolEntry->OriginalData;
|
|||
|
|
|||
|
//
|
|||
|
// Save a link to the Irp that gets returned to the user
|
|||
|
// make sure this is an identifiable buffer;
|
|||
|
//
|
|||
|
UserReply->prefix.Signature = CMSIOCTL_SIGNATURE; // CMSI
|
|||
|
UserReply->prefix.InternalInfo = IoPoolEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Update the user's info
|
|||
|
//
|
|||
|
memcpy(&UserReply->hdr, &IoPoolEntry->drv_request.x, len);
|
|||
|
|
|||
|
//
|
|||
|
// Set the completion status
|
|||
|
//
|
|||
|
Irp->IoStatus.Status = CompletionStatus;
|
|||
|
Irp->IoStatus.Information = len;
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_CompleteRequest: Completed request %x %x status: %x len: %x\n",
|
|||
|
IoPoolEntry,
|
|||
|
UserReply->hdr.driver_cmd,
|
|||
|
UserReply->hdr.status, len));
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we are at dispatch level, and complete the request
|
|||
|
//
|
|||
|
if (!belayCompletion) {
|
|||
|
|
|||
|
//
|
|||
|
// Save the request on the Complete queue (tracking only)
|
|||
|
//
|
|||
|
CheckedDump(DEBUG_LEVEL1,("cms_CompleteRequest: adding to complete list\n"));
|
|||
|
IoPoolEntry->InIoCompleteList = TRUE;
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
InsertTailList(&topIoComplete, &IoPoolEntry->IoListEntry);
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
|
|||
|
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
|||
|
IoCompleteRequest(Irp, 0);
|
|||
|
KeLowerIrql(currentIrql);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void cms_ClearActive(void)
|
|||
|
{
|
|||
|
LIST_ENTRY *cur;
|
|||
|
|
|||
|
// clear out all active and pending requests
|
|||
|
while (!IsListEmpty(&topIoActive)) {
|
|||
|
cur = RemoveHeadList(&topIoActive);
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_ClearActive: WARNING: topIoActive is not empty (%x)\n",cur));
|
|||
|
InsertTailList(&topIoFreePool, cur);
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&topIoComplete)) {
|
|||
|
cur = RemoveHeadList(&topIoComplete);
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_ClearActive: WARNING: topIoComplete is not empty (%x)\n",cur));
|
|||
|
InsertTailList(&topIoFreePool, cur);
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&topBufActive)) {
|
|||
|
cur = RemoveHeadList(&topBufActive);
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_ClearActive: WARNING: topBufActive is not empty (%x)\n",cur));
|
|||
|
InsertTailList(&topBufFreePool, cur);
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(&topIoPending)) {
|
|||
|
cur = RemoveHeadList(&topIoPending);
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_ClearActive: WARNING: topIoPending is not empty (%x)\n",cur));
|
|||
|
InsertTailList(&topIoFreePool, cur);
|
|||
|
}
|
|||
|
}
|
|||
|
void cms_InitPools(
|
|||
|
PQ117_CONTEXT Context
|
|||
|
)
|
|||
|
{
|
|||
|
USHORT ind;
|
|||
|
PBUF_POOL curBufPool;
|
|||
|
PIO_POOL curIoPool;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize spin lock for io pools. This protects the list entries
|
|||
|
// from being corrupted.
|
|||
|
//
|
|||
|
KeInitializeSpinLock( &poolLock );
|
|||
|
|
|||
|
InitializeListHead(&topIoFreePool);
|
|||
|
InitializeListHead(&topIoPending);
|
|||
|
InitializeListHead(&topIoActive);
|
|||
|
InitializeListHead(&topBufFreePool);
|
|||
|
InitializeListHead(&topBufActive);
|
|||
|
InitializeListHead(&topIoPending);
|
|||
|
InitializeListHead(&topIoComplete);
|
|||
|
|
|||
|
/*
|
|||
|
* Initialize buffer pool
|
|||
|
*/
|
|||
|
bufPool = ExAllocatePool(
|
|||
|
NonPagedPool,
|
|||
|
sizeof(BUF_POOL)*Context->SegmentBuffersAvailable
|
|||
|
);
|
|||
|
|
|||
|
curBufPool = bufPool;
|
|||
|
for (ind=0;ind<Context->SegmentBuffersAvailable;++ind) {
|
|||
|
curBufPool->BufferInfo = Context->SegmentBuffer[ind];
|
|||
|
InsertTailList(&topBufFreePool, &curBufPool->BufListEntry);
|
|||
|
++curBufPool;
|
|||
|
}
|
|||
|
|
|||
|
ioPool = ExAllocatePool(
|
|||
|
NonPagedPool,
|
|||
|
sizeof(IO_POOL)*MAX_IO_PENDING
|
|||
|
);
|
|||
|
|
|||
|
curIoPool = ioPool;
|
|||
|
for (ind=0;ind<MAX_IO_PENDING;++ind) {
|
|||
|
curIoPool->Signature = CMSIOCTL_SIGNATURE;
|
|||
|
InsertTailList(&topIoFreePool, &curIoPool->IoListEntry);
|
|||
|
++curIoPool;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
//#include "include\private\kdi_pub.h"
|
|||
|
#include "q117kdi\include\kdiwhio.h"
|
|||
|
#include "q117kdi\include\kdiwpriv.h"
|
|||
|
#include "include\private\kdi_pub.h"
|
|||
|
#include "include\private\cqd_pub.h"
|
|||
|
#include "q117cd\include\cqd_defs.h"
|
|||
|
#include "q117cd\include\cqd_strc.h"
|
|||
|
#include "q117cd\include\cqd_hdr.h"
|
|||
|
cms_ProcessAsyncRequest(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
DeviceOp *userRequest;
|
|||
|
KdiContextPtr kdi_context;
|
|||
|
CqdContextPtr cqd_context;
|
|||
|
PQ117_CONTEXT context;
|
|||
|
|
|||
|
//
|
|||
|
// Get our device context
|
|||
|
//
|
|||
|
context = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// kdi's device context from it's device object
|
|||
|
//
|
|||
|
kdi_context = ((QICDeviceContextPtr)context->q117iDeviceObject->DeviceExtension)->kdi_context;
|
|||
|
|
|||
|
//
|
|||
|
// Get cqd's context from kdi's context
|
|||
|
//
|
|||
|
cqd_context = kdi_context->cqd_context;
|
|||
|
|
|||
|
userRequest = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
memcpy(&userRequest->operation_status, &cqd_context->operation_status, sizeof(OperationStatus));
|
|||
|
return sizeof(DeviceOp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Send the abort command to the driver. This request will be handled in the
|
|||
|
// same fashion as all other requests, except the ioPending queue will
|
|||
|
// be cleared
|
|||
|
//
|
|||
|
dStatus cms_SendAbortRequest(
|
|||
|
PIO_POOL IoPoolEntry,
|
|||
|
PQ117_CONTEXT Context
|
|||
|
)
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
KIRQL currentIrql;
|
|||
|
PIO_POOL ioPending;
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL1,("CMD_ABORT received, sending abort to lower level\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Clear any pending requests (mark them as aborted)
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
while (!IsListEmpty(&topIoPending)) {
|
|||
|
|
|||
|
ioPending = (void *)RemoveHeadList(&topIoPending);
|
|||
|
|
|||
|
//
|
|||
|
// Fail the request (request now moved to the IoComplete queue
|
|||
|
// and the user is notified)
|
|||
|
//
|
|||
|
ioPending->drv_request.x.adi_hdr.status = ERROR_ENCODE(ERR_ABORT, FCT_ID, 1);
|
|||
|
|
|||
|
// release the spin lock, complete the request, and re-aquire spinlock
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
cms_CompleteRequest(ioPending, ioPending->Irp, STATUS_SUCCESS, FALSE);
|
|||
|
KeAcquireSpinLock(&poolLock, ¤tIrql);
|
|||
|
}
|
|||
|
KeReleaseSpinLock(&poolLock, currentIrql);
|
|||
|
|
|||
|
//
|
|||
|
// set up an event (required by io subsystem)
|
|||
|
//
|
|||
|
KeInitializeEvent(
|
|||
|
&IoPoolEntry->drv_request.DoneEvent,
|
|||
|
NotificationEvent,
|
|||
|
FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Create an irp for the ABORT request
|
|||
|
//
|
|||
|
irp = IoBuildDeviceIoControlRequest(
|
|||
|
IOCTL_QIC117_CLEAR_QUEUE,
|
|||
|
Context->q117iDeviceObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
TRUE,
|
|||
|
&IoPoolEntry->drv_request.DoneEvent,
|
|||
|
&IoPoolEntry->drv_request.IoStatus
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
if (irp == NULL) {
|
|||
|
|
|||
|
CheckedDump(DEBUG_LEVEL4,("cms_SendAbortRequest: Can't allocate Irp\n"));
|
|||
|
//
|
|||
|
// If an Irp can't be allocated, then this call will
|
|||
|
// simply return. This will leave the queue frozen for
|
|||
|
// this device, which means it can no longer be accessed.
|
|||
|
//
|
|||
|
|
|||
|
return ERROR_ENCODE(ERR_PROGRAM_FAILURE, FCT_ID, 1);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the completion routine, and notify driver
|
|||
|
//
|
|||
|
IoSetCompletionRoutine(irp, cms_IoCompletionRoutine, IoPoolEntry, TRUE, TRUE, TRUE);
|
|||
|
|
|||
|
(VOID)IoCallDriver(Context->q117iDeviceObject, irp);
|
|||
|
|
|||
|
//
|
|||
|
// At this point the pending queue will be empty, and
|
|||
|
// the IoComplete queue will have all outstanding requests (as
|
|||
|
// they are acknowlegded by the driver.
|
|||
|
//
|
|||
|
return ERR_NO_ERR;
|
|||
|
}
|
|||
|
#endif
|