mirror of
https://github.com/reactos/reactos.git
synced 2024-06-30 01:42:30 +00:00
[CLASSPNP]: Add Windows Server 2003 DDK ClassPNP sample, under the license and terms of the Windows Server 2003 DDK.
[CDROM]: Add Windows Server 2003 DDK Cdrom Sample, under the license and terms of the Windows Server 2003 DDK. They both build and run fine, but PCIIDE(x) must be completed/enabled, and atapi must be rewritten to be WDM-compliant. svn path=/trunk/; revision=49171
This commit is contained in:
parent
8047296236
commit
73c1c7f232
7136
reactos/drivers/storage/class/cdrom_new/cdrom.c
Normal file
7136
reactos/drivers/storage/class/cdrom_new/cdrom.c
Normal file
File diff suppressed because it is too large
Load diff
823
reactos/drivers/storage/class/cdrom_new/cdrom.h
Normal file
823
reactos/drivers/storage/class/cdrom_new/cdrom.h
Normal file
|
@ -0,0 +1,823 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
cdromp.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Private header file for cdrom.sys. This contains private
|
||||
structure and function declarations as well as constant
|
||||
values which do not need to be exported.
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef __CDROMP_H__
|
||||
#define __CDROMP_H__
|
||||
|
||||
#include "ntddmmc.h"
|
||||
#include "trace.h"
|
||||
|
||||
extern CLASSPNP_SCAN_FOR_SPECIAL_INFO CdromHackItems[];
|
||||
|
||||
typedef enum {
|
||||
CdromDebugError = 0, // always printed
|
||||
CdromDebugWarning = 1, // set bit 0x00000001 in nt!kd_cdrom_mask
|
||||
CdromDebugTrace = 2, // set bit 0x00000002 in nt!kd_cdrom_mask
|
||||
CdromDebugInfo = 3, // set bit 0x00000004 in nt!kd_cdrom_mask
|
||||
#if 0
|
||||
CdromDebug = z, // set bit 0x00000000 in nt!kd_cdrom_mask
|
||||
CdromDebug = z, // set bit 0x00000000 in nt!kd_cdrom_mask
|
||||
CdromDebug = z, // set bit 0x00000000 in nt!kd_cdrom_mask
|
||||
CdromDebug = z, // set bit 0x00000000 in nt!kd_cdrom_mask
|
||||
#endif
|
||||
CdromDebugFeatures = 32 // set bit 0x80000000 in nt!kd_cdrom_mask
|
||||
};
|
||||
|
||||
#define CDROM_GET_CONFIGURATION_TIMEOUT (0x4)
|
||||
|
||||
#define CDROM_HACK_DEC_RRD (0x00000001)
|
||||
#define CDROM_HACK_FUJITSU_FMCD_10x (0x00000002)
|
||||
#define CDROM_HACK_HITACHI_1750 (0x00000004)
|
||||
#define CDROM_HACK_HITACHI_GD_2000 (0x00000008)
|
||||
#define CDROM_HACK_TOSHIBA_SD_W1101 (0x00000010)
|
||||
#define CDROM_HACK_TOSHIBA_XM_3xx (0x00000020)
|
||||
#define CDROM_HACK_NEC_CDDA (0x00000040)
|
||||
#define CDROM_HACK_PLEXTOR_CDDA (0x00000080)
|
||||
#define CDROM_HACK_BAD_GET_CONFIG_SUPPORT (0x00000100)
|
||||
#define CDROM_HACK_FORCE_READ_CD_DETECTION (0x00000200)
|
||||
#define CDROM_HACK_READ_CD_SUPPORTED (0x00000400)
|
||||
#define CDROM_HACK_LOCKED_PAGES (0x80000000) // not a valid flag to save
|
||||
|
||||
#define CDROM_HACK_VALID_FLAGS (0x000007ff)
|
||||
#define CDROM_HACK_INVALID_FLAGS (~CDROM_HACK_VALID_FLAGS)
|
||||
|
||||
|
||||
typedef struct _XA_CONTEXT {
|
||||
|
||||
//
|
||||
// Pointer to the device object.
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
||||
//
|
||||
// Pointer to the original request when
|
||||
// a mode select must be sent.
|
||||
//
|
||||
|
||||
PIRP OriginalRequest;
|
||||
|
||||
//
|
||||
// Pointer to the mode select srb.
|
||||
//
|
||||
|
||||
PSCSI_REQUEST_BLOCK Srb;
|
||||
} XA_CONTEXT, *PXA_CONTEXT;
|
||||
|
||||
typedef struct _ERROR_RECOVERY_DATA {
|
||||
MODE_PARAMETER_HEADER Header;
|
||||
MODE_PARAMETER_BLOCK BlockDescriptor;
|
||||
MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
|
||||
} ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA;
|
||||
|
||||
typedef struct _ERROR_RECOVERY_DATA10 {
|
||||
MODE_PARAMETER_HEADER10 Header10;
|
||||
MODE_PARAMETER_BLOCK BlockDescriptor10;
|
||||
MODE_READ_RECOVERY_PAGE ReadRecoveryPage10;
|
||||
} ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
|
||||
|
||||
//
|
||||
// CdRom specific addition to device extension.
|
||||
//
|
||||
|
||||
typedef struct _CDROM_DRIVER_EXTENSION {
|
||||
ULONG InterlockedCdRomCounter;
|
||||
PVOID Reserved[3];
|
||||
} CDROM_DRIVER_EXTENSION, *PCDROM_DRIVER_EXTENSION;
|
||||
|
||||
#define CdromMmcUpdateComplete 0
|
||||
#define CdromMmcUpdateRequired 1
|
||||
#define CdromMmcUpdateStarted 2
|
||||
|
||||
typedef struct _CDROM_MMC_EXTENSION {
|
||||
|
||||
ULONG IsMmc; // allow quick checks
|
||||
ULONG WriteAllowed;
|
||||
|
||||
LONG UpdateState;
|
||||
|
||||
SLIST_HEADER DelayedIrps; // irps delayed due to
|
||||
KSPIN_LOCK DelayedLock; // lock for delayed irps
|
||||
|
||||
PIO_WORKITEM CapabilitiesWorkItem;
|
||||
PIRP CapabilitiesIrp;
|
||||
PMDL CapabilitiesMdl;
|
||||
PGET_CONFIGURATION_HEADER CapabilitiesBuffer;
|
||||
ULONG CapabilitiesBufferSize;
|
||||
KEVENT CapabilitiesEvent;
|
||||
SCSI_REQUEST_BLOCK CapabilitiesSrb;
|
||||
|
||||
} CDROM_MMC_EXTENSION, *PCDROM_MMC_EXTENSION;
|
||||
|
||||
|
||||
#define CDROM_DRIVER_EXTENSION_ID CdRomAddDevice
|
||||
|
||||
typedef struct _CDROM_DATA {
|
||||
|
||||
//
|
||||
// Pointer to the cdrom driver extension
|
||||
//
|
||||
|
||||
PCDROM_DRIVER_EXTENSION DriverExtension;
|
||||
|
||||
|
||||
//
|
||||
// These bits allow detection of when to requery the
|
||||
// drive's capabilities.
|
||||
//
|
||||
|
||||
CDROM_MMC_EXTENSION Mmc;
|
||||
|
||||
//
|
||||
// hack flags for ScanForSpecial routines
|
||||
//
|
||||
|
||||
ULONG_PTR HackFlags;
|
||||
|
||||
//
|
||||
// the error handling routines need to be per-device,
|
||||
// not per-driver....
|
||||
//
|
||||
|
||||
PCLASS_ERROR ErrorHandler;
|
||||
|
||||
//
|
||||
// Indicates whether an audio play operation
|
||||
// is currently being performed.
|
||||
// Only thing this does is prevent reads and
|
||||
// toc requests while playing audio.
|
||||
//
|
||||
|
||||
BOOLEAN PlayActive;
|
||||
|
||||
//
|
||||
// Indicates whether the blocksize used for user data
|
||||
// is 2048 or 2352.
|
||||
//
|
||||
|
||||
BOOLEAN RawAccess;
|
||||
|
||||
//
|
||||
// Indicates that this is a DEC RRD cdrom.
|
||||
// This drive requires software to fix responses
|
||||
// from the faulty firmware
|
||||
//
|
||||
|
||||
BOOLEAN IsDecRrd;
|
||||
|
||||
//
|
||||
// This points to an irp which needs to be delayed for a bit before a
|
||||
// retry can be attempted. The interval counter is set by the deferring
|
||||
// routine and will be decremented to zero in the tick handler. Once
|
||||
// the counter goes to zero the irp will be issued again.
|
||||
// DelayedRetryResend controls whether the irp is resent to the lower
|
||||
// driver (TRUE) or reissued into the startio routine (FALSE)
|
||||
//
|
||||
|
||||
BOOLEAN DelayedRetryResend;
|
||||
|
||||
PIRP DelayedRetryIrp;
|
||||
|
||||
ULONG DelayedRetryInterval;
|
||||
|
||||
KSPIN_LOCK DelayedRetrySpinLock;
|
||||
|
||||
//
|
||||
// indicate we need to pick a default dvd region
|
||||
// for the user if we can
|
||||
//
|
||||
|
||||
ULONG PickDvdRegion;
|
||||
|
||||
//
|
||||
// The interface strings registered for this device.
|
||||
//
|
||||
|
||||
UNICODE_STRING CdromInterfaceString;
|
||||
UNICODE_STRING VolumeInterfaceString;
|
||||
|
||||
//
|
||||
// The well known name link for this device.
|
||||
//
|
||||
|
||||
UNICODE_STRING WellKnownName;
|
||||
|
||||
//
|
||||
// Indicates whether 6 or 10 bytes mode sense/select
|
||||
// should be used
|
||||
//
|
||||
|
||||
ULONG XAFlags;
|
||||
|
||||
//
|
||||
// keep track of what type of DVD device we are
|
||||
//
|
||||
|
||||
BOOLEAN DvdRpc0Device;
|
||||
BOOLEAN DvdRpc0LicenseFailure;
|
||||
UCHAR Rpc0SystemRegion; // bitmask, one means prevent play
|
||||
UCHAR Rpc0SystemRegionResetCount;
|
||||
|
||||
ULONG Rpc0RetryRegistryCallback; // one until initial region choosen
|
||||
|
||||
KMUTEX Rpc0RegionMutex;
|
||||
|
||||
//
|
||||
// Storage for the error recovery page. This is used
|
||||
// as an easy method to switch block sizes.
|
||||
//
|
||||
// NOTE - doubly unnamed structs just aren't very clean looking code - this
|
||||
// should get cleaned up at some point in the future.
|
||||
//
|
||||
|
||||
union {
|
||||
ERROR_RECOVERY_DATA;
|
||||
ERROR_RECOVERY_DATA10;
|
||||
};
|
||||
|
||||
} CDROM_DATA, *PCDROM_DATA;
|
||||
|
||||
#define DEVICE_EXTENSION_SIZE sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(CDROM_DATA)
|
||||
#define SCSI_CDROM_TIMEOUT 10
|
||||
#define SCSI_CHANGER_BONUS_TIMEOUT 10
|
||||
#define HITACHI_MODE_DATA_SIZE 12
|
||||
#define MODE_DATA_SIZE 64
|
||||
#define RAW_SECTOR_SIZE 2352
|
||||
#define COOKED_SECTOR_SIZE 2048
|
||||
#define CDROM_SRB_LIST_SIZE 4
|
||||
|
||||
#define PLAY_ACTIVE(x) (((PCDROM_DATA)(x->CommonExtension.DriverData))->PlayActive)
|
||||
|
||||
#define MSF_TO_LBA(Minutes,Seconds,Frames) \
|
||||
(ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
|
||||
|
||||
#define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
|
||||
{ \
|
||||
(Minutes) = (UCHAR)(Lba / (60 * 75)); \
|
||||
(Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
|
||||
(Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
|
||||
}
|
||||
|
||||
#define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
|
||||
|
||||
//
|
||||
// Define flags for XA, CDDA, and Mode Select/Sense
|
||||
//
|
||||
|
||||
#define XA_USE_6_BYTE 0x01
|
||||
#define XA_USE_10_BYTE 0x02
|
||||
|
||||
#define XA_NOT_SUPPORTED 0x10
|
||||
#define XA_USE_READ_CD 0x20
|
||||
#define XA_PLEXTOR_CDDA 0x40
|
||||
#define XA_NEC_CDDA 0x80
|
||||
|
||||
//
|
||||
// Sector types for READ_CD
|
||||
//
|
||||
|
||||
#define ANY_SECTOR 0
|
||||
#define CD_DA_SECTOR 1
|
||||
#define YELLOW_MODE1_SECTOR 2
|
||||
#define YELLOW_MODE2_SECTOR 3
|
||||
#define FORM2_MODE1_SECTOR 4
|
||||
#define FORM2_MODE2_SECTOR 5
|
||||
|
||||
#define MAX_COPY_PROTECT_AGID 4
|
||||
|
||||
#ifdef ExAllocatePool
|
||||
#undef ExAllocatePool
|
||||
#define ExAllocatePool #assert(FALSE)
|
||||
#endif
|
||||
|
||||
#define CDROM_TAG_GET_CONFIG 'cCcS' // "ScCc" - ioctl GET_CONFIGURATION
|
||||
#define CDROM_TAG_DC_EVENT 'ECcS' // "ScCE" - device control synch event
|
||||
#define CDROM_TAG_FEATURE 'FCcS' // "ScCF" - allocated by CdRomGetConfiguration(), free'd by caller
|
||||
#define CDROM_TAG_DISK_GEOM 'GCcS' // "ScCG" - disk geometry buffer
|
||||
#define CDROM_TAG_HITACHI_ERROR 'HCcS' // "ScCH" - hitachi error buffer
|
||||
#define CDROM_TAG_SENSE_INFO 'ICcS' // "ScCI" - sense info buffers
|
||||
#define CDROM_TAG_POWER_IRP 'iCcS' // "ScCi" - irp for power request
|
||||
#define CDROM_TAG_SRB 'SCcS' // "ScCS" - srb allocation
|
||||
#define CDROM_TAG_STRINGS 'sCcS' // "ScCs" - assorted string data
|
||||
#define CDROM_TAG_MODE_DATA 'MCcS' // "ScCM" - mode data buffer
|
||||
#define CDROM_TAG_READ_CAP 'PCcS' // "ScCP" - read capacity buffer
|
||||
#define CDROM_TAG_PLAY_ACTIVE 'pCcS' // "ScCp" - play active checks
|
||||
#define CDROM_TAG_SUB_Q 'QCcS' // "ScCQ" - read sub q buffer
|
||||
#define CDROM_TAG_RAW 'RCcS' // "ScCR" - raw mode read buffer
|
||||
#define CDROM_TAG_TOC 'TCcS' // "ScCT" - read toc buffer
|
||||
#define CDROM_TAG_TOSHIBA_ERROR 'tCcS' // "ScCt" - toshiba error buffer
|
||||
#define CDROM_TAG_DEC_ERROR 'dCcS' // "ScCt" - DEC error buffer
|
||||
#define CDROM_TAG_UPDATE_CAP 'UCcS' // "ScCU" - update capacity path
|
||||
#define CDROM_TAG_VOLUME 'VCcS' // "ScCV" - volume control buffer
|
||||
#define CDROM_TAG_VOLUME_INT 'vCcS' // "ScCv" - volume control buffer
|
||||
|
||||
#define DVD_TAG_READ_STRUCTURE 'SVcS' // "ScVS" - used for dvd structure reads
|
||||
#define DVD_TAG_READ_KEY 'kVcS' // "ScVk" - read buffer for dvd key
|
||||
#define DVD_TAG_SEND_KEY 'KVcS' // "ScVK" - write buffer for dvd key
|
||||
#define DVD_TAG_RPC2_CHECK 'sVcS' // "ScVs" - read buffer for dvd/rpc2 check
|
||||
#define DVD_TAG_DVD_REGION 'tVcS' // "ScVt" - read buffer for rpc2 check
|
||||
#define DVD_TAG_SECURITY 'XVcS' // "ScVX" - security descriptor
|
||||
|
||||
|
||||
#define CDROM_SUBKEY_NAME (L"CdRom") // store new settings here
|
||||
#define CDROM_READ_CD_NAME (L"ReadCD") // READ_CD support previously detected
|
||||
#define CDROM_NON_MMC_DRIVE_NAME (L"NonMmc") // MMC commands hang
|
||||
//
|
||||
// DVD Registry Value Names for RPC0 Device
|
||||
//
|
||||
#define DVD_DEFAULT_REGION (L"DefaultDvdRegion") // this is init. by the dvd class installer
|
||||
#define DVD_CURRENT_REGION (L"DvdR")
|
||||
#define DVD_REGION_RESET_COUNT (L"DvdRCnt")
|
||||
#define DVD_MAX_REGION_RESET_COUNT 2
|
||||
#define DVD_MAX_REGION 8
|
||||
|
||||
|
||||
|
||||
#define BAIL_OUT(Irp) \
|
||||
DebugPrint((2, "Cdrom: [%p] Bailing with status " \
|
||||
" %lx at line %x file %s\n", \
|
||||
(Irp), (Irp)->IoStatus.Status, \
|
||||
__LINE__, __FILE__))
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine grabs an extra remove lock using a local variable
|
||||
for a unique tag. It then completes the irp in question, and
|
||||
the just-acquired removelock guarantees that it is still safe
|
||||
to call IoStartNextPacket(). When that finishes, we release
|
||||
the newly acquired RemoveLock and return.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object for the StartIo queue
|
||||
Irp - the request we are completing
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
Notes:
|
||||
|
||||
This is implemented as an inline function to allow the compiler
|
||||
to optimize this as either a function call or as actual inline code.
|
||||
|
||||
This routine will not work with IoXxxRemoveLock() calls, as the
|
||||
behavior is different. ClassXxxRemoveLock() calls succeed until
|
||||
the remove has completed, while IoXxxRemoveLock() calls fail as
|
||||
soon as the call to IoReleaseRemoveLockAndWait() has been called.
|
||||
The Class version allows this routine to work in a safe manner.
|
||||
|
||||
replaces the following two lines:
|
||||
IoStartNextPacket(DeviceObject, FALSE);
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
and raises irql as needed to call IoStartNextPacket()
|
||||
|
||||
--*/
|
||||
static inline
|
||||
VOID
|
||||
CdRomCompleteIrpAndStartNextPacketSafely(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
UCHAR uniqueAddress;
|
||||
KIRQL oldIrql = KeGetCurrentIrql();
|
||||
|
||||
ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, IO_CD_ROM_INCREMENT);
|
||||
|
||||
if (oldIrql > DISPATCH_LEVEL) {
|
||||
ASSERT(!"Cannot call IoStartNextPacket at raised IRQL!");
|
||||
} else if (oldIrql < DISPATCH_LEVEL) {
|
||||
KeRaiseIrqlToDpcLevel();
|
||||
} else { // (oldIrql == DISPATCH_LEVEL)
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
IoStartNextPacket(DeviceObject, FALSE);
|
||||
|
||||
if (oldIrql > DISPATCH_LEVEL) {
|
||||
ASSERT(!"Cannot call IoStartNextPacket at raised IRQL!");
|
||||
} else if (oldIrql < DISPATCH_LEVEL) {
|
||||
KeLowerIrql(oldIrql);
|
||||
} else { // (oldIrql == DISPATCH_LEVEL)
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
CdRomDeviceControlDvdReadStructure(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP OriginalIrp,
|
||||
IN PIRP NewIrp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomDeviceControlDvdEndSession(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP OriginalIrp,
|
||||
IN PIRP NewIrp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomDeviceControlDvdStartSessionReadKey(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP OriginalIrp,
|
||||
IN PIRP NewIrp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomDeviceControlDvdSendKey(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP OriginalIrp,
|
||||
IN PIRP NewIrp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomUnload(
|
||||
IN PDRIVER_OBJECT DriverObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomAddDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT Pdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomOpenClose(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomReadWriteVerification(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomSwitchMode(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG SectorSize,
|
||||
IN PIRP OriginalRequest
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomDeviceControlDispatch(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomDeviceControlCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomSetVolumeIntermediateCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomSwitchModeCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomXACompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomClassIoctlCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomStartIo(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomTickHandler(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomUpdateCapacity(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
|
||||
IN PIRP IrpToComplete,
|
||||
IN OPTIONAL PKEVENT IoctlEvent
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomCreateDeviceObject(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT Pdo
|
||||
);
|
||||
|
||||
VOID
|
||||
ScanForSpecialHandler(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
ULONG_PTR HackFlags
|
||||
);
|
||||
|
||||
VOID
|
||||
ScanForSpecial(
|
||||
PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
CdRomIsPlayActive(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomErrorHandler(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
NTSTATUS *Status,
|
||||
BOOLEAN *Retry
|
||||
);
|
||||
|
||||
VOID
|
||||
HitachiProcessErrorGD2000(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
NTSTATUS *Status,
|
||||
BOOLEAN *Retry
|
||||
);
|
||||
|
||||
VOID
|
||||
HitachiProcessError(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
NTSTATUS *Status,
|
||||
BOOLEAN *Retry
|
||||
);
|
||||
|
||||
VOID
|
||||
ToshibaProcessError(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
NTSTATUS *Status,
|
||||
BOOLEAN *Retry
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ToshibaProcessErrorCompletion(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp,
|
||||
PVOID Context
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomCreateNamedEvent(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
|
||||
IN ULONG DeviceNumber
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomInitDevice(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomStartDevice(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomStopDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN UCHAR Type
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomRemoveDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN UCHAR Type
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomDvdEndAllSessionsCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomDvdReadDiskKeyCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
DEVICE_TYPE
|
||||
CdRomGetDeviceType(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomCreateWellKnownName(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomDeleteWellKnownName(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomGetDeviceParameter (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PWSTR ParameterName,
|
||||
IN OUT PULONG ParameterValue
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomSetDeviceParameter (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PWSTR ParameterName,
|
||||
IN ULONG ParameterValue
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomPickDvdRegion (
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomRetryRequest(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PIRP Irp,
|
||||
IN ULONG Delay,
|
||||
IN BOOLEAN ResendIrp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomRerunRequest(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN OPTIONAL PIRP Irp,
|
||||
IN BOOLEAN ResendIrp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomGetRpc0Settings(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomSetRpc0Settings(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN UCHAR NewRegion
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomShutdownFlush(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VOID
|
||||
CdRomIsDeviceMmcDevice(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
OUT PBOOLEAN IsMmc
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomMmcErrorHandler(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PSCSI_REQUEST_BLOCK Srb,
|
||||
OUT PNTSTATUS Status,
|
||||
OUT PBOOLEAN Retry
|
||||
);
|
||||
|
||||
PVOID
|
||||
CdRomFindFeaturePage(
|
||||
IN PGET_CONFIGURATION_HEADER FeatureBuffer,
|
||||
IN ULONG Length,
|
||||
IN FEATURE_NUMBER Feature
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomGetConfiguration(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
OUT PGET_CONFIGURATION_HEADER *Buffer,
|
||||
OUT PULONG BytesReturned,
|
||||
IN FEATURE_NUMBER StartingFeature,
|
||||
IN ULONG RequestedType
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomUpdateMmcDriveCapabilities(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PVOID Context // RESERVED == NULL
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomFindProfileInProfiles(
|
||||
IN PFEATURE_DATA_PROFILE_LIST ProfileHeader,
|
||||
IN FEATURE_PROFILE_TYPE ProfileToFind,
|
||||
OUT PBOOLEAN Exists
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomAllocateMmcResources(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomDeAllocateMmcResources(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
VOID
|
||||
CdromFakePartitionInfo(
|
||||
IN PCOMMON_DEVICE_EXTENSION CommonExtension,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRomInterpretReadCapacity(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PREAD_CAPACITY_DATA ReadCapacityBuffer
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
CdRomShutdownFlushCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PIRP Context
|
||||
);
|
||||
|
||||
VOID
|
||||
CdRompFlushDelayedList(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PCDROM_MMC_EXTENSION MmcData,
|
||||
IN NTSTATUS Status,
|
||||
IN BOOLEAN CalledFromWorkItem
|
||||
);
|
||||
|
||||
#endif // __CDROMP_H__
|
||||
|
||||
|
344
reactos/drivers/storage/class/cdrom_new/cdrom.inf
Normal file
344
reactos/drivers/storage/class/cdrom_new/cdrom.inf
Normal file
|
@ -0,0 +1,344 @@
|
|||
;
|
||||
; cdrom.inf -- INF file for installing CDROM drives
|
||||
;
|
||||
; Copyright (c) 1993-1997, Microsoft Corporation
|
||||
|
||||
[Version]
|
||||
Signature="$WINDOWS NT$"
|
||||
Class=CDROM
|
||||
ClassGuid={4D36E965-E325-11CE-BFC1-08002BE10318}
|
||||
Provider=%DDK_SAMPLE%
|
||||
DriverVer=03/15/2001,5.1.2462.0
|
||||
CatalogFile=ddk_sample.cat
|
||||
|
||||
[cdaudio_copyfiles]
|
||||
cdaudio.sys
|
||||
|
||||
[changer_copyfiles]
|
||||
changer.sys
|
||||
|
||||
[cdrom_copyfiles]
|
||||
cdrom.sys
|
||||
redbook.sys
|
||||
|
||||
[storprop_copyfiles]
|
||||
storprop.dll
|
||||
|
||||
[DestinationDirs]
|
||||
cdrom_copyfiles = 12
|
||||
cdaudio_copyfiles = 12
|
||||
changer_copyfiles = 12
|
||||
storprop_copyfiles = 11
|
||||
|
||||
[Manufacturer]
|
||||
%ATAPI_CHGR% = atapi_chgr
|
||||
%CHINON% = chinon_cdrom
|
||||
%DENON% = denon_cdrom
|
||||
%FUJITSU% = fujitsu_cdrom
|
||||
%HITACHI% = hitachi_cdrom
|
||||
%HP% = hp_cdrom
|
||||
%MITSUMI% = mitsumi_cdrom
|
||||
%NEC% = nec_cdrom
|
||||
%OTI% = oti_cdrom
|
||||
%PIONEER% = pioneer_cdrom
|
||||
%WEARNES% = wearnes_cdrom
|
||||
%GenManufacturer% = cdrom_device
|
||||
|
||||
[atapi_chgr]
|
||||
%NecChanger_devdesc% = changer_install,IDE\CdRomNEC_CD-ROM_DRIVE:251____________________
|
||||
%NecChanger_devdesc% = changer_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:251
|
||||
%NecChanger_devdesc% = changer_install,IDE\CdRomNEC_CD-ROM_DRIVE:253____________________
|
||||
%NecChanger_devdesc% = changer_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:253
|
||||
%NecChanger_devdesc% = changer_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:252
|
||||
%AlpsChanger_devdesc% = changer_install,IDE\CdRomALPS_DC544______________________________
|
||||
%TorisanChanger_devdesc% = changer_install,IDE\CdRomTORiSAN_CD-ROM_CDR-C3G__________________
|
||||
%TorisanChanger_devdesc% = changer_install,SCSI\CdRomTORiSAN_CD-ROM_CDR-C3G__
|
||||
%TorisanChanger_devdesc% = changer_install,IDE\CdRomTORiSAN_CD-ROM_CDR_C36__________________
|
||||
%PanasonicChanger_devdesc% = changer_install,IDE\CdRomMATSHITA_RD-DRC001-M____________________
|
||||
%PanasonicChanger_devdesc% = changer_install,IDE\CdRomMATSHITA_RD-DRC002-S____________________
|
||||
%PanasonicChanger_devdesc% = changer_install,SCSI\CdRomNAKAMICHMJ-5.16_________
|
||||
|
||||
[fujitsu_cdrom]
|
||||
%fujitsu_devdesc% = cdaudio_install,SCSI\CdRomFUJITSU_
|
||||
|
||||
[chinon_cdrom]
|
||||
%chinon_devdesc% = cdaudio_install,SCSI\CdRomCHINON__
|
||||
|
||||
[denon_cdrom]
|
||||
%denon_devdesc% = cdaudio_install,SCSI\CdRomDENON___
|
||||
|
||||
[hp_cdrom]
|
||||
%hp_devdesc% = cdaudio_install,SCSI\CdRomHP______C4324/C4325_____
|
||||
|
||||
[hitachi_cdrom]
|
||||
%hitachi_devdesc% = cdaudio_install,SCSI\CdRomHITACHI_CDR-3650/1650S__
|
||||
%hitachi_devdesc% = cdaudio_install,SCSI\CdRomHITACHI_CDR-1750S_______
|
||||
|
||||
[mitsumi_cdrom]
|
||||
%Mitsumi_cdrom_devdesc% = mitsumi_install,IDE\CdRomMITSUMI_CD-ROM________!A________________
|
||||
|
||||
[nec_cdrom]
|
||||
%NecMultispin_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:38_
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE_4_M
|
||||
%NecIntersect_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:80_
|
||||
%NecIntersect_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:82_
|
||||
%NecIntersect_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:83_
|
||||
%NecIntersect_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:84_
|
||||
%NecMultispin_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:841
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:400
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:401
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:500
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:501
|
||||
%NecOem_devdesc% = cdaudio_install,SCSI\CdRomNEC_____CD-ROM_DRIVE:900
|
||||
|
||||
[oti_cdrom]
|
||||
%oti_devdesc% = cdaudio_install,IDE\CdRomOTI_DOLPHIN_8001_IDE____________________
|
||||
|
||||
[pioneer_cdrom]
|
||||
%pioneer_devdesc% = cdaudio_install,SCSI\CdRomPIONEER_CD-ROM_DRM-600__
|
||||
%pioneer_devdesc% = cdaudio_install,SCSI\CdRomPIONEER_CD-ROM_DRM-600x_
|
||||
|
||||
[wearnes_cdrom]
|
||||
%wearnes_devdesc% = cdaudio_install,IDE\CdRomWEARNES_
|
||||
|
||||
|
||||
[cdrom_device]
|
||||
;;
|
||||
;; if none of the above matched, then only cdrom.sys is required for this drive
|
||||
;;
|
||||
%gencdrom_devdesc% = cdrom_install,SCSI\WormPIONEER_CD-WO_DR-R504X__
|
||||
%gencdrom_devdesc% = cdrom_install,SCSI\WormSONY____CD-R___CDU920S__
|
||||
%gencdrom_devdesc% = cdrom_install,SCSI\WormSONY____CD-R___CDU948S__
|
||||
%gencdrom_devdesc% = cdrom_install,GenCdRom
|
||||
|
||||
;;
|
||||
;; Use to add filter drivers for the device
|
||||
;;
|
||||
|
||||
[cdaudio_addreg]
|
||||
HKR,,"UpperFilters",0x00010008,"cdaudio"
|
||||
|
||||
[changer_addreg]
|
||||
HKR,,"UpperFilters",0x00010008,"changer"
|
||||
|
||||
[mitsumi_addreg]
|
||||
HKR,,"FriendlyName",,%Mitsumi_Generic_FriendlyName%
|
||||
|
||||
;;
|
||||
;; more addreg sections
|
||||
;;
|
||||
|
||||
[dvd_property_provider_AddReg]
|
||||
HKR,,EnumPropPages32,,"storprop.dll,DvdPropPageProvider"
|
||||
|
||||
[autorun_addreg]
|
||||
;;
|
||||
;; The AutoRunAlwaysDisable key is only for use when the hardware cannot
|
||||
;; accepts TEST_UNIT_READY commands. Disabling 'AutoRun' or including
|
||||
;; devices in this list will prevent removable media services from being
|
||||
;; able to properly handle these devices.
|
||||
;;
|
||||
HKLM,"System\CurrentControlSet\Services\cdrom","AutoRun",0x00010003,1
|
||||
HKLM,"System\CurrentControlSet\Services\cdrom","AutoRunAlwaysDisable",\
|
||||
0x00010000,\
|
||||
"NEC MBR-7 ", \
|
||||
"NEC MBR-7.4 ", \
|
||||
"PIONEER CHANGR DRM-1804X", \
|
||||
"PIONEER CD-ROM DRM-6324X", \
|
||||
"PIONEER CD-ROM DRM-624X ", \
|
||||
"TORiSAN CD-ROM CDR_C36"
|
||||
|
||||
;;
|
||||
;; Use to disable synchronous transfers to this device. Sync transfers will
|
||||
;; always be turned off by default in this INF for any cdrom-type device
|
||||
;;
|
||||
[nosync_addreg]
|
||||
HKR,,"DefaultRequestFlags",0x00010001,8
|
||||
|
||||
;;
|
||||
;; Installation section for cdaudio. Sets cdrom as the service and adds
|
||||
;; cdaudio as an upper filter
|
||||
;;
|
||||
|
||||
[cdaudio_install]
|
||||
CopyFiles=cdaudio_copyfiles,cdrom_copyfiles,storprop_copyfiles
|
||||
AddReg=dvd_property_provider_AddReg
|
||||
|
||||
[cdaudio_install.HW]
|
||||
AddReg=nosync_addreg,cdaudio_addreg
|
||||
|
||||
[cdaudio_install.Services]
|
||||
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
|
||||
AddService=cdaudio,,cdaudio_ServiceInstallSection
|
||||
AddService=redbook,,redbook_ServiceInstallSection,redbook_InstallEventLogSection
|
||||
|
||||
;;
|
||||
;; Installation section for changer
|
||||
;;
|
||||
|
||||
[changer_install]
|
||||
CopyFiles=changer_copyfiles,cdrom_copyfiles,storprop_copyfiles
|
||||
AddReg=dvd_property_provider_AddReg
|
||||
|
||||
[changer_install.HW]
|
||||
AddReg=changer_addreg
|
||||
|
||||
[changer_install.Services]
|
||||
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
|
||||
AddService=changer,,changer_ServiceInstallSection
|
||||
AddService=redbook,,redbook_ServiceInstallSection,redbook_InstallEventLogSection
|
||||
|
||||
;;
|
||||
;; Installation section for mitsumi.
|
||||
;;
|
||||
|
||||
[mitsumi_install]
|
||||
CopyFiles=cdrom_copyfiles,storprop_copyfiles
|
||||
AddReg=dvd_property_provider_AddReg
|
||||
|
||||
[mitsumi_install.HW]
|
||||
AddReg=nosync_addreg,mitsumi_addreg
|
||||
|
||||
[mitsumi_install.Services]
|
||||
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
|
||||
AddService=redbook,,redbook_ServiceInstallSection,redbook_InstallEventLogSection
|
||||
|
||||
;;
|
||||
;; Installation section for generic cdrom.
|
||||
;;
|
||||
|
||||
[cdrom_install]
|
||||
CopyFiles=cdrom_copyfiles,storprop_copyfiles
|
||||
AddReg=dvd_property_provider_AddReg
|
||||
|
||||
[cdrom_install.HW]
|
||||
AddReg=nosync_addreg
|
||||
|
||||
[cdrom_install.Services]
|
||||
AddService=cdrom,0x00000002,cdrom_ServiceInstallSection
|
||||
AddService=redbook,,redbook_ServiceInstallSection,redbook_InstallEventLogSection
|
||||
|
||||
;;
|
||||
;; Service install sections for cdrom and cdaudio
|
||||
;;
|
||||
|
||||
[cdrom_ServiceInstallSection]
|
||||
DisplayName = %cdrom_ServiceDesc%
|
||||
ServiceType = 1
|
||||
StartType = 1
|
||||
ErrorControl = 1
|
||||
ServiceBinary = %12%\cdrom.sys
|
||||
LoadOrderGroup = SCSI CDROM Class
|
||||
AddReg=autorun_addreg
|
||||
|
||||
[cdaudio_ServiceInstallSection]
|
||||
DisplayName = %cdaudio_ServiceDesc%
|
||||
ServiceType = 1
|
||||
StartType = 1
|
||||
ErrorControl = 1
|
||||
ServiceBinary = %12%\cdaudio.sys
|
||||
LoadOrderGroup = Pnp Filter
|
||||
|
||||
[changer_ServiceInstallSection]
|
||||
DisplayName = %changer_ServiceDesc%
|
||||
ServiceType = 1
|
||||
StartType = 1
|
||||
ErrorControl = 1
|
||||
ServiceBinary = %12%\changer.sys
|
||||
LoadOrderGroup = Pnp Filter
|
||||
|
||||
[redbook_ServiceInstallSection]
|
||||
DisplayName = %redbook_ServiceDesc%
|
||||
ServiceType = 1
|
||||
StartType = 1
|
||||
ErrorControl = 1
|
||||
ServiceBinary = %12%\redbook.sys
|
||||
LoadOrderGroup = Pnp Filter
|
||||
|
||||
[redbook_InstallEventLogSection]
|
||||
AddReg = redbook_EventLog_addreg
|
||||
|
||||
[redbook_EventLog_addreg]
|
||||
HKR,,"EventMessageFile",0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\redbook.sys"
|
||||
HKR,,"TypesSupported",0x00010001,7
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Strings]
|
||||
DDK_SAMPLE="DDK Sample Provider"
|
||||
CDClassName = "DVD/CD-ROM drives"
|
||||
|
||||
;; Manufacturer specific strings
|
||||
ATAPI_CHGR = "Atapi 2.5 Changer Devices"
|
||||
CHINON = "Chinon"
|
||||
DENON = "Denon"
|
||||
FUJITSU = "Fujitsu"
|
||||
HITACHI = "Hitachi"
|
||||
HP = "Hewlett Packard"
|
||||
MITSUMI = "Mitsumi"
|
||||
NEC = "NEC"
|
||||
OTI = "OTI"
|
||||
PIONEER = "Pioneer"
|
||||
WEARNES = "Wearnes"
|
||||
GenManufacturer = "(Standard CD-ROM drives)"
|
||||
|
||||
;; Descriptions for enumerated brands and models
|
||||
AlpsChanger_devdesc = "Alps CD-ROM Changer"
|
||||
chinon_devdesc = "Chinon CD-ROM Drive"
|
||||
denon_devdesc = "Denon CD-ROM Drive"
|
||||
fujitsu_devdesc = "Fujitsu CD-ROM Drive"
|
||||
hp_devdesc = "Hewlett Packard CD-ROM Drive"
|
||||
hitachi_devdesc = "Hitachi CD-ROM Drive"
|
||||
Mitsumi_cdrom_devdesc = "Mitsumi CD-ROM Drive"
|
||||
NecChanger_devdesc = "NEC CD-ROM Changer"
|
||||
NecIntersect_devdesc = "NEC Intersect CD-ROM Drive"
|
||||
NecMultispin_devdesc = "NEC Multispin CD-ROM Drive"
|
||||
NecOem_devdesc = "NEC CD-ROM Drive"
|
||||
oti_devdesc = "OTI CD-ROM Drive"
|
||||
PanasonicChanger_devdesc = "Panasonic CD-ROM Changer"
|
||||
pioneer_devdesc = "Pioneer CD-ROM Drive"
|
||||
TorisanChanger_devdesc = "Torisan CD-ROM Changer"
|
||||
wearnes_devdesc = "Wearnes CD-ROM Drive"
|
||||
gencdrom_devdesc = "CD-ROM Drive"
|
||||
|
||||
;; Mitsumi Friendly name explictly listed
|
||||
Mitsumi_Generic_FriendlyName = "Mitsumi CD-ROM Drive"
|
||||
|
||||
;; Service descriptions
|
||||
cdrom_ServiceDesc = "CD-ROM Driver"
|
||||
cdaudio_ServiceDesc = "CD-Audio Filter Driver"
|
||||
changer_ServiceDesc = "CD-Changer Filter Driver"
|
||||
redbook_ServiceDesc = "Digital CD Audio Playback Filter Driver"
|
||||
|
||||
|
20
reactos/drivers/storage/class/cdrom_new/cdrom_new.rbuild
Normal file
20
reactos/drivers/storage/class/cdrom_new/cdrom_new.rbuild
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="cdrom_new" type="kernelmodedriver" installbase="system32/drivers" installname="cdrom_new.sys">
|
||||
<bootstrap installbase="$(CDOUTPUT)" />
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<library>classpnp</library>
|
||||
<include base="cdrom_new">../inc</include>
|
||||
<group compilerset="gcc">
|
||||
<compilerflag>-mrtd</compilerflag>
|
||||
<compilerflag>-fno-builtin</compilerflag>
|
||||
<compilerflag>-w</compilerflag>
|
||||
</group>
|
||||
<file>cdrom.c</file>
|
||||
<file>data.c</file>
|
||||
<file>ioctl.c</file>
|
||||
<file>mmc.c</file>
|
||||
<file>scsicdrm.rc</file>
|
||||
<file>sec.c</file>
|
||||
</module>
|
99
reactos/drivers/storage/class/cdrom_new/data.c
Normal file
99
reactos/drivers/storage/class/cdrom_new/data.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
Environment:
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ntddk.h"
|
||||
#include "classpnp.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg("PAGE")
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
#define CDROM_HACK_DEC_RRD (0x00000001)
|
||||
#define CDROM_HACK_FUJITSU_FMCD_10x (0x00000002)
|
||||
#define CDROM_HACK_HITACHI_1750 (0x00000004)
|
||||
#define CDROM_HACK_HITACHI_GD_2000 (0x00000008)
|
||||
#define CDROM_HACK_TOSHIBA_SD_W1101 (0x00000010)
|
||||
#define CDROM_HACK_TOSHIBA_XM_3xx (0x00000020)
|
||||
#define CDROM_HACK_NEC_CDDA (0x00000040)
|
||||
#define CDROM_HACK_PLEXTOR_CDDA (0x00000080)
|
||||
#define CDROM_HACK_BAD_GET_CONFIG_SUPPORT (0x00000100)
|
||||
#define CDROM_HACK_FORCE_READ_CD_DETECTION (0x00000200)
|
||||
#define CDROM_HACK_READ_CD_SUPPORTED (0x00000400)
|
||||
|
||||
*/
|
||||
|
||||
CLASSPNP_SCAN_FOR_SPECIAL_INFO CdromHackItems[] = {
|
||||
// digital put out drives using 512 byte block sizes,
|
||||
// and needed us to send a mode page to set the sector
|
||||
// size back to 2048.
|
||||
{ "DEC" , "RRD" , NULL, 0x0001 },
|
||||
// these fujitsu drives take longer than ten seconds to
|
||||
// timeout commands when audio discs are placed in them
|
||||
{ "FUJITSU" , "FMCD-101" , NULL, 0x0002 },
|
||||
{ "FUJITSU" , "FMCD-102" , NULL, 0x0002 },
|
||||
// these hitachi drives don't work properly in PIO mode
|
||||
{ "HITACHI ", "CDR-1750S" , NULL, 0x0004 },
|
||||
{ "HITACHI ", "CDR-3650/1650S" , NULL, 0x0004 },
|
||||
// this particular gem doesn't automatcially spin up
|
||||
// on some media access commands.
|
||||
{ "" , "HITACHI GD-2000" , NULL, 0x0008 },
|
||||
{ "" , "HITACHI DVD-ROM GD-2000" , NULL, 0x0008 },
|
||||
// this particular drive doesn't support DVD playback.
|
||||
// just print an error message in CHK builds.
|
||||
{ "TOSHIBA ", "SD-W1101 DVD-RAM" , NULL, 0x0010 },
|
||||
// not sure what this device's issue was. seems to
|
||||
// require mode selects at various times.
|
||||
{ "TOSHIBA ", "CD-ROM XM-3" , NULL, 0x0020 },
|
||||
// NEC defined a "READ_CD" type command before there was
|
||||
// a standard, so fall back on this as an option.
|
||||
{ "NEC" , "" , NULL, 0x0040 },
|
||||
// plextor defined a "READ_CD" type command before there was
|
||||
// a standard, so fall back on this as an option.
|
||||
{ "PLEXTOR ", "" , NULL, 0x0080 },
|
||||
// this drive times out and sometimes disappears from the bus
|
||||
// when send GET_CONFIGURATION commands. don't send them.
|
||||
{ "" , "LG DVD-ROM DRD-840B" , NULL, 0x0100 },
|
||||
{ "" , "SAMSUNG DVD-ROM SD-608" , NULL, 0x0300 },
|
||||
// these drives should have supported READ_CD, but at least
|
||||
// some firmware revisions did not. force READ_CD detection.
|
||||
{ "" , "SAMSUNG DVD-ROM SD-" , NULL, 0x2000 },
|
||||
// the mitsumi drive below doesn't follow the block-only spec,
|
||||
// and we end up hanging when sending it commands it doesn't
|
||||
// understand. this causes complications later, also.
|
||||
{ "MITSUMI ", "CR-4802TE " , NULL, 0x0100 },
|
||||
// some drives return various funky errors (such as 3/2/0 NO_SEEK_COMPLETE)
|
||||
// during the detection of READ_CD support, resulting in iffy detection.
|
||||
// since they probably don't support mode switching, which is really old
|
||||
// legacy stuff anyways, the ability to read digitally is lost when
|
||||
// these drives return unexpected error codes. note: MMC compliant drives
|
||||
// are presumed to support READ_CD, as are DVD drives, and anything
|
||||
// connected to a bus type other than IDE or SCSI, and therefore don't
|
||||
// need to be here.
|
||||
{ "YAMAHA ", "CRW8424S " , NULL, 0x0400 },
|
||||
// and finally, a place to finish the list. :)
|
||||
{ NULL , NULL , NULL, 0x0000 }
|
||||
};
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg()
|
||||
#endif
|
||||
|
4054
reactos/drivers/storage/class/cdrom_new/ioctl.c
Normal file
4054
reactos/drivers/storage/class/cdrom_new/ioctl.c
Normal file
File diff suppressed because it is too large
Load diff
1422
reactos/drivers/storage/class/cdrom_new/mmc.c
Normal file
1422
reactos/drivers/storage/class/cdrom_new/mmc.c
Normal file
File diff suppressed because it is too large
Load diff
23
reactos/drivers/storage/class/cdrom_new/scsicdrm.rc
Normal file
23
reactos/drivers/storage/class/cdrom_new/scsicdrm.rc
Normal file
|
@ -0,0 +1,23 @@
|
|||
//+-------------------------------------------------------------------------
|
||||
//
|
||||
// Microsoft Windows
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||||
//
|
||||
// File: scsicdrm.rc
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_DRV
|
||||
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
|
||||
#define VER_FILEDESCRIPTION_STR "SCSI CD-ROM Driver"
|
||||
#define VER_INTERNALNAME_STR "cdrom.sys"
|
||||
#define VER_ORIGINALFILENAME_STR "cdrom.sys"
|
||||
#define VER_LANGNEUTRAL
|
||||
|
||||
#include "common.ver"
|
||||
|
38
reactos/drivers/storage/class/cdrom_new/sec.c
Normal file
38
reactos/drivers/storage/class/cdrom_new/sec.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*--
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1999
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "sec.h"
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdRomGetRpc0Settings(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
|
||||
PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
|
||||
|
||||
cddata->Rpc0SystemRegion = (UCHAR)(~1); // region one
|
||||
cddata->Rpc0SystemRegionResetCount = 0; // no resets
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CdRomSetRpc0Settings(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN UCHAR NewRegion
|
||||
)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
11
reactos/drivers/storage/class/cdrom_new/sec.h
Normal file
11
reactos/drivers/storage/class/cdrom_new/sec.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*--
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1999
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "ntddk.h"
|
||||
#include "classpnp.h"
|
||||
#include "cdrom.h"
|
||||
|
32
reactos/drivers/storage/class/cdrom_new/sources
Normal file
32
reactos/drivers/storage/class/cdrom_new/sources
Normal file
|
@ -0,0 +1,32 @@
|
|||
!IF 0
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1996 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
sources.
|
||||
|
||||
!ENDIF
|
||||
|
||||
TARGETNAME=cdrom
|
||||
TARGETPATH=obj
|
||||
TARGETTYPE=DRIVER
|
||||
|
||||
TARGETLIBS=\
|
||||
$(DDK_LIB_PATH)\classpnp.lib \
|
||||
$(DDK_LIB_PATH)\ntoskrnl.lib
|
||||
|
||||
INCLUDES=..\inc;..\..\inc
|
||||
|
||||
SOURCES=\
|
||||
data.c \
|
||||
cdrom.c \
|
||||
ioctl.c \
|
||||
mmc.c \
|
||||
scsicdrm.rc \
|
||||
sec.c
|
||||
|
||||
RUN_WPP=$(SOURCES)\
|
||||
-km\
|
||||
-func:TraceLog((LEVEL,MSG,...))
|
||||
|
53
reactos/drivers/storage/class/cdrom_new/trace.h
Normal file
53
reactos/drivers/storage/class/cdrom_new/trace.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
|
||||
WPP_DEFINE_CONTROL_GUID specifies the GUID used for this filter.
|
||||
*** REPLACE THE GUID WITH YOUR OWN UNIQUE ID ***
|
||||
WPP_DEFINE_BIT allows setting debug bit masks to selectively print.
|
||||
|
||||
everything else can revert to the default?
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define TraceLogger(x, ...) DbgPrint(__VA_ARGS__)
|
||||
#define TraceLog(x) TraceLogger x
|
||||
#define WPP_INIT_TRACING(x, y)
|
||||
#define WPP_CLEANUP(x)
|
||||
|
||||
#define WPP_CONTROL_GUIDS \
|
||||
WPP_DEFINE_CONTROL_GUID(Cdrom,(58db8e03,0537,45cb,b29b,597f6cbebbfd), \
|
||||
WPP_DEFINE_BIT(CdromDebugError) /* bit 0 = 0x00000001 */ \
|
||||
WPP_DEFINE_BIT(CdromDebugWarning) /* bit 1 = 0x00000002 */ \
|
||||
WPP_DEFINE_BIT(CdromDebugTrace) /* bit 2 = 0x00000004 */ \
|
||||
WPP_DEFINE_BIT(CdromDebugInfo) /* bit 3 = 0x00000008 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD04) /* bit 4 = 0x00000010 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD05) /* bit 5 = 0x00000020 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD06) /* bit 6 = 0x00000040 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD07) /* bit 7 = 0x00000080 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD08) /* bit 8 = 0x00000100 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD09) /* bit 9 = 0x00000200 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD10) /* bit 10 = 0x00000400 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD11) /* bit 11 = 0x00000800 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD12) /* bit 12 = 0x00001000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD13) /* bit 13 = 0x00002000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD14) /* bit 14 = 0x00004000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD15) /* bit 15 = 0x00008000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD16) /* bit 16 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD17) /* bit 17 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD18) /* bit 18 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD19) /* bit 19 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD20) /* bit 20 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD21) /* bit 21 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD22) /* bit 22 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD23) /* bit 23 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD24) /* bit 24 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD25) /* bit 25 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD26) /* bit 26 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD27) /* bit 27 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD28) /* bit 28 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(FilterDebugD29) /* bit 29 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(CdromSecError) /* bit 30 = 0x00000000 */ \
|
||||
WPP_DEFINE_BIT(CdromSecInfo) /* bit 31 = 0x00000000 */ \
|
||||
)
|
||||
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
<directory name="cdrom">
|
||||
<xi:include href="cdrom/cdrom.rbuild" />
|
||||
</directory>
|
||||
<directory name="cdrom_new">
|
||||
<xi:include href="cdrom_new/cdrom_new.rbuild" />
|
||||
</directory>
|
||||
<directory name="class2">
|
||||
<xi:include href="class2/class2.rbuild" />
|
||||
</directory>
|
||||
|
|
3611
reactos/drivers/storage/classpnp/autorun.c
Normal file
3611
reactos/drivers/storage/classpnp/autorun.c
Normal file
File diff suppressed because it is too large
Load diff
9182
reactos/drivers/storage/classpnp/class.c
Normal file
9182
reactos/drivers/storage/classpnp/class.c
Normal file
File diff suppressed because it is too large
Load diff
61
reactos/drivers/storage/classpnp/class.def
Normal file
61
reactos/drivers/storage/classpnp/class.def
Normal file
|
@ -0,0 +1,61 @@
|
|||
NAME CLASSPNP.SYS
|
||||
|
||||
EXPORTS
|
||||
ClassInitialize@12
|
||||
ClassInitializeEx@12
|
||||
ClassGetDescriptor@12
|
||||
ClassReadDriveCapacity@4
|
||||
ClassReleaseQueue@4
|
||||
ClassAsynchronousCompletion@12
|
||||
ClassSplitRequest@12
|
||||
ClassDeviceControl@8
|
||||
ClassIoComplete@12
|
||||
ClassIoCompleteAssociated@12
|
||||
ClassInterpretSenseInfo@28
|
||||
ClassSendDeviceIoControlSynchronous@28
|
||||
ClassSendIrpSynchronous@8
|
||||
ClassForwardIrpSynchronous@8
|
||||
ClassSendSrbSynchronous@20
|
||||
ClassSendSrbAsynchronous@24
|
||||
ClassBuildRequest@8
|
||||
ClassModeSense@16
|
||||
ClassFindModePage@16
|
||||
ClassClaimDevice@8
|
||||
ClassInternalIoControl@8
|
||||
ClassCreateDeviceObject@20
|
||||
ClassRemoveDevice@8
|
||||
ClassInitializeSrbLookasideList@8
|
||||
ClassDeleteSrbLookasideList@4
|
||||
ClassQueryTimeOutRegistryValue@4
|
||||
ClassInvalidateBusRelations@4
|
||||
ClassMarkChildrenMissing@4
|
||||
ClassMarkChildMissing@8
|
||||
ClassDebugPrint
|
||||
ClassGetDriverExtension@4
|
||||
ClassCompleteRequest@12
|
||||
ClassReleaseRemoveLock@8
|
||||
ClassAcquireRemoveLockEx@16
|
||||
ClassUpdateInformationInRegistry@20
|
||||
ClassWmiCompleteRequest@20
|
||||
ClassWmiFireEvent@20
|
||||
ClassGetVpb@4
|
||||
ClassSetFailurePredictionPoll@12
|
||||
ClassNotifyFailurePredicted@32
|
||||
ClassInitializeTestUnitPolling@8
|
||||
ClassSignalCompletion@12
|
||||
ClassSendStartUnit@4
|
||||
ClassSetMediaChangeState@12
|
||||
ClassResetMediaChangeTimer@4
|
||||
ClassCheckMediaState@4
|
||||
ClassInitializeMediaChangeDetection@8
|
||||
ClassCleanupMediaChangeDetection@4
|
||||
ClassEnableMediaChangeDetection@4
|
||||
ClassDisableMediaChangeDetection@4
|
||||
ClassSpinDownPowerHandler@8
|
||||
ClassStopUnitPowerHandler@8
|
||||
ClassAcquireChildLock@4
|
||||
ClassReleaseChildLock@4
|
||||
ClassScanForSpecial@12
|
||||
ClassSetDeviceParameter@16
|
||||
ClassGetDeviceParameter@16
|
||||
|
23
reactos/drivers/storage/classpnp/class.rc
Normal file
23
reactos/drivers/storage/classpnp/class.rc
Normal file
|
@ -0,0 +1,23 @@
|
|||
//+-------------------------------------------------------------------------
|
||||
//
|
||||
// Microsoft Windows
|
||||
//
|
||||
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||||
//
|
||||
// File: class.rc
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_DRV
|
||||
#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
|
||||
#define VER_FILEDESCRIPTION_STR "SCSI Class System Dll"
|
||||
#define VER_INTERNALNAME_STR "Classpnp.sys"
|
||||
#define VER_ORIGINALFILENAME_STR "Classpnp.sys"
|
||||
#define VER_LANGNEUTRAL
|
||||
|
||||
#include "common.ver"
|
||||
|
907
reactos/drivers/storage/classpnp/classp.h
Normal file
907
reactos/drivers/storage/classpnp/classp.h
Normal file
|
@ -0,0 +1,907 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
classp.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Private header file for classpnp.sys modules. This contains private
|
||||
structure and function declarations as well as constant values which do
|
||||
not need to be exported.
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <ntddk.h>
|
||||
|
||||
#include <scsi.h>
|
||||
#include <wmidata.h>
|
||||
#include <classpnp.h>
|
||||
|
||||
#if CLASS_INIT_GUID
|
||||
#include <initguid.h>
|
||||
#endif
|
||||
|
||||
#include <mountdev.h>
|
||||
#include <ioevent.h>
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
extern CLASSPNP_SCAN_FOR_SPECIAL_INFO ClassBadItems[];
|
||||
|
||||
extern GUID ClassGuidQueryRegInfoEx;
|
||||
|
||||
|
||||
#define CLASSP_REG_SUBKEY_NAME (L"Classpnp")
|
||||
|
||||
#define CLASSP_REG_HACK_VALUE_NAME (L"HackMask")
|
||||
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME (L"MMCDetectionState")
|
||||
#define CLASSP_REG_WRITE_CACHE_VALUE_NAME (L"WriteCacheEnableOverride")
|
||||
#define CLASSP_REG_PERF_RESTORE_VALUE_NAME (L"RestorePerfAtCount")
|
||||
#define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME (L"UserRemovalPolicy")
|
||||
|
||||
#define CLASS_PERF_RESTORE_MINIMUM (0x10)
|
||||
#define CLASS_ERROR_LEVEL_1 (0x4)
|
||||
#define CLASS_ERROR_LEVEL_2 (0x8)
|
||||
|
||||
#define FDO_HACK_CANNOT_LOCK_MEDIA (0x00000001)
|
||||
#define FDO_HACK_GESN_IS_BAD (0x00000002)
|
||||
#define FDO_HACK_NO_SYNC_CACHE (0x00000004)
|
||||
|
||||
#define FDO_HACK_VALID_FLAGS (0x00000007)
|
||||
#define FDO_HACK_INVALID_FLAGS (~FDO_HACK_VALID_FLAGS)
|
||||
|
||||
/*
|
||||
* Lots of retries of synchronized SCSI commands that devices may not
|
||||
* even support really slows down the system (especially while booting).
|
||||
* (Even GetDriveCapacity may be failed on purpose if an external disk is powered off).
|
||||
* If a disk cannot return a small initialization buffer at startup
|
||||
* in two attempts (with delay interval) then we cannot expect it to return
|
||||
* data consistently with four retries.
|
||||
* So don't set the retry counts as high here as for data SRBs.
|
||||
*
|
||||
* If we find that these requests are failing consecutively,
|
||||
* despite the retry interval, on otherwise reliable media,
|
||||
* then we should either increase the retry interval for
|
||||
* that failure or (by all means) increase these retry counts as appropriate.
|
||||
*/
|
||||
#define NUM_LOCKMEDIAREMOVAL_RETRIES 1
|
||||
#define NUM_MODESENSE_RETRIES 1
|
||||
#define NUM_DRIVECAPACITY_RETRIES 1
|
||||
|
||||
|
||||
#define CLASS_FILE_OBJECT_EXTENSION_KEY 'eteP'
|
||||
#define CLASSP_VOLUME_VERIFY_CHECKED 0x34
|
||||
|
||||
#define CLASS_TAG_PRIVATE_DATA 'CPcS'
|
||||
#define CLASS_TAG_PRIVATE_DATA_FDO 'FPcS'
|
||||
#define CLASS_TAG_PRIVATE_DATA_PDO 'PPcS'
|
||||
|
||||
struct _MEDIA_CHANGE_DETECTION_INFO {
|
||||
|
||||
//
|
||||
// Mutex to synchronize enable/disable requests and media state changes
|
||||
//
|
||||
|
||||
KMUTEX MediaChangeMutex;
|
||||
|
||||
//
|
||||
// The current state of the media (present, not present, unknown)
|
||||
// protected by MediaChangeSynchronizationEvent
|
||||
//
|
||||
|
||||
MEDIA_CHANGE_DETECTION_STATE MediaChangeDetectionState;
|
||||
|
||||
//
|
||||
// This is a count of how many time MCD has been disabled. if it is
|
||||
// set to zero, then we'll poll the device for MCN events with the
|
||||
// then-current method (ie. TEST UNIT READY or GESN). this is
|
||||
// protected by MediaChangeMutex
|
||||
//
|
||||
|
||||
LONG MediaChangeDetectionDisableCount;
|
||||
|
||||
|
||||
//
|
||||
// The timer value to support media change events. This is a countdown
|
||||
// value used to determine when to poll the device for a media change.
|
||||
// The max value for the timer is 255 seconds. This is not protected
|
||||
// by an event -- simply InterlockedExchanged() as needed.
|
||||
//
|
||||
|
||||
LONG MediaChangeCountDown;
|
||||
|
||||
//
|
||||
// recent changes allowed instant retries of the MCN irp. Since this
|
||||
// could cause an infinite loop, keep a count of how many times we've
|
||||
// retried immediately so that we can catch if the count exceeds an
|
||||
// arbitrary limit.
|
||||
//
|
||||
|
||||
LONG MediaChangeRetryCount;
|
||||
|
||||
//
|
||||
// use GESN if it's available
|
||||
//
|
||||
|
||||
struct {
|
||||
BOOLEAN Supported;
|
||||
BOOLEAN HackEventMask;
|
||||
UCHAR EventMask;
|
||||
UCHAR NoChangeEventMask;
|
||||
PUCHAR Buffer;
|
||||
PMDL Mdl;
|
||||
ULONG BufferSize;
|
||||
} Gesn;
|
||||
|
||||
//
|
||||
// If this value is one, then the irp is currently in use.
|
||||
// If this value is zero, then the irp is available.
|
||||
// Use InterlockedCompareExchange() to set from "available" to "in use".
|
||||
// ASSERT that InterlockedCompareExchange() showed previous value of
|
||||
// "in use" when changing back to "available" state.
|
||||
// This also implicitly protects the MediaChangeSrb and SenseBuffer
|
||||
//
|
||||
|
||||
LONG MediaChangeIrpInUse;
|
||||
|
||||
//
|
||||
// Pointer to the irp to be used for media change detection.
|
||||
// protected by Interlocked MediaChangeIrpInUse
|
||||
//
|
||||
|
||||
PIRP MediaChangeIrp;
|
||||
|
||||
//
|
||||
// The srb for the media change detection.
|
||||
// protected by Interlocked MediaChangeIrpInUse
|
||||
//
|
||||
|
||||
SCSI_REQUEST_BLOCK MediaChangeSrb;
|
||||
PUCHAR SenseBuffer;
|
||||
ULONG SrbFlags;
|
||||
|
||||
//
|
||||
// Second timer to keep track of how long the media change IRP has been
|
||||
// in use. If this value exceeds the timeout (#defined) then we should
|
||||
// print out a message to the user and set the MediaChangeIrpLost flag
|
||||
// protected by using Interlocked() operations in ClasspSendMediaStateIrp,
|
||||
// the only routine which should modify this value.
|
||||
//
|
||||
|
||||
LONG MediaChangeIrpTimeInUse;
|
||||
|
||||
//
|
||||
// Set by CdRomTickHandler when we determine that the media change irp has
|
||||
// been lost
|
||||
//
|
||||
|
||||
BOOLEAN MediaChangeIrpLost;
|
||||
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SimpleMediaLock,
|
||||
SecureMediaLock,
|
||||
InternalMediaLock
|
||||
} MEDIA_LOCK_TYPE, *PMEDIA_LOCK_TYPE;
|
||||
|
||||
typedef struct _FAILURE_PREDICTION_INFO {
|
||||
FAILURE_PREDICTION_METHOD Method;
|
||||
ULONG CountDown; // Countdown timer
|
||||
ULONG Period; // Countdown period
|
||||
|
||||
PIO_WORKITEM WorkQueueItem;
|
||||
|
||||
KEVENT Event;
|
||||
} FAILURE_PREDICTION_INFO, *PFAILURE_PREDICTION_INFO;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// This struct must always fit within four PVOIDs of info,
|
||||
// as it uses the irp's "PVOID DriverContext[4]" to store
|
||||
// this info
|
||||
//
|
||||
typedef struct _CLASS_RETRY_INFO {
|
||||
struct _CLASS_RETRY_INFO *Next;
|
||||
} CLASS_RETRY_INFO, *PCLASS_RETRY_INFO;
|
||||
|
||||
|
||||
|
||||
typedef struct _CSCAN_LIST {
|
||||
|
||||
//
|
||||
// The current block which has an outstanding request.
|
||||
//
|
||||
|
||||
ULONGLONG BlockNumber;
|
||||
|
||||
//
|
||||
// The list of blocks past the CurrentBlock to which we're going to do
|
||||
// i/o. This list is maintained in sorted order.
|
||||
//
|
||||
|
||||
LIST_ENTRY CurrentSweep;
|
||||
|
||||
//
|
||||
// The list of blocks behind the current block for which we'll have to
|
||||
// wait until the next scan across the disk. This is kept as a stack,
|
||||
// the cost of sorting it is taken when it's moved over to be the
|
||||
// running list.
|
||||
//
|
||||
|
||||
LIST_ENTRY NextSweep;
|
||||
|
||||
} CSCAN_LIST, *PCSCAN_LIST;
|
||||
|
||||
//
|
||||
// add to the front of this structure to help prevent illegal
|
||||
// snooping by other utilities.
|
||||
//
|
||||
|
||||
|
||||
|
||||
typedef enum _CLASS_DETECTION_STATE {
|
||||
ClassDetectionUnknown = 0,
|
||||
ClassDetectionUnsupported = 1,
|
||||
ClassDetectionSupported = 2
|
||||
} CLASS_DETECTION_STATE, *PCLASS_DETECTION_STATE;
|
||||
|
||||
|
||||
typedef struct _CLASS_ERROR_LOG_DATA {
|
||||
LARGE_INTEGER TickCount; // Offset 0x00
|
||||
ULONG PortNumber; // Offset 0x08
|
||||
|
||||
UCHAR ErrorPaging : 1; // Offset 0x0c
|
||||
UCHAR ErrorRetried : 1;
|
||||
UCHAR ErrorUnhandled : 1;
|
||||
UCHAR ErrorReserved : 5;
|
||||
|
||||
UCHAR Reserved[3];
|
||||
|
||||
SCSI_REQUEST_BLOCK Srb; // Offset 0x10
|
||||
|
||||
/*
|
||||
* We define the SenseData as the default length.
|
||||
* Since the sense data returned by the port driver may be longer,
|
||||
* SenseData must be at the end of this structure.
|
||||
* For our internal error log, we only log the default length.
|
||||
*/
|
||||
SENSE_DATA SenseData; // Offset 0x50 for x86 (or 0x68 for ia64) (ULONG32 Alignment required!)
|
||||
} CLASS_ERROR_LOG_DATA, *PCLASS_ERROR_LOG_DATA;
|
||||
|
||||
#define NUM_ERROR_LOG_ENTRIES 16
|
||||
|
||||
|
||||
|
||||
typedef struct _TRANSFER_PACKET {
|
||||
|
||||
LIST_ENTRY AllPktsListEntry; // entry in fdoData's static AllTransferPacketsList
|
||||
SINGLE_LIST_ENTRY SlistEntry; // for when in free list (use fast slist)
|
||||
|
||||
PIRP Irp;
|
||||
PDEVICE_OBJECT Fdo;
|
||||
|
||||
/*
|
||||
* This is the client IRP that this TRANSFER_PACKET is currently
|
||||
* servicing.
|
||||
*/
|
||||
PIRP OriginalIrp;
|
||||
BOOLEAN CompleteOriginalIrpWhenLastPacketCompletes;
|
||||
|
||||
/*
|
||||
* Stuff for retrying the transfer.
|
||||
*/
|
||||
ULONG NumRetries;
|
||||
KTIMER RetryTimer;
|
||||
KDPC RetryTimerDPC;
|
||||
ULONG RetryIntervalSec;
|
||||
|
||||
/*
|
||||
* Event for synchronizing the transfer (optional).
|
||||
* (Note that we can't have the event in the packet itself because
|
||||
* by the time a thread waits on an event the packet may have
|
||||
* been completed and re-issued.
|
||||
*/
|
||||
PKEVENT SyncEventPtr;
|
||||
|
||||
/*
|
||||
* Stuff for retrying during extreme low-memory stress
|
||||
* (when we retry 1 page at a time).
|
||||
*/
|
||||
BOOLEAN InLowMemRetry;
|
||||
PUCHAR LowMemRetry_remainingBufPtr;
|
||||
ULONG LowMemRetry_remainingBufLen;
|
||||
LARGE_INTEGER LowMemRetry_nextChunkTargetLocation;
|
||||
|
||||
/*
|
||||
* Fields used for cancelling the packet.
|
||||
*/
|
||||
// BOOLEAN Cancelled;
|
||||
// KEVENT CancelledEvent;
|
||||
|
||||
/*
|
||||
* We keep the buffer and length values here as well
|
||||
* as in the SRB because some miniports return
|
||||
* the transferred length in SRB.DataTransferLength,
|
||||
* and if the SRB failed we need that value again for the retry.
|
||||
* We don't trust the lower stack to preserve any of these values in the SRB.
|
||||
*/
|
||||
PUCHAR BufPtrCopy;
|
||||
ULONG BufLenCopy;
|
||||
LARGE_INTEGER TargetLocationCopy;
|
||||
|
||||
/*
|
||||
* This is a standard SCSI structure that receives a detailed
|
||||
* report about a SCSI error on the hardware.
|
||||
*/
|
||||
SENSE_DATA SrbErrorSenseData;
|
||||
|
||||
/*
|
||||
* This is the SRB block for this TRANSFER_PACKET.
|
||||
* For IOCTLs, the SRB block includes two DWORDs for
|
||||
* device object and ioctl code; so these must
|
||||
* immediately follow the SRB block.
|
||||
*/
|
||||
SCSI_REQUEST_BLOCK Srb;
|
||||
// ULONG SrbIoctlDevObj; // not handling ioctls yet
|
||||
// ULONG SrbIoctlCode;
|
||||
|
||||
} TRANSFER_PACKET, *PTRANSFER_PACKET;
|
||||
|
||||
/*
|
||||
* MIN_INITIAL_TRANSFER_PACKETS is the minimum number of packets that
|
||||
* we preallocate at startup for each device (we need at least one packet
|
||||
* to guarantee forward progress during memory stress).
|
||||
* MIN_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
|
||||
* we allow to build up and remain for each device;
|
||||
* we _lazily_ work down to this number when they're not needed.
|
||||
* MAX_WORKINGSET_TRANSFER_PACKETS is the number of TRANSFER_PACKETs
|
||||
* that we _immediately_ reduce to when they are not needed.
|
||||
*
|
||||
* The absolute maximum number of packets that we will allocate is
|
||||
* whatever is required by the current activity, up to the memory limit;
|
||||
* as soon as stress ends, we snap down to MAX_WORKINGSET_TRANSFER_PACKETS;
|
||||
* we then lazily work down to MIN_WORKINGSET_TRANSFER_PACKETS.
|
||||
*/
|
||||
#define MIN_INITIAL_TRANSFER_PACKETS 1
|
||||
#define MIN_WORKINGSET_TRANSFER_PACKETS_Consumer 4
|
||||
#define MAX_WORKINGSET_TRANSFER_PACKETS_Consumer 64
|
||||
#define MIN_WORKINGSET_TRANSFER_PACKETS_Server 64
|
||||
#define MAX_WORKINGSET_TRANSFER_PACKETS_Server 1024
|
||||
#define MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise 256
|
||||
#define MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise 2048
|
||||
|
||||
|
||||
//
|
||||
// add to the front of this structure to help prevent illegal
|
||||
// snooping by other utilities.
|
||||
//
|
||||
struct _CLASS_PRIVATE_FDO_DATA {
|
||||
|
||||
//
|
||||
// this private structure allows us to
|
||||
// dynamically re-enable the perf benefits
|
||||
// lost due to transient error conditions.
|
||||
// in w2k, a reboot was required. :(
|
||||
//
|
||||
struct {
|
||||
ULONG OriginalSrbFlags;
|
||||
ULONG SuccessfulIO;
|
||||
ULONG ReEnableThreshhold; // 0 means never
|
||||
} Perf;
|
||||
|
||||
ULONG_PTR HackFlags;
|
||||
|
||||
STORAGE_HOTPLUG_INFO HotplugInfo;
|
||||
|
||||
// Legacy. Still used by obsolete legacy code.
|
||||
struct {
|
||||
LARGE_INTEGER Delta; // in ticks
|
||||
LARGE_INTEGER Tick; // when it should fire
|
||||
PCLASS_RETRY_INFO ListHead; // singly-linked list
|
||||
ULONG Granularity; // static
|
||||
KSPIN_LOCK Lock; // protective spin lock
|
||||
KDPC Dpc; // DPC routine object
|
||||
KTIMER Timer; // timer to fire DPC
|
||||
} Retry;
|
||||
|
||||
BOOLEAN TimerStarted;
|
||||
BOOLEAN LoggedTURFailureSinceLastIO;
|
||||
|
||||
//
|
||||
// privately allocated release queue irp
|
||||
// protected by fdoExtension->ReleaseQueueSpinLock
|
||||
//
|
||||
BOOLEAN ReleaseQueueIrpAllocated;
|
||||
PIRP ReleaseQueueIrp;
|
||||
|
||||
/*
|
||||
* Queues for TRANSFER_PACKETs that contextualize the IRPs and SRBs
|
||||
* that we send down to the port driver.
|
||||
* (The free list is an slist so that we can use fast
|
||||
* interlocked operations on it; but the relatively-static
|
||||
* AllTransferPacketsList list has to be
|
||||
* a doubly-linked list since we have to dequeue from the middle).
|
||||
*/
|
||||
LIST_ENTRY AllTransferPacketsList;
|
||||
SLIST_HEADER FreeTransferPacketsList;
|
||||
ULONG NumFreeTransferPackets;
|
||||
ULONG NumTotalTransferPackets;
|
||||
ULONG DbgPeakNumTransferPackets;
|
||||
|
||||
/*
|
||||
* Queue for deferred client irps
|
||||
*/
|
||||
LIST_ENTRY DeferredClientIrpList;
|
||||
|
||||
/*
|
||||
* Precomputed maximum transfer length for the hardware.
|
||||
*/
|
||||
ULONG HwMaxXferLen;
|
||||
|
||||
/*
|
||||
* SCSI_REQUEST_BLOCK template preconfigured with the constant values.
|
||||
* This is slapped into the SRB in the TRANSFER_PACKET for each transfer.
|
||||
*/
|
||||
SCSI_REQUEST_BLOCK SrbTemplate;
|
||||
|
||||
KSPIN_LOCK SpinLock;
|
||||
|
||||
/*
|
||||
* Circular array of timestamped logs of errors that occurred on this device.
|
||||
*/
|
||||
ULONG ErrorLogNextIndex;
|
||||
CLASS_ERROR_LOG_DATA ErrorLogs[NUM_ERROR_LOG_ENTRIES];
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
|
||||
#define NOT_READY_RETRY_INTERVAL 10
|
||||
#define MINIMUM_RETRY_UNITS ((LONGLONG)32)
|
||||
|
||||
|
||||
/*
|
||||
* Simple singly-linked-list queuing macros, with no synchronization.
|
||||
*/
|
||||
static inline VOID SimpleInitSlistHdr(SINGLE_LIST_ENTRY *SListHdr)
|
||||
{
|
||||
SListHdr->Next = NULL;
|
||||
}
|
||||
static inline VOID SimplePushSlist(SINGLE_LIST_ENTRY *SListHdr, SINGLE_LIST_ENTRY *SListEntry)
|
||||
{
|
||||
SListEntry->Next = SListHdr->Next;
|
||||
SListHdr->Next = SListEntry;
|
||||
}
|
||||
static inline SINGLE_LIST_ENTRY *SimplePopSlist(SINGLE_LIST_ENTRY *SListHdr)
|
||||
{
|
||||
SINGLE_LIST_ENTRY *sListEntry = SListHdr->Next;
|
||||
if (sListEntry){
|
||||
SListHdr->Next = sListEntry->Next;
|
||||
sListEntry->Next = NULL;
|
||||
}
|
||||
return sListEntry;
|
||||
}
|
||||
static inline BOOLEAN SimpleIsSlistEmpty(SINGLE_LIST_ENTRY *SListHdr)
|
||||
{
|
||||
return (SListHdr->Next == NULL);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
VOID
|
||||
ClassUnload(
|
||||
IN PDRIVER_OBJECT DriverObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassCreateClose(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspCreateClose(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspCleanupProtectedLocks(
|
||||
IN PFILE_OBJECT_EXTENSION FsContext
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspEjectionControl(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PIRP Irp,
|
||||
IN MEDIA_LOCK_TYPE LockType,
|
||||
IN BOOLEAN Lock
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassReadWrite(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassDeviceControlDispatch(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassDispatchPnp(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassPnpStartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassInternalIoControl (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassShutdownFlush(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassSystemControl(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
//
|
||||
// Class internal routines
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
ClassAddDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN OUT PDEVICE_OBJECT PhysicalDeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspSendSynchronousCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
VOID
|
||||
RetryRequest(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
BOOLEAN Associated,
|
||||
ULONG RetryInterval
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassIoCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassPnpQueryFdoRelations(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassRetrieveDeviceRelations(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN DEVICE_RELATION_TYPE RelationType,
|
||||
OUT PDEVICE_RELATIONS *DeviceRelations
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassGetPdoId(
|
||||
IN PDEVICE_OBJECT Pdo,
|
||||
IN BUS_QUERY_ID_TYPE IdType,
|
||||
IN PUNICODE_STRING IdString
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassQueryPnpCapabilities(
|
||||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||||
IN PDEVICE_CAPABILITIES Capabilities
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspStartIo(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspPagingNotificationCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PDEVICE_OBJECT RealDeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspMediaChangeCompletion(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp,
|
||||
PVOID Context
|
||||
);
|
||||
|
||||
PFILE_OBJECT_EXTENSION
|
||||
ClasspGetFsContext(
|
||||
IN PCOMMON_DEVICE_EXTENSION CommonExtension,
|
||||
IN PFILE_OBJECT FileObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspMcnControl(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PIRP Irp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspRegisterMountedDeviceInterface(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspDisableTimer(
|
||||
PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspEnableTimer(
|
||||
PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
//
|
||||
// routines for dictionary list support
|
||||
//
|
||||
|
||||
VOID
|
||||
InitializeDictionary(
|
||||
IN PDICTIONARY Dictionary
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
TestDictionarySignature(
|
||||
IN PDICTIONARY Dictionary
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
AllocateDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key,
|
||||
IN ULONG Size,
|
||||
IN ULONG Tag,
|
||||
OUT PVOID *Entry
|
||||
);
|
||||
|
||||
PVOID
|
||||
GetDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key
|
||||
);
|
||||
|
||||
VOID
|
||||
FreeDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN PVOID Entry
|
||||
);
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ClasspAllocateReleaseRequest(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspFreeReleaseRequest(
|
||||
IN PDEVICE_OBJECT Fdo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassReleaseQueueCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspReleaseQueue(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP ReleaseQueueIrp
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspDisablePowerNotification(
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
//
|
||||
// class power routines
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
ClassDispatchPower(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClassMinimalPowerHandler(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
//
|
||||
// Child list routines
|
||||
//
|
||||
|
||||
VOID
|
||||
ClassAddChild(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
|
||||
IN PPHYSICAL_DEVICE_EXTENSION Child,
|
||||
IN BOOLEAN AcquireLock
|
||||
);
|
||||
|
||||
PPHYSICAL_DEVICE_EXTENSION
|
||||
ClassRemoveChild(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
|
||||
IN PPHYSICAL_DEVICE_EXTENSION Child,
|
||||
IN BOOLEAN AcquireLock
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspRetryDpcTimer(
|
||||
IN PCLASS_PRIVATE_FDO_DATA FdoData
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspRetryRequestDpc(
|
||||
IN PKDPC Dpc,
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PVOID Arg1,
|
||||
IN PVOID Arg2
|
||||
);
|
||||
|
||||
VOID
|
||||
ClassFreeOrReuseSrb(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
VOID
|
||||
ClassRetryRequest(
|
||||
IN PDEVICE_OBJECT SelfDeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN LARGE_INTEGER TimeDelta100ns // in 100ns units
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspBuildRequestEx(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION Fdo,
|
||||
IN PIRP Irp,
|
||||
IN PSCSI_REQUEST_BLOCK Srb
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspAllocateReleaseQueueIrp(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspInitializeGesn(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PMEDIA_CHANGE_DETECTION_INFO Info
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspSendNotification(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN const GUID * Guid,
|
||||
IN ULONG ExtraDataSize,
|
||||
IN PVOID ExtraData
|
||||
);
|
||||
|
||||
VOID
|
||||
ClassSendEjectionNotification(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspScanForSpecialInRegistry(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspScanForClassHacks(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN ULONG_PTR Data
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ClasspInitializeHotplugInfo(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspPerfIncrementErrorCount(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
VOID
|
||||
ClasspPerfIncrementSuccessfulIo(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
);
|
||||
|
||||
|
||||
PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo);
|
||||
VOID DestroyTransferPacket(PTRANSFER_PACKET Pkt);
|
||||
VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, PTRANSFER_PACKET Pkt);
|
||||
PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded);
|
||||
VOID SetupReadWriteTransferPacket(PTRANSFER_PACKET pkt, PVOID Buf, ULONG Len, LARGE_INTEGER DiskLocation, PIRP OriginalIrp);
|
||||
VOID SubmitTransferPacket(PTRANSFER_PACKET Pkt);
|
||||
NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context);
|
||||
VOID ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp);
|
||||
VOID TransferPacketRetryTimerDpc(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
|
||||
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt);
|
||||
BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt);
|
||||
VOID EnqueueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData, PIRP Irp);
|
||||
PIRP DequeueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData);
|
||||
VOID InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation);
|
||||
BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt);
|
||||
VOID SetupEjectionTransferPacket(TRANSFER_PACKET *Pkt, BOOLEAN PreventMediaRemoval, PKEVENT SyncEventPtr, PIRP OriginalIrp);
|
||||
VOID SetupModeSenseTransferPacket(TRANSFER_PACKET *Pkt, PKEVENT SyncEventPtr, PVOID ModeSenseBuffer, UCHAR ModeSenseBufferLen, UCHAR PageMode, PIRP OriginalIrp);
|
||||
VOID SetupDriveCapacityTransferPacket(TRANSFER_PACKET *Pkt, PVOID ReadCapacityBuffer, ULONG ReadCapacityBufferLen, PKEVENT SyncEventPtr, PIRP OriginalIrp);
|
||||
PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen);
|
||||
VOID FreeDeviceInputMdl(PMDL Mdl);
|
||||
NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo);
|
||||
VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo);
|
||||
|
||||
|
||||
|
||||
|
||||
|
37
reactos/drivers/storage/classpnp/classpnp.rbuild
Normal file
37
reactos/drivers/storage/classpnp/classpnp.rbuild
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="classpnp" type="kernelmodedriver" installbase="system32/drivers" installname="classpnp.sys">
|
||||
<bootstrap installbase="$(CDOUTPUT)" />
|
||||
<importlibrary definition="class.def" />
|
||||
<library>ntoskrnl</library>
|
||||
<library>hal</library>
|
||||
<library>pseh</library>
|
||||
<library>libcntpr</library>
|
||||
<include base="classpnp">../inc</include>
|
||||
<define name="CLASS_GLOBAL_BREAK_ON_LOST_IRPS">0</define>
|
||||
<define name="CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB">100</define>
|
||||
<define name="CLASS_GLOBAL_USE_DELAYED_RETRY">1</define>
|
||||
<define name="CLASS_GLOBAL_BUFFERED_DEBUG_PRINT">0</define>
|
||||
<define name="CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE">512</define>
|
||||
<define name="CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS">512</define>
|
||||
<group compilerset="gcc">
|
||||
<compilerflag>-mrtd</compilerflag>
|
||||
<compilerflag>-fno-builtin</compilerflag>
|
||||
<compilerflag>-w</compilerflag>
|
||||
</group>
|
||||
<file>autorun.c</file>
|
||||
<file>class.c</file>
|
||||
<file>classwmi.c</file>
|
||||
<file>create.c</file>
|
||||
<file>data.c</file>
|
||||
<file>dictlib.c</file>
|
||||
<file>lock.c</file>
|
||||
<file>power.c</file>
|
||||
<file>xferpkt.c</file>
|
||||
<file>clntirp.c</file>
|
||||
<file>retry.c</file>
|
||||
<file>utils.c</file>
|
||||
<file>obsolete.c</file>
|
||||
<file>debug.c</file>
|
||||
<file>class.rc</file>
|
||||
</module>
|
778
reactos/drivers/storage/classpnp/classwmi.c
Normal file
778
reactos/drivers/storage/classpnp/classwmi.c
Normal file
|
@ -0,0 +1,778 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
classwmi.c
|
||||
|
||||
Abstract:
|
||||
|
||||
SCSI class driver routines
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "stddef.h"
|
||||
#include "ntddk.h"
|
||||
#include "scsi.h"
|
||||
|
||||
#include "classpnp.h"
|
||||
|
||||
#include "mountdev.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "wmistr.h"
|
||||
|
||||
NTSTATUS
|
||||
ClassSystemControl(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
ClassFindGuid(
|
||||
PGUIDREGINFO GuidList,
|
||||
ULONG GuidCount,
|
||||
LPGUID Guid,
|
||||
PULONG GuidIndex
|
||||
);
|
||||
|
||||
//
|
||||
// This is the name for the MOF resource that must be part of all drivers that
|
||||
// register via this interface.
|
||||
#define MOFRESOURCENAME L"MofResourceName"
|
||||
|
||||
//
|
||||
// What can be paged ???
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, ClassSystemControl)
|
||||
#pragma alloc_text(PAGE, ClassFindGuid)
|
||||
#endif
|
||||
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassFindGuid()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will search the list of guids registered and return
|
||||
the index for the one that was registered.
|
||||
|
||||
Arguments:
|
||||
|
||||
GuidList is the list of guids to search
|
||||
|
||||
GuidCount is the count of guids in the list
|
||||
|
||||
Guid is the guid being searched for
|
||||
|
||||
*GuidIndex returns the index to the guid
|
||||
|
||||
Return Value:
|
||||
|
||||
TRUE if guid is found else FALSE
|
||||
|
||||
--*/
|
||||
BOOLEAN
|
||||
ClassFindGuid(
|
||||
PGUIDREGINFO GuidList,
|
||||
ULONG GuidCount,
|
||||
LPGUID Guid,
|
||||
PULONG GuidIndex
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
for (i = 0; i < GuidCount; i++)
|
||||
{
|
||||
if (IsEqualGUID(Guid, &GuidList[i].Guid))
|
||||
{
|
||||
*GuidIndex = i;
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
} // end ClassFindGuid()
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassSystemControl()
|
||||
|
||||
Routine Description:
|
||||
|
||||
Dispatch routine for IRP_MJ_SYSTEM_CONTROL. This routine will process
|
||||
all wmi requests received, forwarding them if they are not for this
|
||||
driver or determining if the guid is valid and if so passing it to
|
||||
the driver specific function for handing wmi requests.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Supplies a pointer to the device object for this request.
|
||||
|
||||
Irp - Supplies the Irp making the request.
|
||||
|
||||
Return Value:
|
||||
|
||||
status
|
||||
|
||||
--*/
|
||||
NTSTATUS
|
||||
ClassSystemControl(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PCLASS_DRIVER_EXTENSION driverExtension;
|
||||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
ULONG isRemoved;
|
||||
ULONG bufferSize;
|
||||
PUCHAR buffer;
|
||||
NTSTATUS status;
|
||||
UCHAR minorFunction;
|
||||
ULONG guidIndex;
|
||||
PCLASS_WMI_INFO classWmiInfo;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Make sure device has not been removed
|
||||
isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
|
||||
if(isRemoved)
|
||||
{
|
||||
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
|
||||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
//
|
||||
// If the irp is not a WMI irp or it is not targetted at this device
|
||||
// or this device has not regstered with WMI then just forward it on.
|
||||
minorFunction = irpStack->MinorFunction;
|
||||
if ((minorFunction > IRP_MN_EXECUTE_METHOD) ||
|
||||
(irpStack->Parameters.WMI.ProviderId != (ULONG_PTR)DeviceObject) ||
|
||||
((minorFunction != IRP_MN_REGINFO) &&
|
||||
(commonExtension->GuidRegInfo == NULL)))
|
||||
{
|
||||
//
|
||||
// CONSIDER: Do I need to hang onto lock until IoCallDriver returns ?
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
return(IoCallDriver(commonExtension->LowerDeviceObject, Irp));
|
||||
}
|
||||
|
||||
buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
|
||||
bufferSize = irpStack->Parameters.WMI.BufferSize;
|
||||
|
||||
if (minorFunction != IRP_MN_REGINFO)
|
||||
{
|
||||
//
|
||||
// For all requests other than query registration info we are passed
|
||||
// a guid. Determine if the guid is one that is supported by the
|
||||
// device.
|
||||
if (ClassFindGuid(commonExtension->GuidRegInfo,
|
||||
commonExtension->GuidCount,
|
||||
(LPGUID)irpStack->Parameters.WMI.DataPath,
|
||||
&guidIndex))
|
||||
{
|
||||
status = STATUS_SUCCESS;
|
||||
} else {
|
||||
status = STATUS_WMI_GUID_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status) &&
|
||||
((minorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
|
||||
(minorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE) ||
|
||||
(minorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
|
||||
(minorFunction == IRP_MN_EXECUTE_METHOD)))
|
||||
{
|
||||
if ( (((PWNODE_HEADER)buffer)->Flags) &
|
||||
WNODE_FLAG_STATIC_INSTANCE_NAMES)
|
||||
{
|
||||
if ( ((PWNODE_SINGLE_INSTANCE)buffer)->InstanceIndex != 0 )
|
||||
{
|
||||
status = STATUS_WMI_INSTANCE_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
status = STATUS_WMI_INSTANCE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (! NT_SUCCESS(status))
|
||||
{
|
||||
Irp->IoStatus.Status = status;
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
|
||||
return(status);
|
||||
}
|
||||
}
|
||||
|
||||
driverExtension = commonExtension->DriverExtension;
|
||||
|
||||
classWmiInfo = commonExtension->IsFdo ?
|
||||
&driverExtension->InitData.FdoData.ClassWmiInfo :
|
||||
&driverExtension->InitData.PdoData.ClassWmiInfo;
|
||||
switch(minorFunction)
|
||||
{
|
||||
case IRP_MN_REGINFO:
|
||||
{
|
||||
ULONG guidCount;
|
||||
PGUIDREGINFO guidList;
|
||||
PWMIREGINFOW wmiRegInfo;
|
||||
PWMIREGGUIDW wmiRegGuid;
|
||||
PDEVICE_OBJECT pdo;
|
||||
PUNICODE_STRING regPath;
|
||||
PWCHAR stringPtr;
|
||||
ULONG retSize;
|
||||
ULONG registryPathOffset;
|
||||
ULONG mofResourceOffset;
|
||||
ULONG bufferNeeded;
|
||||
ULONG i;
|
||||
ULONG_PTR nameInfo;
|
||||
ULONG nameSize, nameOffset, nameFlags;
|
||||
UNICODE_STRING name, mofName;
|
||||
PCLASS_QUERY_WMI_REGINFO_EX ClassQueryWmiRegInfoEx;
|
||||
|
||||
name.Buffer = NULL;
|
||||
name.Length = 0;
|
||||
name.MaximumLength = 0;
|
||||
nameFlags = 0;
|
||||
|
||||
ClassQueryWmiRegInfoEx = commonExtension->IsFdo ?
|
||||
driverExtension->ClassFdoQueryWmiRegInfoEx :
|
||||
driverExtension->ClassPdoQueryWmiRegInfoEx;
|
||||
|
||||
if (ClassQueryWmiRegInfoEx == NULL)
|
||||
{
|
||||
status = classWmiInfo->ClassQueryWmiRegInfo(
|
||||
DeviceObject,
|
||||
&nameFlags,
|
||||
&name);
|
||||
|
||||
RtlInitUnicodeString(&mofName, MOFRESOURCENAME);
|
||||
} else {
|
||||
RtlInitUnicodeString(&mofName, L"");
|
||||
status = (*ClassQueryWmiRegInfoEx)(
|
||||
DeviceObject,
|
||||
&nameFlags,
|
||||
&name,
|
||||
&mofName);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status) &&
|
||||
(! (nameFlags & WMIREG_FLAG_INSTANCE_PDO) &&
|
||||
(name.Buffer == NULL)))
|
||||
{
|
||||
//
|
||||
// if PDO flag not specified then an instance name must be
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
guidList = classWmiInfo->GuidRegInfo;
|
||||
guidCount = classWmiInfo->GuidCount;
|
||||
|
||||
nameOffset = sizeof(WMIREGINFO) +
|
||||
guidCount * sizeof(WMIREGGUIDW);
|
||||
|
||||
if (nameFlags & WMIREG_FLAG_INSTANCE_PDO)
|
||||
{
|
||||
nameSize = 0;
|
||||
nameInfo = commonExtension->IsFdo ?
|
||||
(ULONG_PTR)((PFUNCTIONAL_DEVICE_EXTENSION)commonExtension)->LowerPdo :
|
||||
(ULONG_PTR)DeviceObject;
|
||||
} else {
|
||||
nameFlags |= WMIREG_FLAG_INSTANCE_LIST;
|
||||
nameSize = name.Length + sizeof(USHORT);
|
||||
nameInfo = nameOffset;
|
||||
}
|
||||
|
||||
mofResourceOffset = nameOffset + nameSize;
|
||||
|
||||
registryPathOffset = mofResourceOffset +
|
||||
mofName.Length + sizeof(USHORT);
|
||||
|
||||
regPath = &driverExtension->RegistryPath;
|
||||
bufferNeeded = registryPathOffset +
|
||||
regPath->Length + sizeof(USHORT);
|
||||
|
||||
if (bufferNeeded <= bufferSize)
|
||||
{
|
||||
retSize = bufferNeeded;
|
||||
|
||||
commonExtension->GuidCount = guidCount;
|
||||
commonExtension->GuidRegInfo = guidList;
|
||||
|
||||
wmiRegInfo = (PWMIREGINFO)buffer;
|
||||
wmiRegInfo->BufferSize = bufferNeeded;
|
||||
wmiRegInfo->NextWmiRegInfo = 0;
|
||||
wmiRegInfo->MofResourceName = mofResourceOffset;
|
||||
wmiRegInfo->RegistryPath = registryPathOffset;
|
||||
wmiRegInfo->GuidCount = guidCount;
|
||||
|
||||
for (i = 0; i < guidCount; i++)
|
||||
{
|
||||
wmiRegGuid = &wmiRegInfo->WmiRegGuid[i];
|
||||
wmiRegGuid->Guid = guidList[i].Guid;
|
||||
wmiRegGuid->Flags = guidList[i].Flags | nameFlags;
|
||||
wmiRegGuid->InstanceInfo = nameInfo;
|
||||
wmiRegGuid->InstanceCount = 1;
|
||||
}
|
||||
|
||||
if ( nameFlags & WMIREG_FLAG_INSTANCE_LIST)
|
||||
{
|
||||
stringPtr = (PWCHAR)((PUCHAR)buffer + nameOffset);
|
||||
*stringPtr++ = name.Length;
|
||||
RtlCopyMemory(stringPtr,
|
||||
name.Buffer,
|
||||
name.Length);
|
||||
}
|
||||
|
||||
stringPtr = (PWCHAR)((PUCHAR)buffer + mofResourceOffset);
|
||||
*stringPtr++ = mofName.Length;
|
||||
RtlCopyMemory(stringPtr,
|
||||
mofName.Buffer,
|
||||
mofName.Length);
|
||||
|
||||
stringPtr = (PWCHAR)((PUCHAR)buffer + registryPathOffset);
|
||||
*stringPtr++ = regPath->Length;
|
||||
RtlCopyMemory(stringPtr,
|
||||
regPath->Buffer,
|
||||
regPath->Length);
|
||||
} else {
|
||||
*((PULONG)buffer) = bufferNeeded;
|
||||
retSize = sizeof(ULONG);
|
||||
}
|
||||
} else {
|
||||
retSize = 0;
|
||||
}
|
||||
|
||||
if (name.Buffer != NULL)
|
||||
{
|
||||
ExFreePool(name.Buffer);
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = retSize;
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
|
||||
return(status);
|
||||
}
|
||||
|
||||
case IRP_MN_QUERY_ALL_DATA:
|
||||
{
|
||||
PWNODE_ALL_DATA wnode;
|
||||
ULONG bufferAvail;
|
||||
|
||||
wnode = (PWNODE_ALL_DATA)buffer;
|
||||
|
||||
if (bufferSize < sizeof(WNODE_ALL_DATA))
|
||||
{
|
||||
bufferAvail = 0;
|
||||
} else {
|
||||
bufferAvail = bufferSize - sizeof(WNODE_ALL_DATA);
|
||||
}
|
||||
|
||||
wnode->DataBlockOffset = sizeof(WNODE_ALL_DATA);
|
||||
|
||||
status = classWmiInfo->ClassQueryWmiDataBlock(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
bufferAvail,
|
||||
buffer + sizeof(WNODE_ALL_DATA));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_QUERY_SINGLE_INSTANCE:
|
||||
{
|
||||
PWNODE_SINGLE_INSTANCE wnode;
|
||||
ULONG dataBlockOffset;
|
||||
|
||||
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
||||
|
||||
dataBlockOffset = wnode->DataBlockOffset;
|
||||
|
||||
status = classWmiInfo->ClassQueryWmiDataBlock(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
bufferSize - dataBlockOffset,
|
||||
(PUCHAR)wnode + dataBlockOffset);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_CHANGE_SINGLE_INSTANCE:
|
||||
{
|
||||
PWNODE_SINGLE_INSTANCE wnode;
|
||||
|
||||
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
||||
|
||||
status = classWmiInfo->ClassSetWmiDataBlock(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
wnode->SizeDataBlock,
|
||||
(PUCHAR)wnode + wnode->DataBlockOffset);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_CHANGE_SINGLE_ITEM:
|
||||
{
|
||||
PWNODE_SINGLE_ITEM wnode;
|
||||
|
||||
wnode = (PWNODE_SINGLE_ITEM)buffer;
|
||||
|
||||
status = classWmiInfo->ClassSetWmiDataItem(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
wnode->ItemId,
|
||||
wnode->SizeDataItem,
|
||||
(PUCHAR)wnode + wnode->DataBlockOffset);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_EXECUTE_METHOD:
|
||||
{
|
||||
PWNODE_METHOD_ITEM wnode;
|
||||
|
||||
wnode = (PWNODE_METHOD_ITEM)buffer;
|
||||
|
||||
status = classWmiInfo->ClassExecuteWmiMethod(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
wnode->MethodId,
|
||||
wnode->SizeDataBlock,
|
||||
bufferSize - wnode->DataBlockOffset,
|
||||
buffer + wnode->DataBlockOffset);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_ENABLE_EVENTS:
|
||||
{
|
||||
status = classWmiInfo->ClassWmiFunctionControl(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
EventGeneration,
|
||||
TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_DISABLE_EVENTS:
|
||||
{
|
||||
status = classWmiInfo->ClassWmiFunctionControl(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
EventGeneration,
|
||||
FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_ENABLE_COLLECTION:
|
||||
{
|
||||
status = classWmiInfo->ClassWmiFunctionControl(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
DataBlockCollection,
|
||||
TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_DISABLE_COLLECTION:
|
||||
{
|
||||
status = classWmiInfo->ClassWmiFunctionControl(
|
||||
DeviceObject,
|
||||
Irp,
|
||||
guidIndex,
|
||||
DataBlockCollection,
|
||||
FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return(status);
|
||||
} // end ClassSystemControl()
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassWmiCompleteRequest()
|
||||
|
||||
Routine Description:
|
||||
|
||||
|
||||
This routine will do the work of completing a WMI irp. Depending upon the
|
||||
the WMI request this routine will fixup the returned WNODE appropriately.
|
||||
|
||||
NOTE: This routine assumes that the ClassRemoveLock is held and it will
|
||||
release it.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Supplies a pointer to the device object for this request.
|
||||
|
||||
Irp - Supplies the Irp making the request.
|
||||
|
||||
Status - Status to complete the irp with. STATUS_BUFFER_TOO_SMALL is used
|
||||
to indicate that more buffer is required for the data requested.
|
||||
|
||||
BufferUsed - number of bytes of actual data to return (not including WMI
|
||||
specific structures)
|
||||
|
||||
PriorityBoost - priority boost to pass to ClassCompleteRequest
|
||||
|
||||
Return Value:
|
||||
|
||||
status
|
||||
|
||||
--*/
|
||||
SCSIPORTAPI
|
||||
NTSTATUS
|
||||
ClassWmiCompleteRequest(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN NTSTATUS Status,
|
||||
IN ULONG BufferUsed,
|
||||
IN CCHAR PriorityBoost
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
UCHAR MinorFunction;
|
||||
PUCHAR buffer;
|
||||
ULONG retSize;
|
||||
UCHAR minorFunction;
|
||||
ULONG bufferSize;
|
||||
|
||||
minorFunction = irpStack->MinorFunction;
|
||||
buffer = (PUCHAR)irpStack->Parameters.WMI.Buffer;
|
||||
bufferSize = irpStack->Parameters.WMI.BufferSize;
|
||||
|
||||
switch(minorFunction)
|
||||
{
|
||||
case IRP_MN_QUERY_ALL_DATA:
|
||||
{
|
||||
PWNODE_ALL_DATA wnode;
|
||||
PWNODE_TOO_SMALL wnodeTooSmall;
|
||||
ULONG bufferNeeded;
|
||||
|
||||
wnode = (PWNODE_ALL_DATA)buffer;
|
||||
|
||||
bufferNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
retSize = bufferNeeded;
|
||||
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
||||
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
||||
wnode->WnodeHeader.Flags |= WNODE_FLAG_FIXED_INSTANCE_SIZE;
|
||||
wnode->FixedInstanceSize = BufferUsed;
|
||||
wnode->InstanceCount = 1;
|
||||
|
||||
} else if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||||
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
||||
|
||||
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
||||
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
||||
wnodeTooSmall->SizeNeeded = sizeof(WNODE_ALL_DATA) + BufferUsed;
|
||||
retSize = sizeof(WNODE_TOO_SMALL);
|
||||
Status = STATUS_SUCCESS;
|
||||
} else {
|
||||
retSize = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_QUERY_SINGLE_INSTANCE:
|
||||
{
|
||||
PWNODE_SINGLE_INSTANCE wnode;
|
||||
PWNODE_TOO_SMALL wnodeTooSmall;
|
||||
ULONG bufferNeeded;
|
||||
|
||||
wnode = (PWNODE_SINGLE_INSTANCE)buffer;
|
||||
|
||||
bufferNeeded = wnode->DataBlockOffset + BufferUsed;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
retSize = bufferNeeded;
|
||||
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
||||
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
||||
wnode->SizeDataBlock = BufferUsed;
|
||||
|
||||
} else if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||||
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
||||
|
||||
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
||||
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
||||
wnodeTooSmall->SizeNeeded = bufferNeeded;
|
||||
retSize = sizeof(WNODE_TOO_SMALL);
|
||||
Status = STATUS_SUCCESS;
|
||||
} else {
|
||||
retSize = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case IRP_MN_EXECUTE_METHOD:
|
||||
{
|
||||
PWNODE_METHOD_ITEM wnode;
|
||||
PWNODE_TOO_SMALL wnodeTooSmall;
|
||||
ULONG bufferNeeded;
|
||||
|
||||
wnode = (PWNODE_METHOD_ITEM)buffer;
|
||||
|
||||
bufferNeeded = wnode->DataBlockOffset + BufferUsed;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
retSize = bufferNeeded;
|
||||
wnode->WnodeHeader.BufferSize = bufferNeeded;
|
||||
KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
|
||||
wnode->SizeDataBlock = BufferUsed;
|
||||
|
||||
} else if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||||
wnodeTooSmall = (PWNODE_TOO_SMALL)wnode;
|
||||
|
||||
wnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
||||
wnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
||||
wnodeTooSmall->SizeNeeded = bufferNeeded;
|
||||
retSize = sizeof(WNODE_TOO_SMALL);
|
||||
Status = STATUS_SUCCESS;
|
||||
} else {
|
||||
retSize = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
//
|
||||
// All other requests don't return any data
|
||||
retSize = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
Irp->IoStatus.Information = retSize;
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, PriorityBoost);
|
||||
return(Status);
|
||||
} // end ClassWmiCompleteRequest()
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassWmiFireEvent()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will fire a WMI event using the data buffer passed. This
|
||||
routine may be called at or below DPC level
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - Supplies a pointer to the device object for this event
|
||||
|
||||
Guid is pointer to the GUID that represents the event
|
||||
|
||||
InstanceIndex is the index of the instance of the event
|
||||
|
||||
EventDataSize is the number of bytes of data that is being fired with
|
||||
with the event
|
||||
|
||||
EventData is the data that is fired with the events. This may be NULL
|
||||
if there is no data associated with the event
|
||||
|
||||
|
||||
Return Value:
|
||||
|
||||
status
|
||||
|
||||
--*/
|
||||
NTSTATUS
|
||||
ClassWmiFireEvent(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN LPGUID Guid,
|
||||
IN ULONG InstanceIndex,
|
||||
IN ULONG EventDataSize,
|
||||
IN PVOID EventData
|
||||
)
|
||||
{
|
||||
|
||||
ULONG sizeNeeded;
|
||||
PWNODE_SINGLE_INSTANCE event;
|
||||
NTSTATUS status;
|
||||
|
||||
if (EventData == NULL)
|
||||
{
|
||||
EventDataSize = 0;
|
||||
}
|
||||
|
||||
sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventDataSize;
|
||||
|
||||
event = ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, CLASS_TAG_WMI);
|
||||
if (event != NULL)
|
||||
{
|
||||
event->WnodeHeader.Guid = *Guid;
|
||||
event->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(DeviceObject);
|
||||
event->WnodeHeader.BufferSize = sizeNeeded;
|
||||
event->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
|
||||
WNODE_FLAG_EVENT_ITEM |
|
||||
WNODE_FLAG_STATIC_INSTANCE_NAMES;
|
||||
KeQuerySystemTime(&event->WnodeHeader.TimeStamp);
|
||||
|
||||
event->InstanceIndex = InstanceIndex;
|
||||
event->SizeDataBlock = EventDataSize;
|
||||
event->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE);
|
||||
if (EventData != NULL)
|
||||
{
|
||||
RtlCopyMemory( &event->VariableData, EventData, EventDataSize);
|
||||
}
|
||||
|
||||
status = IoWMIWriteEvent(event);
|
||||
if (! NT_SUCCESS(status))
|
||||
{
|
||||
ExFreePool(event);
|
||||
}
|
||||
} else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return(status);
|
||||
} // end ClassWmiFireEvent()
|
||||
|
74
reactos/drivers/storage/classpnp/clntirp.c
Normal file
74
reactos/drivers/storage/classpnp/clntirp.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
clntirp.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Client IRP queuing routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/*
|
||||
* EnqueueDeferredClientIrp
|
||||
*
|
||||
* Note: we currently do not support Cancel for storage irps.
|
||||
*/
|
||||
VOID EnqueueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData, PIRP Irp)
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&FdoData->SpinLock, &oldIrql);
|
||||
InsertTailList(&FdoData->DeferredClientIrpList, &Irp->Tail.Overlay.ListEntry);
|
||||
KeReleaseSpinLock(&FdoData->SpinLock, oldIrql);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DequeueDeferredClientIrp
|
||||
*
|
||||
*/
|
||||
PIRP DequeueDeferredClientIrp(PCLASS_PRIVATE_FDO_DATA FdoData)
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
PLIST_ENTRY listEntry;
|
||||
PIRP irp;
|
||||
|
||||
KeAcquireSpinLock(&FdoData->SpinLock, &oldIrql);
|
||||
if (IsListEmpty(&FdoData->DeferredClientIrpList)){
|
||||
listEntry = NULL;
|
||||
}
|
||||
else {
|
||||
listEntry = RemoveHeadList(&FdoData->DeferredClientIrpList);
|
||||
}
|
||||
KeReleaseSpinLock(&FdoData->SpinLock, oldIrql);
|
||||
|
||||
if (listEntry == NULL) {
|
||||
irp = NULL;
|
||||
} else {
|
||||
irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
||||
ASSERT(irp->Type == IO_TYPE_IRP);
|
||||
InitializeListHead(&irp->Tail.Overlay.ListEntry);
|
||||
}
|
||||
|
||||
return irp;
|
||||
}
|
||||
|
||||
|
||||
|
977
reactos/drivers/storage/classpnp/create.c
Normal file
977
reactos/drivers/storage/classpnp/create.c
Normal file
|
@ -0,0 +1,977 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
class.c
|
||||
|
||||
Abstract:
|
||||
|
||||
SCSI class driver routines
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#define CLASS_INIT_GUID 0
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
ULONG BreakOnClose = 0;
|
||||
|
||||
PUCHAR LockTypeStrings[] = {
|
||||
"Simple",
|
||||
"Secure",
|
||||
"Internal"
|
||||
};
|
||||
|
||||
|
||||
PFILE_OBJECT_EXTENSION
|
||||
ClasspGetFsContext(
|
||||
IN PCOMMON_DEVICE_EXTENSION CommonExtension,
|
||||
IN PFILE_OBJECT FileObject
|
||||
);
|
||||
|
||||
VOID
|
||||
ClasspCleanupDisableMcn(
|
||||
IN PFILE_OBJECT_EXTENSION FsContext
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, ClassCreateClose)
|
||||
#pragma alloc_text(PAGE, ClasspCreateClose)
|
||||
#pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
|
||||
#pragma alloc_text(PAGE, ClasspEjectionControl)
|
||||
#pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
|
||||
#pragma alloc_text(PAGE, ClasspGetFsContext)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
ClassCreateClose(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
SCSI class driver create and close routine. This is called by the I/O system
|
||||
when the device is opened or closed.
|
||||
|
||||
Arguments:
|
||||
|
||||
DriverObject - Pointer to driver object created by system.
|
||||
|
||||
Irp - IRP involved.
|
||||
|
||||
Return Value:
|
||||
|
||||
Device-specific drivers return value or STATUS_SUCCESS.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
ULONG removeState;
|
||||
NTSTATUS status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// If we're getting a close request then we know the device object hasn't
|
||||
// been completely destroyed. Let the driver cleanup if necessary.
|
||||
//
|
||||
|
||||
removeState = ClassAcquireRemoveLock(DeviceObject, Irp);
|
||||
|
||||
//
|
||||
// Invoke the device-specific routine, if one exists. Otherwise complete
|
||||
// with SUCCESS
|
||||
//
|
||||
|
||||
if((removeState == NO_REMOVE) ||
|
||||
IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) {
|
||||
|
||||
status = ClasspCreateClose(DeviceObject, Irp);
|
||||
|
||||
if((NT_SUCCESS(status)) &&
|
||||
(commonExtension->DevInfo->ClassCreateClose)) {
|
||||
|
||||
return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp);
|
||||
}
|
||||
|
||||
} else {
|
||||
status = STATUS_DEVICE_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = status;
|
||||
ClassReleaseRemoveLock(DeviceObject, Irp);
|
||||
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ClasspCreateClose(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine will handle create/close operations for a given classpnp
|
||||
device if the class driver doesn't supply it's own handler. If there
|
||||
is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
|
||||
file object) then it will initialize a file extension on create or destroy
|
||||
the extension on a close.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object being opened or closed.
|
||||
|
||||
Irp - the create/close irp
|
||||
|
||||
Return Value:
|
||||
|
||||
status
|
||||
|
||||
--*/
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
PFILE_OBJECT fileObject = irpStack->FileObject;
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
|
||||
//
|
||||
// ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
|
||||
// in an inconsistent state. re-write to verify all args and allocate all
|
||||
// required resources, then pass the irp down, then complete the
|
||||
// transaction. this is because we also cannot forward the irp, then fail
|
||||
// it after it has succeeded a lower-level driver.
|
||||
//
|
||||
|
||||
if(irpStack->MajorFunction == IRP_MJ_CREATE) {
|
||||
|
||||
PIO_SECURITY_CONTEXT securityContext =
|
||||
irpStack->Parameters.Create.SecurityContext;
|
||||
DebugPrint((2,
|
||||
"ClasspCREATEClose: create received for device %p\n",
|
||||
DeviceObject));
|
||||
DebugPrint((2,
|
||||
"ClasspCREATEClose: desired access %lx\n",
|
||||
securityContext->DesiredAccess));
|
||||
DebugPrint((2,
|
||||
"ClasspCREATEClose: file object %lx\n",
|
||||
irpStack->FileObject));
|
||||
|
||||
ASSERT(BreakOnClose == FALSE);
|
||||
|
||||
if(irpStack->FileObject != NULL) {
|
||||
|
||||
PFILE_OBJECT_EXTENSION fsContext;
|
||||
|
||||
//
|
||||
// Allocate our own file object extension for this device object.
|
||||
//
|
||||
|
||||
status = AllocateDictionaryEntry(
|
||||
&commonExtension->FileObjectDictionary,
|
||||
(ULONGLONG) irpStack->FileObject,
|
||||
sizeof(FILE_OBJECT_EXTENSION),
|
||||
CLASS_TAG_FILE_OBJECT_EXTENSION,
|
||||
&fsContext);
|
||||
|
||||
if(NT_SUCCESS(status)) {
|
||||
|
||||
RtlZeroMemory(fsContext,
|
||||
sizeof(FILE_OBJECT_EXTENSION));
|
||||
|
||||
fsContext->FileObject = irpStack->FileObject;
|
||||
fsContext->DeviceObject = DeviceObject;
|
||||
} else if (status == STATUS_OBJECT_NAME_COLLISION) {
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCreateCLOSE: close received for device %p\n",
|
||||
DeviceObject));
|
||||
DebugPrint((2,
|
||||
"ClasspCreateCLOSE: file object %p\n",
|
||||
fileObject));
|
||||
|
||||
if(irpStack->FileObject != NULL) {
|
||||
|
||||
PFILE_OBJECT_EXTENSION fsContext =
|
||||
ClasspGetFsContext(commonExtension, irpStack->FileObject);
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCreateCLOSE: file extension %p\n",
|
||||
fsContext));
|
||||
|
||||
if(fsContext != NULL) {
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCreateCLOSE: extension is ours - "
|
||||
"freeing\n"));
|
||||
ASSERT(BreakOnClose == FALSE);
|
||||
|
||||
ClasspCleanupProtectedLocks(fsContext);
|
||||
|
||||
ClasspCleanupDisableMcn(fsContext);
|
||||
|
||||
FreeDictionaryEntry(&(commonExtension->FileObjectDictionary),
|
||||
fsContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Notify the lower levels about the create or close operation - give them
|
||||
// a chance to cleanup too.
|
||||
//
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCreateClose: %s for devobj %p\n",
|
||||
(NT_SUCCESS(status) ? "Success" : "FAILED"),
|
||||
DeviceObject));
|
||||
|
||||
|
||||
if(NT_SUCCESS(status)) {
|
||||
|
||||
KEVENT event;
|
||||
|
||||
//
|
||||
// Set up the event to wait on
|
||||
//
|
||||
|
||||
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||||
IoSetCompletionRoutine( Irp, ClassSignalCompletion, &event,
|
||||
TRUE, TRUE, TRUE);
|
||||
|
||||
status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
|
||||
|
||||
if(status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DebugPrint((ClassDebugError,
|
||||
"ClasspCreateClose: Lower driver failed, but we "
|
||||
"succeeded. This is a problem, lock counts will be "
|
||||
"out of sync between levels.\n"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
ClasspCleanupProtectedLocks(
|
||||
IN PFILE_OBJECT_EXTENSION FsContext
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension =
|
||||
FsContext->DeviceObject->DeviceExtension;
|
||||
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
|
||||
commonExtension->PartitionZeroExtension;
|
||||
|
||||
ULONG newDeviceLockCount = 1;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCleanupProtectedLocks called for %p\n",
|
||||
FsContext->DeviceObject));
|
||||
DebugPrint((2,
|
||||
"ClasspCleanupProtectedLocks - FsContext %p is locked "
|
||||
"%d times\n", FsContext, FsContext->LockCount));
|
||||
|
||||
ASSERT(BreakOnClose == FALSE);
|
||||
|
||||
//
|
||||
// Synchronize with ejection and ejection control requests.
|
||||
//
|
||||
|
||||
KeEnterCriticalRegion();
|
||||
KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
|
||||
UserRequest,
|
||||
UserMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
//
|
||||
// For each secure lock on this handle decrement the secured lock count
|
||||
// for the FDO. Keep track of the new value.
|
||||
//
|
||||
|
||||
if(FsContext->LockCount != 0) {
|
||||
|
||||
do {
|
||||
|
||||
InterlockedDecrement(&FsContext->LockCount);
|
||||
|
||||
newDeviceLockCount =
|
||||
InterlockedDecrement(&fdoExtension->ProtectedLockCount);
|
||||
|
||||
} while(FsContext->LockCount != 0);
|
||||
|
||||
//
|
||||
// If the new lock count has been dropped to zero then issue a lock
|
||||
// command to the device.
|
||||
//
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCleanupProtectedLocks: FDO secured lock count = %d "
|
||||
"lock count = %d\n",
|
||||
fdoExtension->ProtectedLockCount,
|
||||
fdoExtension->LockCount));
|
||||
|
||||
if((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {
|
||||
|
||||
SCSI_REQUEST_BLOCK srb;
|
||||
PCDB cdb;
|
||||
NTSTATUS status;
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCleanupProtectedLocks: FDO lock count dropped "
|
||||
"to zero\n"));
|
||||
|
||||
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
cdb = (PCDB) &(srb.Cdb);
|
||||
|
||||
srb.CdbLength = 6;
|
||||
|
||||
cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
|
||||
|
||||
//
|
||||
// TRUE - prevent media removal.
|
||||
// FALSE - allow media removal.
|
||||
//
|
||||
|
||||
cdb->MEDIA_REMOVAL.Prevent = FALSE;
|
||||
|
||||
//
|
||||
// Set timeout value.
|
||||
//
|
||||
|
||||
srb.TimeOutValue = fdoExtension->TimeOutValue;
|
||||
status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
|
||||
&srb,
|
||||
NULL,
|
||||
0,
|
||||
FALSE);
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspCleanupProtectedLocks: unlock request to drive "
|
||||
"returned status %lx\n", status));
|
||||
}
|
||||
}
|
||||
|
||||
KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
|
||||
IO_NO_INCREMENT,
|
||||
FALSE);
|
||||
KeLeaveCriticalRegion();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
ClasspCleanupDisableMcn(
|
||||
IN PFILE_OBJECT_EXTENSION FsContext
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension =
|
||||
FsContext->DeviceObject->DeviceExtension;
|
||||
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
|
||||
commonExtension->PartitionZeroExtension;
|
||||
|
||||
ULONG newCount = 1;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DebugPrint((ClassDebugTrace,
|
||||
"ClasspCleanupDisableMcn called for %p\n",
|
||||
FsContext->DeviceObject));
|
||||
DebugPrint((ClassDebugTrace,
|
||||
"ClasspCleanupDisableMcn - FsContext %p is disabled "
|
||||
"%d times\n", FsContext, FsContext->McnDisableCount));
|
||||
|
||||
//
|
||||
// For each secure lock on this handle decrement the secured lock count
|
||||
// for the FDO. Keep track of the new value.
|
||||
//
|
||||
|
||||
while(FsContext->McnDisableCount != 0) {
|
||||
FsContext->McnDisableCount--;
|
||||
ClassEnableMediaChangeDetection(fdoExtension);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* BUGBUG REMOVE this old function implementation as soon as the
|
||||
* boottime pagefile problems with the new one (below)
|
||||
* are resolved.
|
||||
*/
|
||||
NTSTATUS
|
||||
ClasspEjectionControl(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PIRP Irp,
|
||||
IN MEDIA_LOCK_TYPE LockType,
|
||||
IN BOOLEAN Lock
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension =
|
||||
(PCOMMON_DEVICE_EXTENSION) FdoExtension;
|
||||
|
||||
PFILE_OBJECT_EXTENSION fsContext = NULL;
|
||||
NTSTATUS status;
|
||||
PSCSI_REQUEST_BLOCK srb = NULL;
|
||||
BOOLEAN countChanged = FALSE;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// Interlock with ejection and secure lock cleanup code. This is a
|
||||
// user request so we can allow the stack to get swapped out while we
|
||||
// wait for synchronization.
|
||||
//
|
||||
|
||||
status = KeWaitForSingleObject(
|
||||
&(FdoExtension->EjectSynchronizationEvent),
|
||||
UserRequest,
|
||||
UserMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
ASSERT(status == STATUS_SUCCESS);
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspEjectionControl: "
|
||||
"Received request for %s lock type\n",
|
||||
LockTypeStrings[LockType]
|
||||
));
|
||||
|
||||
_SEH2_TRY {
|
||||
PCDB cdb;
|
||||
|
||||
srb = ClasspAllocateSrb(FdoExtension);
|
||||
|
||||
if(srb == NULL) {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
_SEH2_LEAVE;
|
||||
}
|
||||
|
||||
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
|
||||
cdb = (PCDB) srb->Cdb;
|
||||
|
||||
//
|
||||
// Determine if this is a "secured" request.
|
||||
//
|
||||
|
||||
if(LockType == SecureMediaLock) {
|
||||
|
||||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT fileObject = irpStack->FileObject;
|
||||
|
||||
//
|
||||
// Make sure that the file object we are supplied has a
|
||||
// proper FsContext before we try doing a secured lock.
|
||||
//
|
||||
|
||||
if(fileObject != NULL) {
|
||||
fsContext = ClasspGetFsContext(commonExtension, fileObject);
|
||||
}
|
||||
|
||||
if (fsContext == NULL) {
|
||||
|
||||
//
|
||||
// This handle isn't setup correctly. We can't let the
|
||||
// operation go.
|
||||
//
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
_SEH2_LEAVE;
|
||||
}
|
||||
}
|
||||
|
||||
if(Lock) {
|
||||
|
||||
//
|
||||
// This is a lock command. Reissue the command in case bus or
|
||||
// device was reset and the lock was cleared.
|
||||
// note: may need to decrement count if actual lock operation
|
||||
// failed....
|
||||
//
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
FdoExtension->LockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
fsContext->LockCount++;
|
||||
FdoExtension->ProtectedLockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
FdoExtension->InternalLockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// This is an unlock command. If it's a secured one then make sure
|
||||
// the caller has a lock outstanding or return an error.
|
||||
// note: may need to re-increment the count if actual unlock
|
||||
// operation fails....
|
||||
//
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
if(FdoExtension->LockCount != 0) {
|
||||
FdoExtension->LockCount--;
|
||||
countChanged = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
if(fsContext->LockCount == 0) {
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
_SEH2_LEAVE;
|
||||
}
|
||||
fsContext->LockCount--;
|
||||
FdoExtension->ProtectedLockCount--;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
ASSERT(FdoExtension->InternalLockCount != 0);
|
||||
FdoExtension->InternalLockCount--;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We only send an unlock command to the drive if both the
|
||||
// secured and unsecured lock counts have dropped to zero.
|
||||
//
|
||||
|
||||
if((FdoExtension->ProtectedLockCount != 0) ||
|
||||
(FdoExtension->InternalLockCount != 0) ||
|
||||
(FdoExtension->LockCount != 0)) {
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
_SEH2_LEAVE;
|
||||
}
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
|
||||
|
||||
srb->CdbLength = 6;
|
||||
cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
|
||||
|
||||
//
|
||||
// TRUE - prevent media removal.
|
||||
// FALSE - allow media removal.
|
||||
//
|
||||
|
||||
cdb->MEDIA_REMOVAL.Prevent = Lock;
|
||||
|
||||
//
|
||||
// Set timeout value.
|
||||
//
|
||||
|
||||
srb->TimeOutValue = FdoExtension->TimeOutValue;
|
||||
|
||||
//
|
||||
// The actual lock operation on the device isn't so important
|
||||
// as the internal lock counts. Ignore failures.
|
||||
//
|
||||
|
||||
status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
|
||||
srb,
|
||||
NULL,
|
||||
0,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
} _SEH2_FINALLY {
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
DebugPrint((2,
|
||||
"ClasspEjectionControl: FAILED status %x -- "
|
||||
"reverting lock counts\n", status));
|
||||
|
||||
if (countChanged) {
|
||||
|
||||
//
|
||||
// have to revert to previous counts if the
|
||||
// lock/unlock operation actually failed.
|
||||
//
|
||||
|
||||
if(Lock) {
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
FdoExtension->LockCount--;
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
fsContext->LockCount--;
|
||||
FdoExtension->ProtectedLockCount--;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
FdoExtension->InternalLockCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
FdoExtension->LockCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
fsContext->LockCount++;
|
||||
FdoExtension->ProtectedLockCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
FdoExtension->InternalLockCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspEjectionControl: Succeeded\n"));
|
||||
|
||||
}
|
||||
|
||||
DebugPrint((2,
|
||||
"ClasspEjectionControl: "
|
||||
"Current Counts: Internal: %x Secure: %x Simple: %x\n",
|
||||
FdoExtension->InternalLockCount,
|
||||
FdoExtension->ProtectedLockCount,
|
||||
FdoExtension->LockCount
|
||||
));
|
||||
|
||||
KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
|
||||
IO_NO_INCREMENT,
|
||||
FALSE);
|
||||
if (srb) {
|
||||
ClassFreeOrReuseSrb(FdoExtension, srb);
|
||||
}
|
||||
|
||||
} _SEH2_END;
|
||||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* BUGBUG RESTORE
|
||||
* This is a new implementation of the function that doesn't thrash memory
|
||||
* or depend on the srbLookasideList.
|
||||
* HOWEVER, it seems to cause pagefile initialization to fail during boot
|
||||
* for some reason. Need to resolve this before switching to this function.
|
||||
*/
|
||||
NTSTATUS
|
||||
ClasspEjectionControl(
|
||||
IN PDEVICE_OBJECT Fdo,
|
||||
IN PIRP Irp,
|
||||
IN MEDIA_LOCK_TYPE LockType,
|
||||
IN BOOLEAN Lock
|
||||
)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PFILE_OBJECT_EXTENSION fsContext;
|
||||
BOOLEAN fileHandleOk = TRUE;
|
||||
BOOLEAN countChanged = FALSE;
|
||||
NTSTATUS status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
status = KeWaitForSingleObject(
|
||||
&fdoExt->EjectSynchronizationEvent,
|
||||
UserRequest,
|
||||
UserMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
ASSERT(status == STATUS_SUCCESS);
|
||||
|
||||
/*
|
||||
* If this is a "secured" request, we have to make sure
|
||||
* that the file handle is valid.
|
||||
*/
|
||||
if (LockType == SecureMediaLock){
|
||||
PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/*
|
||||
* Make sure that the file object we are supplied has a
|
||||
* proper FsContext before we try doing a secured lock.
|
||||
*/
|
||||
if (thisSp->FileObject){
|
||||
PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt;
|
||||
fsContext = ClasspGetFsContext(commonExt, thisSp->FileObject);
|
||||
}
|
||||
else {
|
||||
fsContext = NULL;
|
||||
}
|
||||
|
||||
if (!fsContext){
|
||||
ASSERT(fsContext);
|
||||
fileHandleOk = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (fileHandleOk){
|
||||
|
||||
/*
|
||||
* Adjust the lock counts and make sure they make sense.
|
||||
*/
|
||||
status = STATUS_SUCCESS;
|
||||
if (Lock){
|
||||
switch(LockType) {
|
||||
case SimpleMediaLock:
|
||||
fdoExt->LockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
case SecureMediaLock:
|
||||
fsContext->LockCount++;
|
||||
fdoExt->ProtectedLockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
case InternalMediaLock:
|
||||
fdoExt->InternalLockCount++;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* This is an unlock command. If it's a secured one then make sure
|
||||
* the caller has a lock outstanding or return an error.
|
||||
*/
|
||||
switch (LockType){
|
||||
case SimpleMediaLock:
|
||||
if (fdoExt->LockCount > 0){
|
||||
fdoExt->LockCount--;
|
||||
countChanged = TRUE;
|
||||
}
|
||||
else {
|
||||
ASSERT(fdoExt->LockCount > 0);
|
||||
status = STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
case SecureMediaLock:
|
||||
if (fsContext->LockCount > 0){
|
||||
ASSERT(fdoExt->ProtectedLockCount > 0);
|
||||
fsContext->LockCount--;
|
||||
fdoExt->ProtectedLockCount--;
|
||||
countChanged = TRUE;
|
||||
}
|
||||
else {
|
||||
ASSERT(fsContext->LockCount > 0);
|
||||
status = STATUS_INVALID_DEVICE_STATE;
|
||||
}
|
||||
break;
|
||||
case InternalMediaLock:
|
||||
ASSERT(fdoExt->InternalLockCount > 0);
|
||||
fdoExt->InternalLockCount--;
|
||||
countChanged = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)){
|
||||
/*
|
||||
* We only send an unlock command to the drive if
|
||||
* all the lock counts have dropped to zero.
|
||||
*/
|
||||
if (!Lock &&
|
||||
(fdoExt->ProtectedLockCount ||
|
||||
fdoExt->InternalLockCount ||
|
||||
fdoExt->LockCount)){
|
||||
|
||||
/*
|
||||
* The lock count is still positive, so don't unlock yet.
|
||||
*/
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
|
||||
/*
|
||||
* The device isn't removable media. don't send a cmd.
|
||||
*/
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else {
|
||||
TRANSFER_PACKET *pkt;
|
||||
|
||||
pkt = DequeueFreeTransferPacket(Fdo, TRUE);
|
||||
if (pkt){
|
||||
KEVENT event;
|
||||
|
||||
/*
|
||||
* Store the number of packets servicing the irp (one)
|
||||
* inside the original IRP. It will be used to counted down
|
||||
* to zero when the packet completes.
|
||||
* Initialize the original IRP's status to success.
|
||||
* If the packet fails, we will set it to the error status.
|
||||
*/
|
||||
Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
|
||||
/*
|
||||
* Set this up as a SYNCHRONOUS transfer, submit it,
|
||||
* and wait for the packet to complete. The result
|
||||
* status will be written to the original irp.
|
||||
*/
|
||||
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
||||
SetupEjectionTransferPacket(pkt, Lock, &event, Irp);
|
||||
SubmitTransferPacket(pkt);
|
||||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||||
status = Irp->IoStatus.Status;
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status) && countChanged) {
|
||||
|
||||
//
|
||||
// have to revert to previous counts if the
|
||||
// lock/unlock operation actually failed.
|
||||
//
|
||||
|
||||
if(Lock) {
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
FdoExtension->LockCount--;
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
fsContext->LockCount--;
|
||||
FdoExtension->ProtectedLockCount--;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
FdoExtension->InternalLockCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch(LockType) {
|
||||
|
||||
case SimpleMediaLock: {
|
||||
FdoExtension->LockCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
case SecureMediaLock: {
|
||||
fsContext->LockCount++;
|
||||
FdoExtension->ProtectedLockCount++;
|
||||
break;
|
||||
}
|
||||
|
||||
case InternalMediaLock: {
|
||||
FdoExtension->InternalLockCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
PFILE_OBJECT_EXTENSION
|
||||
ClasspGetFsContext(
|
||||
IN PCOMMON_DEVICE_EXTENSION CommonExtension,
|
||||
IN PFILE_OBJECT FileObject
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary),
|
||||
(ULONGLONG) FileObject);
|
||||
}
|
||||
|
48
reactos/drivers/storage/classpnp/data.c
Normal file
48
reactos/drivers/storage/classpnp/data.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
disk.c
|
||||
|
||||
Abstract:
|
||||
|
||||
SCSI disk class driver
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg("PAGE")
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define FDO_HACK_CANNOT_LOCK_MEDIA (0x00000001)
|
||||
#define FDO_HACK_GESN_IS_BAD (0x00000002)
|
||||
*/
|
||||
|
||||
CLASSPNP_SCAN_FOR_SPECIAL_INFO ClassBadItems[] = {
|
||||
{ "" , "MITSUMI CD-ROM FX240" , NULL, 0x02 },
|
||||
{ "" , "MITSUMI CD-ROM FX320" , NULL, 0x02 },
|
||||
{ "" , "MITSUMI CD-ROM FX322" , NULL, 0x02 },
|
||||
{ "" , "COMPAQ CRD-8481B" , NULL, 0x04 },
|
||||
{ NULL , NULL , NULL, 0x0 }
|
||||
};
|
||||
|
||||
|
||||
GUID ClassGuidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
|
||||
|
||||
#ifdef ALLOC_DATA_PRAGMA
|
||||
#pragma data_seg()
|
||||
#endif
|
||||
|
693
reactos/drivers/storage/classpnp/debug.c
Normal file
693
reactos/drivers/storage/classpnp/debug.c
Normal file
|
@ -0,0 +1,693 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
debug.c
|
||||
|
||||
Abstract:
|
||||
|
||||
CLASSPNP debug code and data
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
#if DBG
|
||||
|
||||
//
|
||||
// default to not breaking in for lost irps, five minutes before we even
|
||||
// bother checking for lost irps, using standard debug print macros, and
|
||||
// using a 64k debug print buffer
|
||||
//
|
||||
|
||||
#ifndef CLASS_GLOBAL_BREAK_ON_LOST_IRPS
|
||||
#error "CLASS_GLOBAL_BREAK_ON_LOST_IRPS undefined"
|
||||
#define CLASS_GLOBAL_BREAK_ON_LOST_IRPS 0
|
||||
#endif // CLASS_GLOBAL_BREAK_ON_LOST_IRPS
|
||||
|
||||
#ifndef CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
|
||||
#error "CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB undefined"
|
||||
#define CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB 300
|
||||
#endif // CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
|
||||
|
||||
#ifndef CLASS_GLOBAL_USE_DELAYED_RETRY
|
||||
#error "CLASS_GLOBAL_USE_DELAYED_RETRY undefined"
|
||||
#define CLASS_GLOBAL_USE_DELAYED_RETRY 1
|
||||
#endif // CLASS_GLOBAL_USE_DELAYED_RETRY
|
||||
|
||||
#ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
|
||||
#error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT undefined"
|
||||
#define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT 0
|
||||
#endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
|
||||
|
||||
#ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
|
||||
#error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE undefined"
|
||||
#define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE 512
|
||||
#endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
|
||||
|
||||
#ifndef CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
|
||||
#error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS undefined"
|
||||
#define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS 512
|
||||
#endif // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
|
||||
|
||||
#pragma data_seg("NONPAGE")
|
||||
|
||||
|
||||
|
||||
CLASSPNP_GLOBALS ClasspnpGlobals;
|
||||
|
||||
//
|
||||
// the low sixteen bits are used to see if the debug level is high enough
|
||||
// the high sixteen bits are used to singly enable debug levels 1-16
|
||||
//
|
||||
LONG ClassDebug = 0xFFFFFFFF;
|
||||
|
||||
BOOLEAN DebugTrapOnWarn = FALSE;
|
||||
|
||||
VOID ClasspInitializeDebugGlobals()
|
||||
{
|
||||
KIRQL irql;
|
||||
|
||||
if (InterlockedCompareExchange(&ClasspnpGlobals.Initializing, 1, 0) == 0) {
|
||||
|
||||
KeInitializeSpinLock(&ClasspnpGlobals.SpinLock);
|
||||
|
||||
KeAcquireSpinLock(&ClasspnpGlobals.SpinLock, &irql);
|
||||
|
||||
DebugPrint((1, "CLASSPNP.SYS => Initializing ClasspnpGlobals...\n"));
|
||||
|
||||
ClasspnpGlobals.Buffer = NULL;
|
||||
ClasspnpGlobals.Index = -1;
|
||||
ClasspnpGlobals.BreakOnLostIrps = CLASS_GLOBAL_BREAK_ON_LOST_IRPS;
|
||||
ClasspnpGlobals.EachBufferSize = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE;
|
||||
ClasspnpGlobals.NumberOfBuffers = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS;
|
||||
ClasspnpGlobals.SecondsToWaitForIrps = CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB;
|
||||
|
||||
//
|
||||
// this should be the last item set
|
||||
//
|
||||
|
||||
ClasspnpGlobals.UseBufferedDebugPrint = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT;
|
||||
|
||||
KeReleaseSpinLock(&ClasspnpGlobals.SpinLock, irql);
|
||||
|
||||
InterlockedExchange(&ClasspnpGlobals.Initialized, 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassDebugPrint()
|
||||
|
||||
Routine Description:
|
||||
|
||||
Debug print for all class drivers, NOOP on FRE versions.
|
||||
Allows printing to a debug buffer (with auto fallback to kdprint) by
|
||||
properly setting the Globals in classpnp on CHK versions.
|
||||
|
||||
Arguments:
|
||||
|
||||
Debug print level, or from 0 to 3 for legacy drivers.
|
||||
|
||||
Return Value:
|
||||
|
||||
None
|
||||
|
||||
--*/
|
||||
VOID ClassDebugPrint(CLASS_DEBUG_LEVEL DebugPrintLevel, PCCHAR DebugMessage, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, DebugMessage);
|
||||
|
||||
if ((DebugPrintLevel <= (ClassDebug & 0x0000ffff)) ||
|
||||
((1 << (DebugPrintLevel + 15)) & ClassDebug)) {
|
||||
|
||||
if (ClasspnpGlobals.UseBufferedDebugPrint &&
|
||||
ClasspnpGlobals.Buffer == NULL) {
|
||||
|
||||
//
|
||||
// this double-check prevents always taking
|
||||
// a spinlock just to ensure we have a buffer
|
||||
//
|
||||
|
||||
KIRQL irql;
|
||||
|
||||
KeAcquireSpinLock(&ClasspnpGlobals.SpinLock, &irql);
|
||||
if (ClasspnpGlobals.Buffer == NULL) {
|
||||
|
||||
SIZE_T bufferSize;
|
||||
bufferSize = ClasspnpGlobals.NumberOfBuffers *
|
||||
ClasspnpGlobals.EachBufferSize;
|
||||
DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
|
||||
"ClassDebugPrint: Allocating %x bytes for "
|
||||
"classdebugprint buffer\n", bufferSize);
|
||||
ClasspnpGlobals.Index = -1;
|
||||
ClasspnpGlobals.Buffer =
|
||||
ExAllocatePoolWithTag(NonPagedPool, bufferSize, 'bDcS');
|
||||
DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
|
||||
"ClassDebugPrint: Allocated buffer at %p\n",
|
||||
ClasspnpGlobals.Buffer);
|
||||
|
||||
}
|
||||
KeReleaseSpinLock(&ClasspnpGlobals.SpinLock, irql);
|
||||
|
||||
}
|
||||
|
||||
if (ClasspnpGlobals.UseBufferedDebugPrint &&
|
||||
ClasspnpGlobals.Buffer != NULL) {
|
||||
|
||||
//
|
||||
// we never free the buffer, so once it exists,
|
||||
// we can just print to it with immunity
|
||||
//
|
||||
|
||||
ULONG index;
|
||||
PUCHAR buffer;
|
||||
index = InterlockedIncrement(&ClasspnpGlobals.Index);
|
||||
index %= ClasspnpGlobals.NumberOfBuffers;
|
||||
index *= (ULONG)ClasspnpGlobals.EachBufferSize;
|
||||
|
||||
buffer = ClasspnpGlobals.Buffer;
|
||||
buffer += index;
|
||||
|
||||
_vsnprintf(buffer, ClasspnpGlobals.EachBufferSize, DebugMessage, ap);
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// either we could not allocate a buffer for debug prints
|
||||
// or buffered debug prints are disabled
|
||||
//
|
||||
vDbgPrintEx(-1, DPFLTR_ERROR_LEVEL, DebugMessage, ap);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
}
|
||||
|
||||
|
||||
char *DbgGetIoctlStr(ULONG ioctl)
|
||||
{
|
||||
char *ioctlStr = "?";
|
||||
|
||||
switch (ioctl){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(ioctlCode) case ioctlCode: ioctlStr = #ioctlCode; break;
|
||||
|
||||
MAKE_CASE(IOCTL_STORAGE_CHECK_VERIFY)
|
||||
MAKE_CASE(IOCTL_STORAGE_CHECK_VERIFY2)
|
||||
MAKE_CASE(IOCTL_STORAGE_MEDIA_REMOVAL)
|
||||
MAKE_CASE(IOCTL_STORAGE_EJECT_MEDIA)
|
||||
MAKE_CASE(IOCTL_STORAGE_LOAD_MEDIA)
|
||||
MAKE_CASE(IOCTL_STORAGE_LOAD_MEDIA2)
|
||||
MAKE_CASE(IOCTL_STORAGE_RESERVE)
|
||||
MAKE_CASE(IOCTL_STORAGE_RELEASE)
|
||||
MAKE_CASE(IOCTL_STORAGE_FIND_NEW_DEVICES)
|
||||
MAKE_CASE(IOCTL_STORAGE_EJECTION_CONTROL)
|
||||
MAKE_CASE(IOCTL_STORAGE_MCN_CONTROL)
|
||||
MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_TYPES)
|
||||
MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_TYPES_EX)
|
||||
MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
|
||||
MAKE_CASE(IOCTL_STORAGE_GET_HOTPLUG_INFO)
|
||||
MAKE_CASE(IOCTL_STORAGE_RESET_BUS)
|
||||
MAKE_CASE(IOCTL_STORAGE_RESET_DEVICE)
|
||||
MAKE_CASE(IOCTL_STORAGE_GET_DEVICE_NUMBER)
|
||||
MAKE_CASE(IOCTL_STORAGE_PREDICT_FAILURE)
|
||||
MAKE_CASE(IOCTL_STORAGE_QUERY_PROPERTY)
|
||||
MAKE_CASE(OBSOLETE_IOCTL_STORAGE_RESET_BUS)
|
||||
MAKE_CASE(OBSOLETE_IOCTL_STORAGE_RESET_DEVICE)
|
||||
}
|
||||
|
||||
return ioctlStr;
|
||||
}
|
||||
|
||||
char *DbgGetScsiOpStr(PSCSI_REQUEST_BLOCK Srb)
|
||||
{
|
||||
PCDB pCdb = (PCDB)Srb->Cdb;
|
||||
UCHAR scsiOp = pCdb->CDB6GENERIC.OperationCode;
|
||||
char *scsiOpStr = "?";
|
||||
|
||||
switch (scsiOp){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(scsiOpCode) case scsiOpCode: scsiOpStr = #scsiOpCode; break;
|
||||
|
||||
MAKE_CASE(SCSIOP_TEST_UNIT_READY)
|
||||
MAKE_CASE(SCSIOP_REWIND) // aka SCSIOP_REZERO_UNIT
|
||||
MAKE_CASE(SCSIOP_REQUEST_BLOCK_ADDR)
|
||||
MAKE_CASE(SCSIOP_REQUEST_SENSE)
|
||||
MAKE_CASE(SCSIOP_FORMAT_UNIT)
|
||||
MAKE_CASE(SCSIOP_READ_BLOCK_LIMITS)
|
||||
MAKE_CASE(SCSIOP_INIT_ELEMENT_STATUS) // aka SCSIOP_REASSIGN_BLOCKS
|
||||
MAKE_CASE(SCSIOP_RECEIVE) // aka SCSIOP_READ6
|
||||
MAKE_CASE(SCSIOP_SEND) // aka SCSIOP_WRITE6, SCSIOP_PRINT
|
||||
MAKE_CASE(SCSIOP_SLEW_PRINT) // aka SCSIOP_SEEK6, SCSIOP_TRACK_SELECT
|
||||
MAKE_CASE(SCSIOP_SEEK_BLOCK)
|
||||
MAKE_CASE(SCSIOP_PARTITION)
|
||||
MAKE_CASE(SCSIOP_READ_REVERSE)
|
||||
MAKE_CASE(SCSIOP_FLUSH_BUFFER) // aka SCSIOP_WRITE_FILEMARKS
|
||||
MAKE_CASE(SCSIOP_SPACE)
|
||||
MAKE_CASE(SCSIOP_INQUIRY)
|
||||
MAKE_CASE(SCSIOP_VERIFY6)
|
||||
MAKE_CASE(SCSIOP_RECOVER_BUF_DATA)
|
||||
MAKE_CASE(SCSIOP_MODE_SELECT)
|
||||
MAKE_CASE(SCSIOP_RESERVE_UNIT)
|
||||
MAKE_CASE(SCSIOP_RELEASE_UNIT)
|
||||
MAKE_CASE(SCSIOP_COPY)
|
||||
MAKE_CASE(SCSIOP_ERASE)
|
||||
MAKE_CASE(SCSIOP_MODE_SENSE)
|
||||
MAKE_CASE(SCSIOP_START_STOP_UNIT) // aka SCSIOP_STOP_PRINT, SCSIOP_LOAD_UNLOAD
|
||||
MAKE_CASE(SCSIOP_RECEIVE_DIAGNOSTIC)
|
||||
MAKE_CASE(SCSIOP_SEND_DIAGNOSTIC)
|
||||
MAKE_CASE(SCSIOP_MEDIUM_REMOVAL)
|
||||
MAKE_CASE(SCSIOP_READ_FORMATTED_CAPACITY)
|
||||
MAKE_CASE(SCSIOP_READ_CAPACITY)
|
||||
MAKE_CASE(SCSIOP_READ)
|
||||
MAKE_CASE(SCSIOP_WRITE)
|
||||
MAKE_CASE(SCSIOP_SEEK) // aka SCSIOP_LOCATE, SCSIOP_POSITION_TO_ELEMENT
|
||||
MAKE_CASE(SCSIOP_WRITE_VERIFY)
|
||||
MAKE_CASE(SCSIOP_VERIFY)
|
||||
MAKE_CASE(SCSIOP_SEARCH_DATA_HIGH)
|
||||
MAKE_CASE(SCSIOP_SEARCH_DATA_EQUAL)
|
||||
MAKE_CASE(SCSIOP_SEARCH_DATA_LOW)
|
||||
MAKE_CASE(SCSIOP_SET_LIMITS)
|
||||
MAKE_CASE(SCSIOP_READ_POSITION)
|
||||
MAKE_CASE(SCSIOP_SYNCHRONIZE_CACHE)
|
||||
MAKE_CASE(SCSIOP_COMPARE)
|
||||
MAKE_CASE(SCSIOP_COPY_COMPARE)
|
||||
MAKE_CASE(SCSIOP_WRITE_DATA_BUFF)
|
||||
MAKE_CASE(SCSIOP_READ_DATA_BUFF)
|
||||
MAKE_CASE(SCSIOP_CHANGE_DEFINITION)
|
||||
MAKE_CASE(SCSIOP_READ_SUB_CHANNEL)
|
||||
MAKE_CASE(SCSIOP_READ_TOC)
|
||||
MAKE_CASE(SCSIOP_READ_HEADER)
|
||||
MAKE_CASE(SCSIOP_PLAY_AUDIO)
|
||||
MAKE_CASE(SCSIOP_GET_CONFIGURATION)
|
||||
MAKE_CASE(SCSIOP_PLAY_AUDIO_MSF)
|
||||
MAKE_CASE(SCSIOP_PLAY_TRACK_INDEX)
|
||||
MAKE_CASE(SCSIOP_PLAY_TRACK_RELATIVE)
|
||||
MAKE_CASE(SCSIOP_GET_EVENT_STATUS)
|
||||
MAKE_CASE(SCSIOP_PAUSE_RESUME)
|
||||
MAKE_CASE(SCSIOP_LOG_SELECT)
|
||||
MAKE_CASE(SCSIOP_LOG_SENSE)
|
||||
MAKE_CASE(SCSIOP_STOP_PLAY_SCAN)
|
||||
MAKE_CASE(SCSIOP_READ_DISK_INFORMATION)
|
||||
MAKE_CASE(SCSIOP_READ_TRACK_INFORMATION)
|
||||
MAKE_CASE(SCSIOP_RESERVE_TRACK_RZONE)
|
||||
MAKE_CASE(SCSIOP_SEND_OPC_INFORMATION)
|
||||
MAKE_CASE(SCSIOP_MODE_SELECT10)
|
||||
MAKE_CASE(SCSIOP_MODE_SENSE10)
|
||||
MAKE_CASE(SCSIOP_CLOSE_TRACK_SESSION)
|
||||
MAKE_CASE(SCSIOP_READ_BUFFER_CAPACITY)
|
||||
MAKE_CASE(SCSIOP_SEND_CUE_SHEET)
|
||||
MAKE_CASE(SCSIOP_PERSISTENT_RESERVE_IN)
|
||||
MAKE_CASE(SCSIOP_PERSISTENT_RESERVE_OUT)
|
||||
MAKE_CASE(SCSIOP_REPORT_LUNS)
|
||||
MAKE_CASE(SCSIOP_BLANK)
|
||||
MAKE_CASE(SCSIOP_SEND_KEY)
|
||||
MAKE_CASE(SCSIOP_REPORT_KEY)
|
||||
MAKE_CASE(SCSIOP_MOVE_MEDIUM)
|
||||
MAKE_CASE(SCSIOP_LOAD_UNLOAD_SLOT) // aka SCSIOP_EXCHANGE_MEDIUM
|
||||
MAKE_CASE(SCSIOP_SET_READ_AHEAD)
|
||||
MAKE_CASE(SCSIOP_READ_DVD_STRUCTURE)
|
||||
MAKE_CASE(SCSIOP_REQUEST_VOL_ELEMENT)
|
||||
MAKE_CASE(SCSIOP_SEND_VOLUME_TAG)
|
||||
MAKE_CASE(SCSIOP_READ_ELEMENT_STATUS)
|
||||
MAKE_CASE(SCSIOP_READ_CD_MSF)
|
||||
MAKE_CASE(SCSIOP_SCAN_CD)
|
||||
MAKE_CASE(SCSIOP_SET_CD_SPEED)
|
||||
MAKE_CASE(SCSIOP_PLAY_CD)
|
||||
MAKE_CASE(SCSIOP_MECHANISM_STATUS)
|
||||
MAKE_CASE(SCSIOP_READ_CD)
|
||||
MAKE_CASE(SCSIOP_SEND_DVD_STRUCTURE)
|
||||
MAKE_CASE(SCSIOP_INIT_ELEMENT_RANGE)
|
||||
}
|
||||
|
||||
return scsiOpStr;
|
||||
}
|
||||
|
||||
|
||||
char *DbgGetSrbStatusStr(PSCSI_REQUEST_BLOCK Srb)
|
||||
{
|
||||
char *srbStatStr = "?";
|
||||
|
||||
switch (Srb->SrbStatus){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(srbStat) \
|
||||
case srbStat: \
|
||||
srbStatStr = #srbStat; \
|
||||
break; \
|
||||
case srbStat|SRB_STATUS_QUEUE_FROZEN: \
|
||||
srbStatStr = #srbStat "|SRB_STATUS_QUEUE_FROZEN"; \
|
||||
break; \
|
||||
case srbStat|SRB_STATUS_AUTOSENSE_VALID: \
|
||||
srbStatStr = #srbStat "|SRB_STATUS_AUTOSENSE_VALID"; \
|
||||
break; \
|
||||
case srbStat|SRB_STATUS_QUEUE_FROZEN|SRB_STATUS_AUTOSENSE_VALID: \
|
||||
srbStatStr = #srbStat "|SRB_STATUS_QUEUE_FROZEN|SRB_STATUS_AUTOSENSE_VALID"; \
|
||||
break;
|
||||
|
||||
MAKE_CASE(SRB_STATUS_PENDING)
|
||||
MAKE_CASE(SRB_STATUS_SUCCESS)
|
||||
MAKE_CASE(SRB_STATUS_ABORTED)
|
||||
MAKE_CASE(SRB_STATUS_ABORT_FAILED)
|
||||
MAKE_CASE(SRB_STATUS_ERROR)
|
||||
MAKE_CASE(SRB_STATUS_BUSY)
|
||||
MAKE_CASE(SRB_STATUS_INVALID_REQUEST)
|
||||
MAKE_CASE(SRB_STATUS_INVALID_PATH_ID)
|
||||
MAKE_CASE(SRB_STATUS_NO_DEVICE)
|
||||
MAKE_CASE(SRB_STATUS_TIMEOUT)
|
||||
MAKE_CASE(SRB_STATUS_SELECTION_TIMEOUT)
|
||||
MAKE_CASE(SRB_STATUS_COMMAND_TIMEOUT)
|
||||
MAKE_CASE(SRB_STATUS_MESSAGE_REJECTED)
|
||||
MAKE_CASE(SRB_STATUS_BUS_RESET)
|
||||
MAKE_CASE(SRB_STATUS_PARITY_ERROR)
|
||||
MAKE_CASE(SRB_STATUS_REQUEST_SENSE_FAILED)
|
||||
MAKE_CASE(SRB_STATUS_NO_HBA)
|
||||
MAKE_CASE(SRB_STATUS_DATA_OVERRUN)
|
||||
MAKE_CASE(SRB_STATUS_UNEXPECTED_BUS_FREE)
|
||||
MAKE_CASE(SRB_STATUS_PHASE_SEQUENCE_FAILURE)
|
||||
MAKE_CASE(SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
|
||||
MAKE_CASE(SRB_STATUS_REQUEST_FLUSHED)
|
||||
MAKE_CASE(SRB_STATUS_INVALID_LUN)
|
||||
MAKE_CASE(SRB_STATUS_INVALID_TARGET_ID)
|
||||
MAKE_CASE(SRB_STATUS_BAD_FUNCTION)
|
||||
MAKE_CASE(SRB_STATUS_ERROR_RECOVERY)
|
||||
MAKE_CASE(SRB_STATUS_NOT_POWERED)
|
||||
MAKE_CASE(SRB_STATUS_INTERNAL_ERROR)
|
||||
}
|
||||
|
||||
return srbStatStr;
|
||||
}
|
||||
|
||||
|
||||
char *DbgGetSenseCodeStr(PSCSI_REQUEST_BLOCK Srb)
|
||||
{
|
||||
char *senseCodeStr = "?";
|
||||
|
||||
if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
|
||||
PSENSE_DATA senseData;
|
||||
UCHAR senseCode;
|
||||
|
||||
ASSERT(Srb->SenseInfoBuffer);
|
||||
senseData = Srb->SenseInfoBuffer;
|
||||
senseCode = senseData->SenseKey & 0xf;
|
||||
|
||||
switch (senseCode){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(snsCod) case snsCod: senseCodeStr = #snsCod; break;
|
||||
|
||||
MAKE_CASE(SCSI_SENSE_NO_SENSE)
|
||||
MAKE_CASE(SCSI_SENSE_RECOVERED_ERROR)
|
||||
MAKE_CASE(SCSI_SENSE_NOT_READY)
|
||||
MAKE_CASE(SCSI_SENSE_MEDIUM_ERROR)
|
||||
MAKE_CASE(SCSI_SENSE_HARDWARE_ERROR)
|
||||
MAKE_CASE(SCSI_SENSE_ILLEGAL_REQUEST)
|
||||
MAKE_CASE(SCSI_SENSE_UNIT_ATTENTION)
|
||||
MAKE_CASE(SCSI_SENSE_DATA_PROTECT)
|
||||
MAKE_CASE(SCSI_SENSE_BLANK_CHECK)
|
||||
MAKE_CASE(SCSI_SENSE_UNIQUE)
|
||||
MAKE_CASE(SCSI_SENSE_COPY_ABORTED)
|
||||
MAKE_CASE(SCSI_SENSE_ABORTED_COMMAND)
|
||||
MAKE_CASE(SCSI_SENSE_EQUAL)
|
||||
MAKE_CASE(SCSI_SENSE_VOL_OVERFLOW)
|
||||
MAKE_CASE(SCSI_SENSE_MISCOMPARE)
|
||||
MAKE_CASE(SCSI_SENSE_RESERVED)
|
||||
}
|
||||
}
|
||||
|
||||
return senseCodeStr;
|
||||
}
|
||||
|
||||
|
||||
char *DbgGetAdditionalSenseCodeStr(PSCSI_REQUEST_BLOCK Srb)
|
||||
{
|
||||
char *adSenseCodeStr = "?";
|
||||
|
||||
if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
|
||||
PSENSE_DATA senseData;
|
||||
UCHAR adSenseCode;
|
||||
|
||||
ASSERT(Srb->SenseInfoBuffer);
|
||||
senseData = Srb->SenseInfoBuffer;
|
||||
adSenseCode = senseData->AdditionalSenseCode;
|
||||
|
||||
switch (adSenseCode){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(adSnsCod) case adSnsCod: adSenseCodeStr = #adSnsCod; break;
|
||||
|
||||
MAKE_CASE(SCSI_ADSENSE_NO_SENSE)
|
||||
MAKE_CASE(SCSI_ADSENSE_LUN_NOT_READY)
|
||||
MAKE_CASE(SCSI_ADSENSE_TRACK_ERROR)
|
||||
MAKE_CASE(SCSI_ADSENSE_SEEK_ERROR)
|
||||
MAKE_CASE(SCSI_ADSENSE_REC_DATA_NOECC)
|
||||
MAKE_CASE(SCSI_ADSENSE_REC_DATA_ECC)
|
||||
MAKE_CASE(SCSI_ADSENSE_ILLEGAL_COMMAND)
|
||||
MAKE_CASE(SCSI_ADSENSE_ILLEGAL_BLOCK)
|
||||
MAKE_CASE(SCSI_ADSENSE_INVALID_CDB)
|
||||
MAKE_CASE(SCSI_ADSENSE_INVALID_LUN)
|
||||
MAKE_CASE(SCSI_ADSENSE_WRITE_PROTECT) // aka SCSI_ADWRITE_PROTECT
|
||||
MAKE_CASE(SCSI_ADSENSE_MEDIUM_CHANGED)
|
||||
MAKE_CASE(SCSI_ADSENSE_BUS_RESET)
|
||||
MAKE_CASE(SCSI_ADSENSE_INVALID_MEDIA)
|
||||
MAKE_CASE(SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
|
||||
MAKE_CASE(SCSI_ADSENSE_POSITION_ERROR)
|
||||
MAKE_CASE(SCSI_ADSENSE_OPERATOR_REQUEST)
|
||||
MAKE_CASE(SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED)
|
||||
MAKE_CASE(SCSI_ADSENSE_COPY_PROTECTION_FAILURE)
|
||||
MAKE_CASE(SCSI_ADSENSE_VENDOR_UNIQUE)
|
||||
MAKE_CASE(SCSI_ADSENSE_MUSIC_AREA)
|
||||
MAKE_CASE(SCSI_ADSENSE_DATA_AREA)
|
||||
MAKE_CASE(SCSI_ADSENSE_VOLUME_OVERFLOW)
|
||||
}
|
||||
}
|
||||
|
||||
return adSenseCodeStr;
|
||||
}
|
||||
|
||||
|
||||
char *DbgGetAdditionalSenseCodeQualifierStr(PSCSI_REQUEST_BLOCK Srb)
|
||||
{
|
||||
char *adSenseCodeQualStr = "?";
|
||||
|
||||
if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
|
||||
PSENSE_DATA senseData;
|
||||
UCHAR adSenseCode;
|
||||
UCHAR adSenseCodeQual;
|
||||
|
||||
ASSERT(Srb->SenseInfoBuffer);
|
||||
senseData = Srb->SenseInfoBuffer;
|
||||
adSenseCode = senseData->AdditionalSenseCode;
|
||||
adSenseCodeQual = senseData->AdditionalSenseCodeQualifier;
|
||||
|
||||
switch (adSenseCode){
|
||||
|
||||
#undef MAKE_CASE
|
||||
#define MAKE_CASE(adSnsCodQual) case adSnsCodQual: adSenseCodeQualStr = #adSnsCodQual; break;
|
||||
|
||||
case SCSI_ADSENSE_LUN_NOT_READY:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
|
||||
MAKE_CASE(SCSI_SENSEQ_BECOMING_READY)
|
||||
MAKE_CASE(SCSI_SENSEQ_INIT_COMMAND_REQUIRED)
|
||||
MAKE_CASE(SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED)
|
||||
MAKE_CASE(SCSI_SENSEQ_FORMAT_IN_PROGRESS)
|
||||
MAKE_CASE(SCSI_SENSEQ_REBUILD_IN_PROGRESS)
|
||||
MAKE_CASE(SCSI_SENSEQ_RECALCULATION_IN_PROGRESS)
|
||||
MAKE_CASE(SCSI_SENSEQ_OPERATION_IN_PROGRESS)
|
||||
MAKE_CASE(SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_NO_SENSE:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_FILEMARK_DETECTED)
|
||||
MAKE_CASE(SCSI_SENSEQ_END_OF_MEDIA_DETECTED)
|
||||
MAKE_CASE(SCSI_SENSEQ_SETMARK_DETECTED)
|
||||
MAKE_CASE(SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_ILLEGAL_BLOCK:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_ILLEGAL_ELEMENT_ADDR)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_POSITION_ERROR:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_DESTINATION_FULL)
|
||||
MAKE_CASE(SCSI_SENSEQ_SOURCE_EMPTY)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_INVALID_MEDIA:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_INCOMPATIBLE_MEDIA_INSTALLED)
|
||||
MAKE_CASE(SCSI_SENSEQ_UNKNOWN_FORMAT)
|
||||
MAKE_CASE(SCSI_SENSEQ_INCOMPATIBLE_FORMAT)
|
||||
MAKE_CASE(SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_OPERATOR_REQUEST:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_STATE_CHANGE_INPUT)
|
||||
MAKE_CASE(SCSI_SENSEQ_MEDIUM_REMOVAL)
|
||||
MAKE_CASE(SCSI_SENSEQ_WRITE_PROTECT_ENABLE)
|
||||
MAKE_CASE(SCSI_SENSEQ_WRITE_PROTECT_DISABLE)
|
||||
}
|
||||
break;
|
||||
case SCSI_ADSENSE_COPY_PROTECTION_FAILURE:
|
||||
switch (adSenseCodeQual){
|
||||
MAKE_CASE(SCSI_SENSEQ_AUTHENTICATION_FAILURE)
|
||||
MAKE_CASE(SCSI_SENSEQ_KEY_NOT_PRESENT)
|
||||
MAKE_CASE(SCSI_SENSEQ_KEY_NOT_ESTABLISHED)
|
||||
MAKE_CASE(SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION)
|
||||
MAKE_CASE(SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT)
|
||||
MAKE_CASE(SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return adSenseCodeQualStr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DbgCheckReturnedPkt
|
||||
*
|
||||
* Check a completed TRANSFER_PACKET for all sorts of error conditions
|
||||
* and warn/trap appropriately.
|
||||
*/
|
||||
VOID DbgCheckReturnedPkt(TRANSFER_PACKET *Pkt)
|
||||
{
|
||||
PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
|
||||
ASSERT(Pkt->Srb.OriginalRequest == Pkt->Irp);
|
||||
ASSERT(Pkt->Srb.DataBuffer == Pkt->BufPtrCopy);
|
||||
ASSERT(Pkt->Srb.DataTransferLength <= Pkt->BufLenCopy);
|
||||
ASSERT(!Pkt->Irp->CancelRoutine);
|
||||
|
||||
if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_PENDING){
|
||||
DBGERR(("SRB completed with status PENDING in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
(ULONG)Pkt->Srb.SrbStatus,
|
||||
Pkt->Irp->IoStatus.Status));
|
||||
}
|
||||
else if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SUCCESS){
|
||||
/*
|
||||
* Make sure SRB and IRP status match.
|
||||
*/
|
||||
if (!NT_SUCCESS(Pkt->Irp->IoStatus.Status)){
|
||||
DBGWARN(("SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
(ULONG)Pkt->Srb.SrbStatus,
|
||||
Pkt->Irp->IoStatus.Status));
|
||||
}
|
||||
|
||||
if (Pkt->Irp->IoStatus.Information != Pkt->Srb.DataTransferLength){
|
||||
DBGERR(("SRB and IRP result transfer lengths don't match in succeeded packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%xh).",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
Pkt->Srb.DataTransferLength,
|
||||
Pkt->Irp->IoStatus.Information));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (NT_SUCCESS(Pkt->Irp->IoStatus.Status)){
|
||||
DBGWARN(("SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
(ULONG)Pkt->Srb.SrbStatus,
|
||||
Pkt->Irp->IoStatus.Status));
|
||||
}
|
||||
DBGTRACE(ClassDebugWarning, ("Packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
(ULONG)Pkt->Srb.SrbStatus,
|
||||
Pkt->Irp->IoStatus.Status,
|
||||
DBGGETSENSECODESTR(&Pkt->Srb),
|
||||
DBGGETADSENSECODESTR(&Pkt->Srb),
|
||||
DBGGETADSENSEQUALIFIERSTR(&Pkt->Srb)));
|
||||
|
||||
/*
|
||||
* If the SRB failed with underrun or overrun, then the actual
|
||||
* transferred length should be returned in both SRB and IRP.
|
||||
* (SRB's only have an error status for overrun, so it's overloaded).
|
||||
*/
|
||||
if ((SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) &&
|
||||
(Pkt->Irp->IoStatus.Information != Pkt->Srb.DataTransferLength)){
|
||||
DBGERR(("SRB and IRP result transfer lengths don't match in failed packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%xh).",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
Pkt->Srb.DataTransferLength,
|
||||
Pkt->Irp->IoStatus.Information));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Some miniport drivers have been caught changing the SCSI operation
|
||||
* code in the SRB. This is absolutely disallowed as it breaks our error handling.
|
||||
*/
|
||||
switch (pCdb->CDB10.OperationCode){
|
||||
case SCSIOP_MEDIUM_REMOVAL:
|
||||
case SCSIOP_MODE_SENSE:
|
||||
case SCSIOP_READ_CAPACITY:
|
||||
case SCSIOP_READ:
|
||||
case SCSIOP_WRITE:
|
||||
case SCSIOP_START_STOP_UNIT:
|
||||
break;
|
||||
default:
|
||||
DBGERR(("Miniport illegally changed Srb.Cdb.OperationCode in packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)",
|
||||
Pkt,
|
||||
DBGGETSCSIOPSTR(&Pkt->Srb),
|
||||
DBGGETSRBSTATUSSTR(&Pkt->Srb),
|
||||
(ULONG)Pkt->Srb.SrbStatus,
|
||||
Pkt->Irp->IoStatus.Status,
|
||||
DBGGETSENSECODESTR(&Pkt->Srb),
|
||||
DBGGETADSENSECODESTR(&Pkt->Srb),
|
||||
DBGGETADSENSEQUALIFIERSTR(&Pkt->Srb)));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// We have to keep this in the retail build for legacy.
|
||||
VOID ClassDebugPrint(CLASS_DEBUG_LEVEL DebugPrintLevel, PCCHAR DebugMessage, ...)
|
||||
{
|
||||
DbgPrint("retail build\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
148
reactos/drivers/storage/classpnp/debug.h
Normal file
148
reactos/drivers/storage/classpnp/debug.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
debug.h
|
||||
|
||||
Abstract:
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
VOID ClassDebugPrint(CLASS_DEBUG_LEVEL DebugPrintLevel, PCCHAR DebugMessage, ...);
|
||||
|
||||
#if DBG
|
||||
|
||||
typedef struct _CLASSPNP_GLOBALS {
|
||||
|
||||
//
|
||||
// whether or not to ASSERT for lost irps
|
||||
//
|
||||
|
||||
ULONG BreakOnLostIrps;
|
||||
ULONG SecondsToWaitForIrps;
|
||||
|
||||
//
|
||||
// use a buffered debug print to help
|
||||
// catch timing issues that do not
|
||||
// reproduce with std debugprints enabled
|
||||
//
|
||||
|
||||
ULONG UseBufferedDebugPrint;
|
||||
ULONG UseDelayedRetry;
|
||||
|
||||
//
|
||||
// the next four are the buffered printing support
|
||||
// (currently unimplemented) and require the spinlock
|
||||
// to use
|
||||
//
|
||||
|
||||
ULONG Index; // index into buffer
|
||||
KSPIN_LOCK SpinLock;
|
||||
PUCHAR Buffer; // requires spinlock to access
|
||||
ULONG NumberOfBuffers; // number of buffers available
|
||||
SIZE_T EachBufferSize; // size of each buffer
|
||||
|
||||
//
|
||||
// interlocked variables to initialize
|
||||
// this data only once
|
||||
//
|
||||
|
||||
LONG Initializing;
|
||||
LONG Initialized;
|
||||
|
||||
} CLASSPNP_GLOBALS, *PCLASSPNP_GLOBALS;
|
||||
|
||||
#define DBGTRACE(dbgTraceLevel, args_in_parens) \
|
||||
if (ClassDebug & (1 << (dbgTraceLevel+15))){ \
|
||||
DbgPrint("CLASSPNP> *** TRACE *** (file %s, line %d)\n", __FILE__, __LINE__ ); \
|
||||
DbgPrint(" > "); \
|
||||
DbgPrint args_in_parens; \
|
||||
DbgPrint("\n"); \
|
||||
if (DebugTrapOnWarn && (dbgTraceLevel == ClassDebugWarning)){ \
|
||||
DbgBreakPoint(); \
|
||||
} \
|
||||
}
|
||||
#define DBGWARN(args_in_parens) \
|
||||
{ \
|
||||
DbgPrint("CLASSPNP> *** WARNING *** (file %s, line %d)\n", __FILE__, __LINE__ ); \
|
||||
DbgPrint(" > "); \
|
||||
DbgPrint args_in_parens; \
|
||||
DbgPrint("\n"); \
|
||||
if (DebugTrapOnWarn){ \
|
||||
DbgBreakPoint(); \
|
||||
} \
|
||||
}
|
||||
#define DBGERR(args_in_parens) \
|
||||
{ \
|
||||
DbgPrint("CLASSPNP> *** ERROR *** (file %s, line %d)\n", __FILE__, __LINE__ ); \
|
||||
DbgPrint(" > "); \
|
||||
DbgPrint args_in_parens; \
|
||||
DbgPrint("\n"); \
|
||||
DbgBreakPoint(); \
|
||||
}
|
||||
#define DBGTRAP(args_in_parens) \
|
||||
{ \
|
||||
DbgPrint("CLASSPNP> *** COVERAGE TRAP *** (file %s, line %d)\n", __FILE__, __LINE__ ); \
|
||||
DbgPrint(" > "); \
|
||||
DbgPrint args_in_parens; \
|
||||
DbgPrint("\n"); \
|
||||
DbgBreakPoint(); \
|
||||
}
|
||||
|
||||
|
||||
#define DBGGETIOCTLSTR(_ioctl) DbgGetIoctlStr(_ioctl)
|
||||
#define DBGGETSCSIOPSTR(_pSrb) DbgGetScsiOpStr(_pSrb)
|
||||
#define DBGGETSENSECODESTR(_pSrb) DbgGetSenseCodeStr(_pSrb)
|
||||
#define DBGGETADSENSECODESTR(_pSrb) DbgGetAdditionalSenseCodeStr(_pSrb)
|
||||
#define DBGGETADSENSEQUALIFIERSTR(_pSrb) DbgGetAdditionalSenseCodeQualifierStr(_pSrb)
|
||||
#define DBGCHECKRETURNEDPKT(_pkt) DbgCheckReturnedPkt(_pkt)
|
||||
#define DBGGETSRBSTATUSSTR(_pSrb) DbgGetSrbStatusStr(_pSrb)
|
||||
|
||||
VOID ClasspInitializeDebugGlobals();
|
||||
char *DbgGetIoctlStr(ULONG ioctl);
|
||||
char *DbgGetScsiOpStr(PSCSI_REQUEST_BLOCK Srb);
|
||||
char *DbgGetSenseCodeStr(PSCSI_REQUEST_BLOCK Srb);
|
||||
char *DbgGetAdditionalSenseCodeStr(PSCSI_REQUEST_BLOCK Srb);
|
||||
char *DbgGetAdditionalSenseCodeQualifierStr(PSCSI_REQUEST_BLOCK Srb);
|
||||
VOID DbgCheckReturnedPkt(TRANSFER_PACKET *Pkt);
|
||||
char *DbgGetSrbStatusStr(PSCSI_REQUEST_BLOCK Srb);
|
||||
|
||||
|
||||
extern CLASSPNP_GLOBALS ClasspnpGlobals;
|
||||
extern LONG ClassDebug;
|
||||
extern BOOLEAN DebugTrapOnWarn;
|
||||
|
||||
#else
|
||||
|
||||
#define ClasspInitializeDebugGlobals()
|
||||
#define DBGWARN(args_in_parens)
|
||||
#define DBGERR(args_in_parens)
|
||||
#define DBGTRACE(dbgTraceLevel, args_in_parens)
|
||||
#define DBGTRAP(args_in_parens)
|
||||
|
||||
#define DBGGETIOCTLSTR(_ioctl)
|
||||
#define DBGGETSCSIOPSTR(_pSrb)
|
||||
#define DBGGETSENSECODESTR(_pSrb)
|
||||
#define DBGGETADSENSECODESTR(_pSrb)
|
||||
#define DBGGETADSENSEQUALIFIERSTR(_pSrb)
|
||||
#define DBGCHECKRETURNEDPKT(_pkt)
|
||||
#define DBGGETSRBSTATUSSTR(_pSrb)
|
||||
|
||||
#endif
|
||||
|
||||
|
216
reactos/drivers/storage/classpnp/dictlib.c
Normal file
216
reactos/drivers/storage/classpnp/dictlib.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1990 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
dictlib.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Support library for maintaining a dictionary list (list of objects
|
||||
referenced by a key value).
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
This module generates a static library
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <classpnp.h>
|
||||
|
||||
#define DICTIONARY_SIGNATURE (((ULONG)'dict' << 32) + 'sig ')
|
||||
|
||||
struct _DICTIONARY_HEADER {
|
||||
struct _DICTIONARY_HEADER* Next;
|
||||
ULONGLONG Key;
|
||||
UCHAR Data[0];
|
||||
};
|
||||
|
||||
struct _DICTIONARY_HEADER;
|
||||
typedef struct _DICTIONARY_HEADER DICTIONARY_HEADER, *PDICTIONARY_HEADER;
|
||||
|
||||
|
||||
VOID
|
||||
InitializeDictionary(
|
||||
IN PDICTIONARY Dictionary
|
||||
)
|
||||
{
|
||||
RtlZeroMemory(Dictionary, sizeof(Dictionary));
|
||||
Dictionary->Signature = DICTIONARY_SIGNATURE;
|
||||
KeInitializeSpinLock(&Dictionary->SpinLock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
TestDictionarySignature(
|
||||
IN PDICTIONARY Dictionary
|
||||
)
|
||||
{
|
||||
return Dictionary->Signature == DICTIONARY_SIGNATURE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
AllocateDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key,
|
||||
IN ULONG Size,
|
||||
IN ULONG Tag,
|
||||
OUT PVOID *Entry
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER header;
|
||||
KIRQL oldIrql;
|
||||
PDICTIONARY_HEADER *entry;
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
*Entry = NULL;
|
||||
|
||||
header = ExAllocatePoolWithTag(NonPagedPool,
|
||||
Size + sizeof(DICTIONARY_HEADER),
|
||||
Tag);
|
||||
|
||||
if(header == NULL) {
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(header, sizeof(DICTIONARY_HEADER) + Size);
|
||||
header->Key = Key;
|
||||
|
||||
//
|
||||
// Find the correct location for this entry in the dictionary.
|
||||
//
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
TRY {
|
||||
|
||||
entry = &(Dictionary->List);
|
||||
|
||||
while(*entry != NULL) {
|
||||
if((*entry)->Key == Key) {
|
||||
|
||||
//
|
||||
// Dictionary must have unique keys.
|
||||
//
|
||||
|
||||
status = STATUS_OBJECT_NAME_COLLISION;
|
||||
LEAVE;
|
||||
|
||||
} else if ((*entry)->Key < Key) {
|
||||
|
||||
//
|
||||
// We will go ahead and insert the key in here.
|
||||
//
|
||||
break;
|
||||
} else {
|
||||
entry = &((*entry)->Next);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If we make it here then we will go ahead and do the insertion.
|
||||
//
|
||||
|
||||
header->Next = *entry;
|
||||
*entry = header;
|
||||
|
||||
} FINALLY {
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
if(!NT_SUCCESS(status)) {
|
||||
ExFreePool(header);
|
||||
} else {
|
||||
*Entry = (PVOID) header->Data;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
PVOID
|
||||
GetDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN ULONGLONG Key
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER entry;
|
||||
PVOID data;
|
||||
KIRQL oldIrql;
|
||||
|
||||
|
||||
data = NULL;
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
entry = Dictionary->List;
|
||||
while (entry != NULL) {
|
||||
|
||||
if (entry->Key == Key) {
|
||||
data = entry->Data;
|
||||
break;
|
||||
} else {
|
||||
entry = entry->Next;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FreeDictionaryEntry(
|
||||
IN PDICTIONARY Dictionary,
|
||||
IN PVOID Entry
|
||||
)
|
||||
{
|
||||
PDICTIONARY_HEADER header;
|
||||
PDICTIONARY_HEADER *entry;
|
||||
KIRQL oldIrql;
|
||||
BOOLEAN found;
|
||||
|
||||
found = FALSE;
|
||||
header = CONTAINING_RECORD(Entry, DICTIONARY_HEADER, Data);
|
||||
|
||||
KeAcquireSpinLock(&(Dictionary->SpinLock), &oldIrql);
|
||||
|
||||
entry = &(Dictionary->List);
|
||||
while(*entry != NULL) {
|
||||
|
||||
if(*entry == header) {
|
||||
*entry = header->Next;
|
||||
found = TRUE;
|
||||
break;
|
||||
} else {
|
||||
entry = &(*entry)->Next;
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&(Dictionary->SpinLock), oldIrql);
|
||||
|
||||
//
|
||||
// calling this w/an invalid pointer invalidates the dictionary system,
|
||||
// so ASSERT() that we never try to Free something not in the list
|
||||
//
|
||||
|
||||
ASSERT(found);
|
||||
if (found) {
|
||||
ExFreePool(header);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
418
reactos/drivers/storage/classpnp/lock.c
Normal file
418
reactos/drivers/storage/classpnp/lock.c
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1990 - 1998
|
||||
|
||||
Module Name:
|
||||
|
||||
lock.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This is the NT SCSI port driver.
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
This module is a driver dll for scsi miniports.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
LONG LockHighWatermark = 0;
|
||||
LONG LockLowWatermark = 0;
|
||||
LONG MaxLockedMinutes = 5;
|
||||
|
||||
//
|
||||
// Structure used for tracking remove lock allocations in checked builds
|
||||
//
|
||||
typedef struct _REMOVE_TRACKING_BLOCK {
|
||||
struct _REMOVE_TRACKING_BLOCK *NextBlock;
|
||||
PVOID Tag;
|
||||
LARGE_INTEGER TimeLocked;
|
||||
PCSTR File;
|
||||
ULONG Line;
|
||||
} REMOVE_TRACKING_BLOCK, *PREMOVE_TRACKING_BLOCK;
|
||||
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassAcquireRemoveLockEx()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to acquire the remove lock on the device object.
|
||||
While the lock is held, the caller can assume that no pending pnp REMOVE
|
||||
requests will be completed.
|
||||
|
||||
The lock should be acquired immediately upon entering a dispatch routine.
|
||||
It should also be acquired before creating any new reference to the
|
||||
device object if there's a chance of releasing the reference before the
|
||||
new one is done.
|
||||
|
||||
This routine will return TRUE if the lock was successfully acquired or
|
||||
FALSE if it cannot be because the device object has already been removed.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object to lock
|
||||
|
||||
Tag - Used for tracking lock allocation and release. If an irp is
|
||||
specified when acquiring the lock then the same Tag must be
|
||||
used to release the lock before the Tag is completed.
|
||||
|
||||
Return Value:
|
||||
|
||||
The value of the IsRemoved flag in the device extension. If this is
|
||||
non-zero then the device object has received a Remove irp and non-cleanup
|
||||
IRP's should fail.
|
||||
|
||||
If the value is REMOVE_COMPLETE, the caller should not even release the
|
||||
lock.
|
||||
|
||||
--*/
|
||||
ULONG
|
||||
ClassAcquireRemoveLockEx(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN OPTIONAL PVOID Tag,
|
||||
IN PCSTR File,
|
||||
IN ULONG Line
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
LONG lockValue;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Grab the remove lock
|
||||
//
|
||||
lockValue = InterlockedIncrement(&commonExtension->RemoveLock);
|
||||
|
||||
#if DBG
|
||||
|
||||
DebugPrint((ClassDebugRemoveLock, "ClassAcquireRemoveLock: "
|
||||
"Acquired for Object %p & irp %p - count is %d\n",
|
||||
DeviceObject, Tag, lockValue));
|
||||
|
||||
ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
|
||||
(lockValue > 0));
|
||||
|
||||
ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
|
||||
((LockHighWatermark == 0) ||
|
||||
(lockValue != LockHighWatermark)));
|
||||
|
||||
if (commonExtension->IsRemoved != REMOVE_COMPLETE){
|
||||
PREMOVE_TRACKING_BLOCK trackingBlock;
|
||||
|
||||
trackingBlock = ExAllocatePool(NonPagedPool,
|
||||
sizeof(REMOVE_TRACKING_BLOCK));
|
||||
|
||||
if(trackingBlock == NULL) {
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
commonExtension->RemoveTrackingUntrackedCount++;
|
||||
|
||||
DebugPrint((ClassDebugWarning, ">>>>>ClassAcquireRemoveLock: "
|
||||
"Cannot track Tag %p - currently %d untracked requsts\n",
|
||||
Tag, commonExtension->RemoveTrackingUntrackedCount));
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
oldIrql);
|
||||
}
|
||||
else {
|
||||
PREMOVE_TRACKING_BLOCK *removeTrackingList =
|
||||
(PREMOVE_TRACKING_BLOCK)&commonExtension->RemoveTrackingList;
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
trackingBlock->Tag = Tag;
|
||||
|
||||
trackingBlock->File = File;
|
||||
trackingBlock->Line = Line;
|
||||
|
||||
KeQueryTickCount((&trackingBlock->TimeLocked));
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
while(*removeTrackingList != NULL) {
|
||||
|
||||
if((*removeTrackingList)->Tag > Tag) {
|
||||
break;
|
||||
}
|
||||
|
||||
if((*removeTrackingList)->Tag == Tag) {
|
||||
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassAcquireRemoveLock: "
|
||||
"already tracking Tag %p\n", Tag));
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassAcquireRemoveLock: "
|
||||
"acquired in file %s on line %d\n",
|
||||
(*removeTrackingList)->File,
|
||||
(*removeTrackingList)->Line));
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
removeTrackingList = &((*removeTrackingList)->NextBlock);
|
||||
}
|
||||
|
||||
trackingBlock->NextBlock = *removeTrackingList;
|
||||
*removeTrackingList = trackingBlock;
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
oldIrql);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return (commonExtension->IsRemoved);
|
||||
}
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassReleaseRemoveLock()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called to release the remove lock on the device object. It
|
||||
must be called when finished using a previously locked reference to the
|
||||
device object. If an Tag was specified when acquiring the lock then the
|
||||
same Tag must be specified when releasing the lock.
|
||||
|
||||
When the lock count reduces to zero, this routine will signal the waiting
|
||||
remove Tag to delete the device object. As a result the DeviceObject
|
||||
pointer should not be used again once the lock has been released.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object to lock
|
||||
|
||||
Tag - The irp (if any) specified when acquiring the lock. This is used
|
||||
for lock tracking purposes
|
||||
|
||||
Return Value:
|
||||
|
||||
none
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClassReleaseRemoveLock(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN OPTIONAL PIRP Tag
|
||||
)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
LONG lockValue;
|
||||
|
||||
#if DBG
|
||||
PREMOVE_TRACKING_BLOCK *listEntry =
|
||||
(PREMOVE_TRACKING_BLOCK)&commonExtension->RemoveTrackingList;
|
||||
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
LONGLONG maxCount;
|
||||
|
||||
BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE);
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
if(isRemoved) {
|
||||
DBGTRAP(("ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
|
||||
InterlockedDecrement(&(commonExtension->RemoveLock));
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check the tick count and make sure this thing hasn't been locked
|
||||
// for more than MaxLockedMinutes.
|
||||
//
|
||||
|
||||
maxCount = KeQueryTimeIncrement() * 10; // microseconds
|
||||
maxCount *= 1000; // milliseconds
|
||||
maxCount *= 1000; // seconds
|
||||
maxCount *= 60; // minutes
|
||||
maxCount *= MaxLockedMinutes;
|
||||
|
||||
DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
|
||||
"maxCount = %0I64x\n", maxCount));
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
while(*listEntry != NULL) {
|
||||
|
||||
PREMOVE_TRACKING_BLOCK block;
|
||||
LARGE_INTEGER difference;
|
||||
|
||||
block = *listEntry;
|
||||
|
||||
KeQueryTickCount((&difference));
|
||||
|
||||
difference.QuadPart -= block->TimeLocked.QuadPart;
|
||||
|
||||
DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
|
||||
"Object %p (tag %p) locked for %I64d ticks\n",
|
||||
DeviceObject, block->Tag, difference.QuadPart));
|
||||
|
||||
if(difference.QuadPart >= maxCount) {
|
||||
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Object %p (tag %p) locked for %I64d ticks - TOO LONG\n",
|
||||
DeviceObject, block->Tag, difference.QuadPart));
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Lock acquired in file %s on line %d\n",
|
||||
block->File, block->Line));
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
if((found == FALSE) && ((*listEntry)->Tag == Tag)) {
|
||||
|
||||
*listEntry = block->NextBlock;
|
||||
ExFreePool(block);
|
||||
found = TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
listEntry = &((*listEntry)->NextBlock);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
if(commonExtension->RemoveTrackingUntrackedCount == 0) {
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Couldn't find Tag %p in the lock tracking list\n",
|
||||
Tag));
|
||||
ASSERT(FALSE);
|
||||
} else {
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassReleaseRemoveLock: "
|
||||
"Couldn't find Tag %p in the lock tracking list - "
|
||||
"may be one of the %d untracked requests still "
|
||||
"outstanding\n",
|
||||
Tag,
|
||||
commonExtension->RemoveTrackingUntrackedCount));
|
||||
|
||||
commonExtension->RemoveTrackingUntrackedCount--;
|
||||
ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
oldIrql);
|
||||
|
||||
#endif
|
||||
|
||||
lockValue = InterlockedDecrement(&commonExtension->RemoveLock);
|
||||
|
||||
DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
|
||||
"Released for Object %p & irp %p - count is %d\n",
|
||||
DeviceObject, Tag, lockValue));
|
||||
|
||||
ASSERT(lockValue >= 0);
|
||||
|
||||
ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
|
||||
((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));
|
||||
|
||||
if(lockValue == 0) {
|
||||
|
||||
ASSERT(commonExtension->IsRemoved);
|
||||
|
||||
//
|
||||
// The device needs to be removed. Signal the remove event
|
||||
// that it's safe to go ahead.
|
||||
//
|
||||
|
||||
DebugPrint((ClassDebugRemoveLock, "ClassReleaseRemoveLock: "
|
||||
"Release for object %p & irp %p caused lock to go to zero\n",
|
||||
DeviceObject, Tag));
|
||||
|
||||
KeSetEvent(&commonExtension->RemoveEvent,
|
||||
IO_NO_INCREMENT,
|
||||
FALSE);
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*++////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ClassCompleteRequest()
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is a wrapper around (and should be used instead of)
|
||||
IoCompleteRequest. It is used primarily for debugging purposes.
|
||||
The routine will assert if the Irp being completed is still holding
|
||||
the release lock.
|
||||
|
||||
Arguments:
|
||||
|
||||
DeviceObject - the device object that was handling this request
|
||||
|
||||
Irp - the irp to be completed by IoCompleteRequest
|
||||
|
||||
PriorityBoost - the priority boost to pass to IoCompleteRequest
|
||||
|
||||
Return Value:
|
||||
|
||||
none
|
||||
|
||||
--*/
|
||||
VOID
|
||||
ClassCompleteRequest(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN CCHAR PriorityBoost
|
||||
)
|
||||
{
|
||||
|
||||
#if DBG
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||||
PREMOVE_TRACKING_BLOCK *listEntry =
|
||||
(PREMOVE_TRACKING_BLOCK)&commonExtension->RemoveTrackingList;
|
||||
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
|
||||
&oldIrql);
|
||||
|
||||
while(*listEntry != NULL) {
|
||||
|
||||
if((*listEntry)->Tag == Irp) {
|
||||
break;
|
||||
}
|
||||
|
||||
listEntry = &((*listEntry)->NextBlock);
|
||||
}
|
||||
|
||||
if(*listEntry != NULL) {
|
||||
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassCompleteRequest: "
|
||||
"Irp %p completed while still holding the remove lock\n",
|
||||
Irp));
|
||||
DebugPrint((ClassDebugError, ">>>>>ClassCompleteRequest: "
|
||||
"Lock acquired in file %s on line %d\n",
|
||||
(*listEntry)->File, (*listEntry)->Line));
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
|
||||
#endif
|
||||
|
||||
IoCompleteRequest(Irp, PriorityBoost);
|
||||
return;
|
||||
} // end ClassCompleteRequest()
|
||||
|
1060
reactos/drivers/storage/classpnp/obsolete.c
Normal file
1060
reactos/drivers/storage/classpnp/obsolete.c
Normal file
File diff suppressed because it is too large
Load diff
1607
reactos/drivers/storage/classpnp/power.c
Normal file
1607
reactos/drivers/storage/classpnp/power.c
Normal file
File diff suppressed because it is too large
Load diff
349
reactos/drivers/storage/classpnp/retry.c
Normal file
349
reactos/drivers/storage/classpnp/retry.c
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
retry.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Packet retry routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* InterpretTransferPacketError
|
||||
*
|
||||
* Interpret the SRB error into a meaningful IRP status.
|
||||
* ClassInterpretSenseInfo also may modify the SRB for the retry.
|
||||
*
|
||||
* Return TRUE iff packet should be retried.
|
||||
*/
|
||||
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
BOOLEAN shouldRetry = FALSE;
|
||||
PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
|
||||
/*
|
||||
* Interpret the error using the returned sense info first.
|
||||
*/
|
||||
Pkt->RetryIntervalSec = 0;
|
||||
if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){
|
||||
/*
|
||||
* This is an Ejection Control SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
&Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
MAXIMUM_RETRIES - Pkt->NumRetries,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&Pkt->RetryIntervalSec);
|
||||
if (shouldRetry){
|
||||
/*
|
||||
* If the device is not ready, wait at least 2 seconds before retrying.
|
||||
*/
|
||||
PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer;
|
||||
ASSERT(senseInfoBuffer);
|
||||
if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
|
||||
(senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
|
||||
(SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){
|
||||
|
||||
Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
|
||||
(pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){
|
||||
/*
|
||||
* This is an Mode Sense SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
&Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
MAXIMUM_RETRIES - Pkt->NumRetries,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&Pkt->RetryIntervalSec);
|
||||
if (shouldRetry){
|
||||
/*
|
||||
* If the device is not ready, wait at least 2 seconds before retrying.
|
||||
*/
|
||||
PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer;
|
||||
ASSERT(senseInfoBuffer);
|
||||
if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
|
||||
(senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
|
||||
(SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){
|
||||
|
||||
Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some special cases for mode sense.
|
||||
*/
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
else if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN){
|
||||
/*
|
||||
* This is a HACK.
|
||||
* Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
|
||||
* underrun (i.e. success, and the buffer is longer than needed).
|
||||
* So treat this as a success.
|
||||
*/
|
||||
Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
InterlockedExchangeAdd((PLONG)&Pkt->OriginalIrp->IoStatus.Information, (LONG)Pkt->Srb.DataTransferLength);
|
||||
shouldRetry = FALSE;
|
||||
}
|
||||
}
|
||||
else if (pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY){
|
||||
/*
|
||||
* This is a Drive Capacity SRB. Interpret its sense info specially.
|
||||
*/
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
&Pkt->Srb,
|
||||
IRP_MJ_SCSI,
|
||||
0,
|
||||
MAXIMUM_RETRIES - Pkt->NumRetries,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&Pkt->RetryIntervalSec);
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
}
|
||||
else if ((pCdb->CDB10.OperationCode == SCSIOP_READ) ||
|
||||
(pCdb->CDB10.OperationCode == SCSIOP_WRITE)){
|
||||
/*
|
||||
* This is a Read/Write Data packet.
|
||||
*/
|
||||
PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
|
||||
|
||||
shouldRetry = ClassInterpretSenseInfo(
|
||||
Pkt->Fdo,
|
||||
&Pkt->Srb,
|
||||
origCurrentSp->MajorFunction,
|
||||
0,
|
||||
MAXIMUM_RETRIES - Pkt->NumRetries,
|
||||
&Pkt->Irp->IoStatus.Status,
|
||||
&Pkt->RetryIntervalSec);
|
||||
/*
|
||||
* Deal with some special cases.
|
||||
*/
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
|
||||
/*
|
||||
* We are in extreme low-memory stress.
|
||||
* We will retry in smaller chunks.
|
||||
*/
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
|
||||
(Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){
|
||||
/*
|
||||
* We are still verifying a (possibly) reloaded disk/cdrom.
|
||||
* So retry the request.
|
||||
*/
|
||||
Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||||
shouldRetry = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBGERR(("Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
|
||||
}
|
||||
|
||||
return shouldRetry;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RetryTransferPacket
|
||||
*
|
||||
* Retry sending a TRANSFER_PACKET.
|
||||
*
|
||||
* Return TRUE iff the packet is complete.
|
||||
* (if so the status in pkt->irp is the final status).
|
||||
*/
|
||||
BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
BOOLEAN packetDone;
|
||||
|
||||
DBGTRACE(ClassDebugTrace, ("retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(&Pkt->Srb)));
|
||||
|
||||
ASSERT(Pkt->NumRetries > 0);
|
||||
Pkt->NumRetries--;
|
||||
|
||||
/*
|
||||
* Tone down performance on the retry.
|
||||
* This increases the chance for success on the retry.
|
||||
* We've seen instances of drives that fail consistently but then start working
|
||||
* once this scale-down is applied.
|
||||
*/
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
CLEAR_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
||||
Pkt->Srb.QueueTag = SP_UNTAGGED;
|
||||
|
||||
if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
|
||||
PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
BOOLEAN isReadWrite = ((pCdb->CDB10.OperationCode == SCSIOP_READ) ||
|
||||
(pCdb->CDB10.OperationCode == SCSIOP_WRITE));
|
||||
|
||||
if (Pkt->InLowMemRetry || !isReadWrite){
|
||||
/*
|
||||
* This should never happen.
|
||||
* The memory manager guarantees that at least four pages will
|
||||
* be available to allow forward progress in the port driver.
|
||||
* So a one-page transfer should never fail with insufficient resources.
|
||||
*/
|
||||
ASSERT(isReadWrite && !Pkt->InLowMemRetry);
|
||||
packetDone = TRUE;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* We are in low-memory stress.
|
||||
* Start the low-memory retry state machine, which tries to
|
||||
* resend the packet in little one-page chunks.
|
||||
*/
|
||||
InitLowMemRetry( Pkt,
|
||||
Pkt->BufPtrCopy,
|
||||
Pkt->BufLenCopy,
|
||||
Pkt->TargetLocationCopy);
|
||||
StepLowMemRetry(Pkt);
|
||||
packetDone = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Retry the packet by simply resending it after a delay.
|
||||
* Put the packet back in the pending queue and
|
||||
* schedule a timer to retry the transfer.
|
||||
*
|
||||
* Do not call SetupReadWriteTransferPacket again because:
|
||||
* (1) The minidriver may have set some bits
|
||||
* in the SRB that it needs again and
|
||||
* (2) doing so would reset numRetries.
|
||||
*
|
||||
* BECAUSE we do not call SetupReadWriteTransferPacket again,
|
||||
* we have to reset a couple fields in the SRB that
|
||||
* some miniports overwrite when they fail an SRB.
|
||||
*/
|
||||
|
||||
Pkt->Srb.DataBuffer = Pkt->BufPtrCopy;
|
||||
Pkt->Srb.DataTransferLength = Pkt->BufLenCopy;
|
||||
|
||||
if (Pkt->RetryIntervalSec == 0){
|
||||
/*
|
||||
* Always delay by at least a little when retrying.
|
||||
* Some problems (e.g. CRC errors) are not recoverable without a slight delay.
|
||||
*/
|
||||
LARGE_INTEGER timerPeriod;
|
||||
|
||||
timerPeriod.HighPart = -1;
|
||||
timerPeriod.LowPart = -(LONG)((ULONG)MINIMUM_RETRY_UNITS*KeQueryTimeIncrement());
|
||||
KeInitializeTimer(&Pkt->RetryTimer);
|
||||
KeInitializeDpc(&Pkt->RetryTimerDPC, TransferPacketRetryTimerDpc, Pkt);
|
||||
KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC);
|
||||
}
|
||||
else {
|
||||
LARGE_INTEGER timerPeriod;
|
||||
|
||||
ASSERT(Pkt->RetryIntervalSec < 100); // sanity check
|
||||
timerPeriod.HighPart = -1;
|
||||
timerPeriod.LowPart = Pkt->RetryIntervalSec*-10000000;
|
||||
KeInitializeTimer(&Pkt->RetryTimer);
|
||||
KeInitializeDpc(&Pkt->RetryTimerDPC, TransferPacketRetryTimerDpc, Pkt);
|
||||
KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC);
|
||||
}
|
||||
packetDone = FALSE;
|
||||
}
|
||||
|
||||
return packetDone;
|
||||
}
|
||||
|
||||
|
||||
VOID TransferPacketRetryTimerDpc( IN PKDPC Dpc,
|
||||
IN PVOID DeferredContext,
|
||||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2)
|
||||
{
|
||||
PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)DeferredContext;
|
||||
SubmitTransferPacket(pkt);
|
||||
}
|
||||
|
||||
|
||||
VOID InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation)
|
||||
{
|
||||
ASSERT(Len > 0);
|
||||
ASSERT(!Pkt->InLowMemRetry);
|
||||
Pkt->InLowMemRetry = TRUE;
|
||||
Pkt->LowMemRetry_remainingBufPtr = BufPtr;
|
||||
Pkt->LowMemRetry_remainingBufLen = Len;
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation = TargetLocation;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* StepLowMemRetry
|
||||
*
|
||||
* During extreme low-memory stress, this function retries
|
||||
* a packet in small one-page chunks, sent serially.
|
||||
*
|
||||
* Returns TRUE iff the packet is done.
|
||||
*/
|
||||
BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
BOOLEAN packetDone;
|
||||
|
||||
if (Pkt->LowMemRetry_remainingBufLen == 0){
|
||||
packetDone = TRUE;
|
||||
}
|
||||
else {
|
||||
ULONG thisChunkLen;
|
||||
ULONG bytesToNextPageBoundary;
|
||||
|
||||
/*
|
||||
* Make sure the little chunk we send is <= a page length
|
||||
* AND that it does not cross any page boundaries.
|
||||
*/
|
||||
bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE);
|
||||
thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary);
|
||||
|
||||
/*
|
||||
* Set up the transfer packet for the new little chunk.
|
||||
* This will reset numRetries so that we retry each chunk as required.
|
||||
*/
|
||||
SetupReadWriteTransferPacket(Pkt,
|
||||
Pkt->LowMemRetry_remainingBufPtr,
|
||||
thisChunkLen,
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation,
|
||||
Pkt->OriginalIrp);
|
||||
|
||||
Pkt->LowMemRetry_remainingBufPtr += thisChunkLen;
|
||||
Pkt->LowMemRetry_remainingBufLen -= thisChunkLen;
|
||||
Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen;
|
||||
|
||||
SubmitTransferPacket(Pkt);
|
||||
packetDone = FALSE;
|
||||
}
|
||||
|
||||
return packetDone;
|
||||
}
|
||||
|
85
reactos/drivers/storage/classpnp/sources
Normal file
85
reactos/drivers/storage/classpnp/sources
Normal file
|
@ -0,0 +1,85 @@
|
|||
!IF 0
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1996 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
sources.
|
||||
|
||||
!ENDIF
|
||||
|
||||
TARGETNAME=classpnp
|
||||
TARGETPATH=obj
|
||||
TARGETTYPE=EXPORT_DRIVER
|
||||
|
||||
!IFNDEF MSC_WARNING_LEVEL
|
||||
MSC_WARNING_LEVEL=/W3
|
||||
!ENDIF
|
||||
|
||||
MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /WX
|
||||
|
||||
PASS1_PUBLISH={$(O)\classpnp.lib=$(DDK_LIB_PATH)\classpnp.lib}
|
||||
|
||||
INCLUDES=..\inc;..\..\inc
|
||||
|
||||
#
|
||||
# Specify whether to break into the debugger if synchronous irps
|
||||
# sent via ClassSendSrbSynchronous() do not complete within the
|
||||
# given timeout period
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_BREAK_ON_LOST_IRPS=0
|
||||
|
||||
#
|
||||
# Specifies the number of seconds for breaking for above
|
||||
# Implementation details are within the source.
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB=100
|
||||
|
||||
#
|
||||
# Specifies that retried requests shall be delayed as
|
||||
# specified by ClassInterpretSenseInfo().
|
||||
# Implementation details are within the source.
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_USE_DELAYED_RETRY=1
|
||||
|
||||
#
|
||||
# You can enable buffering of debug prints to a global buffer by setting
|
||||
# this to 1. This allows debug prints while tracking timing issues.
|
||||
# Implementation details are within the source.
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_BUFFERED_DEBUG_PRINT=0
|
||||
|
||||
#
|
||||
# This is the maximum size for each debug print string sent to DebugPrint(()),
|
||||
# including the trailing NUL character.
|
||||
# Implementation details are within the source.
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE=512
|
||||
|
||||
#
|
||||
# This is the number of unique buffers allocated for buffered printing.
|
||||
# Implementation details are within the source.
|
||||
#
|
||||
C_DEFINES=$(C_DEFINES) -DCLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS=512
|
||||
|
||||
|
||||
SOURCES=autorun.c \
|
||||
class.c \
|
||||
classwmi.c \
|
||||
create.c \
|
||||
data.c \
|
||||
dictlib.c \
|
||||
lock.c \
|
||||
power.c \
|
||||
xferpkt.c \
|
||||
clntirp.c \
|
||||
retry.c \
|
||||
utils.c \
|
||||
obsolete.c \
|
||||
debug.c \
|
||||
class.rc
|
||||
|
||||
DLLDEF=$(O)\class.def
|
||||
|
||||
|
||||
|
565
reactos/drivers/storage/classpnp/utils.c
Normal file
565
reactos/drivers/storage/classpnp/utils.c
Normal file
|
@ -0,0 +1,565 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
utils.c
|
||||
|
||||
Abstract:
|
||||
|
||||
SCSI class driver routines
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, ClassGetDeviceParameter)
|
||||
#pragma alloc_text(PAGE, ClassScanForSpecial)
|
||||
#pragma alloc_text(PAGE, ClassSetDeviceParameter)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// custom string match -- careful!
|
||||
BOOLEAN ClasspMyStringMatches(IN PCHAR StringToMatch OPTIONAL, IN PCHAR TargetString)
|
||||
{
|
||||
ULONG length; // strlen returns an int, not size_t (!)
|
||||
PAGED_CODE();
|
||||
ASSERT(TargetString);
|
||||
// if no match requested, return TRUE
|
||||
if (StringToMatch == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
// cache the string length for efficiency
|
||||
length = strlen(StringToMatch);
|
||||
// ZERO-length strings may only match zero-length strings
|
||||
if (length == 0) {
|
||||
return (strlen(TargetString) == 0);
|
||||
}
|
||||
// strncmp returns zero if the strings match
|
||||
return (strncmp(StringToMatch, TargetString, length) == 0);
|
||||
}
|
||||
|
||||
|
||||
VOID ClassGetDeviceParameter(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PWSTR SubkeyName OPTIONAL,
|
||||
IN PWSTR ParameterName,
|
||||
IN OUT PULONG ParameterValue // also default value
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
||||
HANDLE deviceParameterHandle;
|
||||
HANDLE deviceSubkeyHandle;
|
||||
ULONG defaultParameterValue;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// open the given parameter
|
||||
//
|
||||
|
||||
status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo,
|
||||
PLUGPLAY_REGKEY_DEVICE,
|
||||
KEY_READ,
|
||||
&deviceParameterHandle);
|
||||
|
||||
if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
|
||||
|
||||
UNICODE_STRING subkeyName;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
|
||||
RtlInitUnicodeString(&subkeyName, SubkeyName);
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
&subkeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
deviceParameterHandle,
|
||||
NULL);
|
||||
|
||||
status = ZwOpenKey(&deviceSubkeyHandle,
|
||||
KEY_READ,
|
||||
&objectAttributes);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
ZwClose(deviceParameterHandle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
RtlZeroMemory(queryTable, sizeof(queryTable));
|
||||
|
||||
defaultParameterValue = *ParameterValue;
|
||||
|
||||
queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
||||
queryTable->Name = ParameterName;
|
||||
queryTable->EntryContext = ParameterValue;
|
||||
queryTable->DefaultType = REG_DWORD;
|
||||
queryTable->DefaultData = NULL;
|
||||
queryTable->DefaultLength = 0;
|
||||
|
||||
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
||||
(PWSTR)(SubkeyName ?
|
||||
deviceSubkeyHandle :
|
||||
deviceParameterHandle),
|
||||
queryTable,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
*ParameterValue = defaultParameterValue; // use default value
|
||||
}
|
||||
|
||||
//
|
||||
// close what we open
|
||||
//
|
||||
|
||||
if (SubkeyName) {
|
||||
ZwClose(deviceSubkeyHandle);
|
||||
}
|
||||
|
||||
ZwClose(deviceParameterHandle);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} // end ClassGetDeviceParameter()
|
||||
|
||||
|
||||
NTSTATUS ClassSetDeviceParameter(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN PWSTR SubkeyName OPTIONAL,
|
||||
IN PWSTR ParameterName,
|
||||
IN ULONG ParameterValue)
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE deviceParameterHandle;
|
||||
HANDLE deviceSubkeyHandle;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
//
|
||||
// open the given parameter
|
||||
//
|
||||
|
||||
status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo,
|
||||
PLUGPLAY_REGKEY_DEVICE,
|
||||
KEY_READ | KEY_WRITE,
|
||||
&deviceParameterHandle);
|
||||
|
||||
if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
|
||||
|
||||
UNICODE_STRING subkeyName;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
|
||||
RtlInitUnicodeString(&subkeyName, SubkeyName);
|
||||
InitializeObjectAttributes(&objectAttributes,
|
||||
&subkeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
deviceParameterHandle,
|
||||
NULL);
|
||||
|
||||
status = ZwCreateKey(&deviceSubkeyHandle,
|
||||
KEY_READ | KEY_WRITE,
|
||||
&objectAttributes,
|
||||
0, NULL, 0, NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
ZwClose(deviceParameterHandle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status)) {
|
||||
|
||||
status = RtlWriteRegistryValue(
|
||||
RTL_REGISTRY_HANDLE,
|
||||
(PWSTR) (SubkeyName ?
|
||||
deviceSubkeyHandle :
|
||||
deviceParameterHandle),
|
||||
ParameterName,
|
||||
REG_DWORD,
|
||||
&ParameterValue,
|
||||
sizeof(ULONG));
|
||||
|
||||
//
|
||||
// close what we open
|
||||
//
|
||||
|
||||
if (SubkeyName) {
|
||||
ZwClose(deviceSubkeyHandle);
|
||||
}
|
||||
|
||||
ZwClose(deviceParameterHandle);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
} // end ClassSetDeviceParameter()
|
||||
|
||||
|
||||
/*
|
||||
* ClassScanForSpecial
|
||||
*
|
||||
* This routine was written to simplify scanning for special
|
||||
* hardware based upon id strings. it does not check the registry.
|
||||
*/
|
||||
|
||||
VOID ClassScanForSpecial(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
|
||||
IN CLASSPNP_SCAN_FOR_SPECIAL_INFO DeviceList[],
|
||||
IN PCLASS_SCAN_FOR_SPECIAL_HANDLER Function)
|
||||
{
|
||||
PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
|
||||
PUCHAR vendorId;
|
||||
PUCHAR productId;
|
||||
PUCHAR productRevision;
|
||||
UCHAR nullString[] = "";
|
||||
ULONG j;
|
||||
|
||||
PAGED_CODE();
|
||||
ASSERT(DeviceList);
|
||||
ASSERT(Function);
|
||||
|
||||
deviceDescriptor = FdoExtension->DeviceDescriptor;
|
||||
|
||||
if (DeviceList == NULL) {
|
||||
return;
|
||||
}
|
||||
if (Function == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// SCSI sets offsets to -1, ATAPI sets to 0. check for both.
|
||||
//
|
||||
|
||||
if (deviceDescriptor->VendorIdOffset != 0 &&
|
||||
deviceDescriptor->VendorIdOffset != -1) {
|
||||
vendorId = ((PUCHAR)deviceDescriptor);
|
||||
vendorId += deviceDescriptor->VendorIdOffset;
|
||||
} else {
|
||||
vendorId = nullString;
|
||||
}
|
||||
if (deviceDescriptor->ProductIdOffset != 0 &&
|
||||
deviceDescriptor->ProductIdOffset != -1) {
|
||||
productId = ((PUCHAR)deviceDescriptor);
|
||||
productId += deviceDescriptor->ProductIdOffset;
|
||||
} else {
|
||||
productId = nullString;
|
||||
}
|
||||
if (deviceDescriptor->VendorIdOffset != 0 &&
|
||||
deviceDescriptor->VendorIdOffset != -1) {
|
||||
productRevision = ((PUCHAR)deviceDescriptor);
|
||||
productRevision += deviceDescriptor->ProductRevisionOffset;
|
||||
} else {
|
||||
productRevision = nullString;
|
||||
}
|
||||
|
||||
//
|
||||
// loop while the device list is valid (not null-filled)
|
||||
//
|
||||
|
||||
for (;(DeviceList->VendorId != NULL ||
|
||||
DeviceList->ProductId != NULL ||
|
||||
DeviceList->ProductRevision != NULL);DeviceList++) {
|
||||
|
||||
if (ClasspMyStringMatches(DeviceList->VendorId, vendorId) &&
|
||||
ClasspMyStringMatches(DeviceList->ProductId, productId) &&
|
||||
ClasspMyStringMatches(DeviceList->ProductRevision, productRevision)
|
||||
) {
|
||||
|
||||
DebugPrint((1, "ClasspScanForSpecialByInquiry: Found matching "
|
||||
"controller Ven: %s Prod: %s Rev: %s\n",
|
||||
vendorId, productId, productRevision));
|
||||
|
||||
//
|
||||
// pass the context to the call back routine and exit
|
||||
//
|
||||
|
||||
(Function)(FdoExtension, DeviceList->Data);
|
||||
|
||||
//
|
||||
// for CHK builds, try to prevent wierd stacks by having a debug
|
||||
// print here. it's a hack, but i know of no other way to prevent
|
||||
// the stack from being wrong.
|
||||
//
|
||||
|
||||
DebugPrint((16, "ClasspScanForSpecialByInquiry: "
|
||||
"completed callback\n"));
|
||||
return;
|
||||
|
||||
} // else the strings did not match
|
||||
|
||||
} // none of the devices matched.
|
||||
|
||||
DebugPrint((1, "ClasspScanForSpecialByInquiry: no match found for %p\n",
|
||||
FdoExtension->DeviceObject));
|
||||
return;
|
||||
|
||||
} // end ClasspScanForSpecialByInquiry()
|
||||
|
||||
|
||||
//
|
||||
// In order to provide better performance without the need to reboot,
|
||||
// we need to implement a self-adjusting method to set and clear the
|
||||
// srb flags based upon current performance.
|
||||
//
|
||||
// whenever there is an error, immediately grab the spin lock. the
|
||||
// MP perf hit here is acceptable, since we're in an error path. this
|
||||
// is also neccessary because we are guaranteed to be modifying the
|
||||
// SRB flags here, setting SuccessfulIO to zero, and incrementing the
|
||||
// actual error count (which is always done within this spinlock).
|
||||
//
|
||||
// whenever there is no error, increment a counter. if there have been
|
||||
// errors on the device, and we've enabled dynamic perf, *and* we've
|
||||
// just crossed the perf threshhold, then grab the spin lock and
|
||||
// double check that the threshhold has, indeed been hit(*). then
|
||||
// decrement the error count, and if it's dropped sufficiently, undo
|
||||
// some of the safety changes made in the SRB flags due to the errors.
|
||||
//
|
||||
// * this works in all cases. even if lots of ios occur after the
|
||||
// previous guy went in and cleared the successfulio counter, that
|
||||
// just means that we've hit the threshhold again, and so it's proper
|
||||
// to run the inner loop again.
|
||||
//
|
||||
|
||||
VOID
|
||||
ClasspPerfIncrementErrorCount(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
ULONG errors;
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
|
||||
fdoData->Perf.SuccessfulIO = 0; // implicit interlock
|
||||
errors = InterlockedIncrement(&FdoExtension->ErrorCount);
|
||||
|
||||
if (errors >= CLASS_ERROR_LEVEL_1) {
|
||||
|
||||
//
|
||||
// If the error count has exceeded the error limit, then disable
|
||||
// any tagged queuing, multiple requests per lu queueing
|
||||
// and sychronous data transfers.
|
||||
//
|
||||
// Clearing the no queue freeze flag prevents the port driver
|
||||
// from sending multiple requests per logical unit.
|
||||
//
|
||||
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
||||
|
||||
SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
|
||||
DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: "
|
||||
"Too many errors; disabling tagged queuing and "
|
||||
"synchronous data tranfers.\n"));
|
||||
|
||||
}
|
||||
|
||||
if (errors >= CLASS_ERROR_LEVEL_2) {
|
||||
|
||||
//
|
||||
// If a second threshold is reached, disable disconnects.
|
||||
//
|
||||
|
||||
SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
|
||||
DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: "
|
||||
"Too many errors; disabling disconnects.\n"));
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
ClasspPerfIncrementSuccessfulIo(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
ULONG errors;
|
||||
ULONG succeeded = 0;
|
||||
|
||||
//
|
||||
// don't take a hit from the interlocked op unless we're in
|
||||
// a degraded state and we've got a threshold to hit.
|
||||
//
|
||||
|
||||
if (FdoExtension->ErrorCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fdoData->Perf.ReEnableThreshhold == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
succeeded = InterlockedIncrement(&fdoData->Perf.SuccessfulIO);
|
||||
if (succeeded < fdoData->Perf.ReEnableThreshhold) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// if we hit the threshold, grab the spinlock and verify we've
|
||||
// actually done so. this allows us to ignore the spinlock 99%
|
||||
// of the time.
|
||||
//
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
|
||||
//
|
||||
// re-read the value, so we don't run this multiple times
|
||||
// for a single threshhold being hit. this keeps errorcount
|
||||
// somewhat useful.
|
||||
//
|
||||
|
||||
succeeded = fdoData->Perf.SuccessfulIO;
|
||||
|
||||
if ((FdoExtension->ErrorCount != 0) &&
|
||||
(fdoData->Perf.ReEnableThreshhold <= succeeded)
|
||||
) {
|
||||
|
||||
fdoData->Perf.SuccessfulIO = 0; // implicit interlock
|
||||
|
||||
ASSERT(FdoExtension->ErrorCount > 0);
|
||||
errors = InterlockedDecrement(&FdoExtension->ErrorCount);
|
||||
|
||||
//
|
||||
// note: do in reverse order of the sets "just in case"
|
||||
//
|
||||
|
||||
if (errors < CLASS_ERROR_LEVEL_2) {
|
||||
if (errors == CLASS_ERROR_LEVEL_2 - 1) {
|
||||
DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: "
|
||||
"Error level 2 no longer required.\n"));
|
||||
}
|
||||
if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_DISABLE_DISCONNECT)) {
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_DISABLE_DISCONNECT);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors < CLASS_ERROR_LEVEL_1) {
|
||||
if (errors == CLASS_ERROR_LEVEL_1 - 1) {
|
||||
DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: "
|
||||
"Error level 1 no longer required.\n"));
|
||||
}
|
||||
if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) {
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
}
|
||||
if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_QUEUE_ACTION_ENABLE)) {
|
||||
SET_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
||||
}
|
||||
if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_NO_QUEUE_FREEZE)) {
|
||||
SET_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
}
|
||||
}
|
||||
} // end of threshhold definitely being hit for first time
|
||||
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen)
|
||||
{
|
||||
PMDL mdl;
|
||||
|
||||
mdl = IoAllocateMdl(Buffer, BufferLen, FALSE, FALSE, NULL);
|
||||
if (mdl){
|
||||
_SEH2_TRY {
|
||||
/*
|
||||
* We are reading from the device.
|
||||
* Therefore, the device is WRITING to the locked memory.
|
||||
* So we request IoWriteAccess.
|
||||
*/
|
||||
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
|
||||
|
||||
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
||||
NTSTATUS status = _SEH2_GetExceptionCode();
|
||||
|
||||
DBGWARN(("BuildReadMdl: MmProbeAndLockPages failed with %xh.", status));
|
||||
IoFreeMdl(mdl);
|
||||
mdl = NULL;
|
||||
} _SEH2_END;
|
||||
}
|
||||
else {
|
||||
DBGWARN(("BuildReadMdl: IoAllocateMdl failed"));
|
||||
}
|
||||
|
||||
return mdl;
|
||||
}
|
||||
|
||||
|
||||
VOID FreeDeviceInputMdl(PMDL Mdl)
|
||||
{
|
||||
MmUnlockPages(Mdl);
|
||||
IoFreeMdl(Mdl);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
VOID
|
||||
ClasspPerfResetCounters(
|
||||
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
|
||||
)
|
||||
{
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
DebugPrint((ClassDebugError, "ClasspPerfResetCounters: "
|
||||
"Resetting all perf counters.\n"));
|
||||
fdoData->Perf.SuccessfulIO = 0;
|
||||
FdoExtension->ErrorCount = 0;
|
||||
|
||||
if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_DISABLE_DISCONNECT)) {
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_DISABLE_DISCONNECT);
|
||||
}
|
||||
if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) {
|
||||
CLEAR_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
}
|
||||
if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_QUEUE_ACTION_ENABLE)) {
|
||||
SET_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_QUEUE_ACTION_ENABLE);
|
||||
}
|
||||
if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
|
||||
SRB_FLAGS_NO_QUEUE_FREEZE)) {
|
||||
SET_FLAG(FdoExtension->SrbFlags,
|
||||
SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
}
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
911
reactos/drivers/storage/classpnp/xferpkt.c
Normal file
911
reactos/drivers/storage/classpnp/xferpkt.c
Normal file
|
@ -0,0 +1,911 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1991 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
xferpkt.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Packet routines for CLASSPNP
|
||||
|
||||
Environment:
|
||||
|
||||
kernel mode only
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "classp.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, InitializeTransferPackets)
|
||||
#pragma alloc_text(PAGE, DestroyAllTransferPackets)
|
||||
#pragma alloc_text(PAGE, SetupEjectionTransferPacket)
|
||||
#pragma alloc_text(PAGE, SetupModeSenseTransferPacket)
|
||||
#endif
|
||||
|
||||
|
||||
ULONG MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
ULONG MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
|
||||
|
||||
/*
|
||||
* InitializeTransferPackets
|
||||
*
|
||||
* Allocate/initialize TRANSFER_PACKETs and related resources.
|
||||
*/
|
||||
NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension;
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor;
|
||||
ULONG hwMaxPages;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Precompute the maximum transfer length
|
||||
*/
|
||||
ASSERT(adapterDesc->MaximumTransferLength);
|
||||
ASSERT(adapterDesc->MaximumPhysicalPages);
|
||||
hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0;
|
||||
|
||||
#if defined(_AMD64_SIMULATOR_)
|
||||
|
||||
//
|
||||
// The simulator appears to have a problem with large transfers.
|
||||
//
|
||||
|
||||
if (hwMaxPages > 4) {
|
||||
hwMaxPages = 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT);
|
||||
fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE);
|
||||
|
||||
fdoData->NumTotalTransferPackets = 0;
|
||||
fdoData->NumFreeTransferPackets = 0;
|
||||
InitializeSListHead(&fdoData->FreeTransferPacketsList);
|
||||
InitializeListHead(&fdoData->AllTransferPacketsList);
|
||||
InitializeListHead(&fdoData->DeferredClientIrpList);
|
||||
|
||||
/*
|
||||
* Set the packet threshold numbers based on the Windows SKU.
|
||||
*/
|
||||
if (ExVerifySuite(Personal)){
|
||||
// this is Windows Personal
|
||||
MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
}
|
||||
else if (ExVerifySuite(Enterprise) || ExVerifySuite(DataCenter)){
|
||||
// this is Advanced Server or Datacenter
|
||||
MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise;
|
||||
MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise;
|
||||
}
|
||||
else if (ExVerifySuite(TerminalServer)){
|
||||
// this is standard Server or Pro with terminal server
|
||||
MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Server;
|
||||
MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Server;
|
||||
}
|
||||
else {
|
||||
// this is Professional without terminal server
|
||||
MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
|
||||
}
|
||||
|
||||
while (fdoData->NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){
|
||||
PTRANSFER_PACKET pkt = NewTransferPacket(Fdo);
|
||||
if (pkt){
|
||||
InterlockedIncrement(&fdoData->NumTotalTransferPackets);
|
||||
EnqueueFreeTransferPacket(Fdo, pkt);
|
||||
}
|
||||
else {
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fdoData->DbgPeakNumTransferPackets = fdoData->NumTotalTransferPackets;
|
||||
|
||||
/*
|
||||
* Pre-initialize our SCSI_REQUEST_BLOCK template with all
|
||||
* the constant fields. This will save a little time for each xfer.
|
||||
* NOTE: a CdbLength field of 10 may not always be appropriate
|
||||
*/
|
||||
RtlZeroMemory(&fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK));
|
||||
fdoData->SrbTemplate.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||||
fdoData->SrbTemplate.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||||
fdoData->SrbTemplate.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
||||
fdoData->SrbTemplate.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
fdoData->SrbTemplate.CdbLength = 10;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
TRANSFER_PACKET *pkt;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(IsListEmpty(&fdoData->DeferredClientIrpList));
|
||||
|
||||
while (pkt = DequeueFreeTransferPacket(Fdo, FALSE)){
|
||||
DestroyTransferPacket(pkt);
|
||||
InterlockedDecrement(&fdoData->NumTotalTransferPackets);
|
||||
}
|
||||
|
||||
ASSERT(fdoData->NumTotalTransferPackets == 0);
|
||||
}
|
||||
|
||||
|
||||
PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PTRANSFER_PACKET newPkt;
|
||||
|
||||
newPkt = ExAllocatePoolWithTag(NonPagedPool, sizeof(TRANSFER_PACKET), 'pnPC');
|
||||
if (newPkt){
|
||||
RtlZeroMemory(newPkt, sizeof(TRANSFER_PACKET)); // just to be sure
|
||||
|
||||
/*
|
||||
* Allocate resources for the packet.
|
||||
*/
|
||||
newPkt->Irp = IoAllocateIrp(Fdo->StackSize, FALSE);
|
||||
if (newPkt->Irp){
|
||||
KIRQL oldIrql;
|
||||
|
||||
newPkt->Fdo = Fdo;
|
||||
|
||||
/*
|
||||
* Enqueue the packet in our static AllTransferPacketsList
|
||||
* (just so we can find it during debugging if its stuck somewhere).
|
||||
*/
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
InsertTailList(&fdoData->AllTransferPacketsList, &newPkt->AllPktsListEntry);
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
}
|
||||
else {
|
||||
ExFreePool(newPkt);
|
||||
newPkt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return newPkt;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DestroyTransferPacket
|
||||
*
|
||||
*/
|
||||
VOID DestroyTransferPacket(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
|
||||
ASSERT(!Pkt->SlistEntry.Next);
|
||||
ASSERT(!Pkt->OriginalIrp);
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
|
||||
/*
|
||||
* Delete the packet from our all-packets queue.
|
||||
*/
|
||||
ASSERT(!IsListEmpty(&Pkt->AllPktsListEntry));
|
||||
ASSERT(!IsListEmpty(&fdoData->AllTransferPacketsList));
|
||||
RemoveEntryList(&Pkt->AllPktsListEntry);
|
||||
InitializeListHead(&Pkt->AllPktsListEntry);
|
||||
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
|
||||
IoFreeIrp(Pkt->Irp);
|
||||
ExFreePool(Pkt);
|
||||
}
|
||||
|
||||
|
||||
VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
KIRQL oldIrql;
|
||||
ULONG newNumPkts;
|
||||
|
||||
ASSERT(!Pkt->SlistEntry.Next);
|
||||
|
||||
InterlockedPushEntrySList(&fdoData->FreeTransferPacketsList, &Pkt->SlistEntry);
|
||||
newNumPkts = InterlockedIncrement(&fdoData->NumFreeTransferPackets);
|
||||
ASSERT(newNumPkts <= fdoData->NumTotalTransferPackets);
|
||||
|
||||
/*
|
||||
* If the total number of packets is larger than MinWorkingSetTransferPackets,
|
||||
* that means that we've been in stress. If all those packets are now
|
||||
* free, then we are now out of stress and can free the extra packets.
|
||||
* Free down to MaxWorkingSetTransferPackets immediately, and
|
||||
* down to MinWorkingSetTransferPackets lazily (one at a time).
|
||||
*/
|
||||
if (fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets){
|
||||
|
||||
/*
|
||||
* 1. Immediately snap down to our UPPER threshold.
|
||||
*/
|
||||
if (fdoData->NumTotalTransferPackets > MaxWorkingSetTransferPackets){
|
||||
SINGLE_LIST_ENTRY pktList;
|
||||
PSINGLE_LIST_ENTRY slistEntry;
|
||||
PTRANSFER_PACKET pktToDelete;
|
||||
|
||||
DBGTRACE(ClassDebugTrace, ("Exiting stress, block freeing (%d-%d) packets.", fdoData->NumTotalTransferPackets, MaxWorkingSetTransferPackets));
|
||||
|
||||
/*
|
||||
* Check the counter again with lock held. This eliminates a race condition
|
||||
* while still allowing us to not grab the spinlock in the common codepath.
|
||||
*
|
||||
* Note that the spinlock does not synchronize with threads dequeuing free
|
||||
* packets to send (DequeueFreeTransferPacket does that with a lightweight
|
||||
* interlocked exchange); the spinlock prevents multiple threads in this function
|
||||
* from deciding to free too many extra packets at once.
|
||||
*/
|
||||
SimpleInitSlistHdr(&pktList);
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
while ((fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets) &&
|
||||
(fdoData->NumTotalTransferPackets > MaxWorkingSetTransferPackets)){
|
||||
|
||||
pktToDelete = DequeueFreeTransferPacket(Fdo, FALSE);
|
||||
if (pktToDelete){
|
||||
SimplePushSlist(&pktList, &pktToDelete->SlistEntry);
|
||||
InterlockedDecrement(&fdoData->NumTotalTransferPackets);
|
||||
}
|
||||
else {
|
||||
DBGTRACE(ClassDebugTrace, ("Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (1).", MaxWorkingSetTransferPackets, Fdo, fdoData->NumTotalTransferPackets));
|
||||
break;
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
|
||||
while (slistEntry = SimplePopSlist(&pktList)){
|
||||
pktToDelete = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
|
||||
DestroyTransferPacket(pktToDelete);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Lazily work down to our LOWER threshold (by only freeing one packet at a time).
|
||||
*/
|
||||
if (fdoData->NumTotalTransferPackets > MinWorkingSetTransferPackets){
|
||||
/*
|
||||
* Check the counter again with lock held. This eliminates a race condition
|
||||
* while still allowing us to not grab the spinlock in the common codepath.
|
||||
*
|
||||
* Note that the spinlock does not synchronize with threads dequeuing free
|
||||
* packets to send (DequeueFreeTransferPacket does that with a lightweight
|
||||
* interlocked exchange); the spinlock prevents multiple threads in this function
|
||||
* from deciding to free too many extra packets at once.
|
||||
*/
|
||||
PTRANSFER_PACKET pktToDelete = NULL;
|
||||
|
||||
DBGTRACE(ClassDebugTrace, ("Exiting stress, lazily freeing one of %d/%d packets.", fdoData->NumTotalTransferPackets, MinWorkingSetTransferPackets));
|
||||
|
||||
KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
|
||||
if ((fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets) &&
|
||||
(fdoData->NumTotalTransferPackets > MinWorkingSetTransferPackets)){
|
||||
|
||||
pktToDelete = DequeueFreeTransferPacket(Fdo, FALSE);
|
||||
if (pktToDelete){
|
||||
InterlockedDecrement(&fdoData->NumTotalTransferPackets);
|
||||
}
|
||||
else {
|
||||
DBGTRACE(ClassDebugTrace, ("Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (2).", MinWorkingSetTransferPackets, Fdo, fdoData->NumTotalTransferPackets));
|
||||
}
|
||||
}
|
||||
KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
|
||||
|
||||
if (pktToDelete){
|
||||
DestroyTransferPacket(pktToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PTRANSFER_PACKET pkt;
|
||||
PSINGLE_LIST_ENTRY slistEntry;
|
||||
KIRQL oldIrql;
|
||||
|
||||
slistEntry = InterlockedPopEntrySList(&fdoData->FreeTransferPacketsList);
|
||||
if (slistEntry){
|
||||
slistEntry->Next = NULL;
|
||||
pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
|
||||
ASSERT(fdoData->NumFreeTransferPackets > 0);
|
||||
InterlockedDecrement(&fdoData->NumFreeTransferPackets);
|
||||
}
|
||||
else {
|
||||
if (AllocIfNeeded){
|
||||
/*
|
||||
* We are in stress and have run out of lookaside packets.
|
||||
* In order to service the current transfer,
|
||||
* allocate an extra packet.
|
||||
* We will free it lazily when we are out of stress.
|
||||
*/
|
||||
pkt = NewTransferPacket(Fdo);
|
||||
if (pkt){
|
||||
InterlockedIncrement(&fdoData->NumTotalTransferPackets);
|
||||
fdoData->DbgPeakNumTransferPackets = max(fdoData->DbgPeakNumTransferPackets, fdoData->NumTotalTransferPackets);
|
||||
}
|
||||
else {
|
||||
DBGWARN(("DequeueFreeTransferPacket: packet allocation failed"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
pkt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* SetupReadWriteTransferPacket
|
||||
*
|
||||
* This function is called once to set up the first attempt to send a packet.
|
||||
* It is not called before a retry, as SRB fields may be modified for the retry.
|
||||
*
|
||||
* Set up the Srb of the TRANSFER_PACKET for the transfer.
|
||||
* The Irp is set up in SubmitTransferPacket because it must be reset
|
||||
* for each packet submission.
|
||||
*/
|
||||
VOID SetupReadWriteTransferPacket( PTRANSFER_PACKET Pkt,
|
||||
PVOID Buf,
|
||||
ULONG Len,
|
||||
LARGE_INTEGER DiskLocation,
|
||||
PIRP OriginalIrp)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(OriginalIrp);
|
||||
UCHAR majorFunc = origCurSp->MajorFunction;
|
||||
ULONG logicalBlockAddr;
|
||||
ULONG numTransferBlocks;
|
||||
PCDB pCdb;
|
||||
|
||||
logicalBlockAddr = (ULONG)Int64ShrlMod32(DiskLocation.QuadPart, fdoExt->SectorShift);
|
||||
numTransferBlocks = Len >> fdoExt->SectorShift;
|
||||
|
||||
/*
|
||||
* Slap the constant SRB fields in from our pre-initialized template.
|
||||
* We'll then only have to fill in the unique fields for this transfer.
|
||||
* Tell lower drivers to sort the SRBs by the logical block address
|
||||
* so that disk seeks are minimized.
|
||||
*/
|
||||
Pkt->Srb = fdoData->SrbTemplate; // copies _contents_ of SRB blocks
|
||||
Pkt->Srb.DataBuffer = Buf;
|
||||
Pkt->Srb.DataTransferLength = Len;
|
||||
Pkt->Srb.QueueSortKey = logicalBlockAddr;
|
||||
Pkt->Srb.OriginalRequest = Pkt->Irp;
|
||||
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
|
||||
Pkt->Srb.TimeOutValue = (Len/0x10000) + ((Len%0x10000) ? 1 : 0);
|
||||
Pkt->Srb.TimeOutValue *= fdoExt->TimeOutValue;
|
||||
|
||||
/*
|
||||
* Arrange values in CDB in big-endian format.
|
||||
*/
|
||||
pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
pCdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte3;
|
||||
pCdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte2;
|
||||
pCdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte1;
|
||||
pCdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte0;
|
||||
pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1;
|
||||
pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0;
|
||||
pCdb->CDB10.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ : SCSIOP_WRITE;
|
||||
|
||||
/*
|
||||
* Set SRB and IRP flags
|
||||
*/
|
||||
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
|
||||
if (TEST_FLAG(OriginalIrp->Flags, IRP_PAGING_IO) ||
|
||||
TEST_FLAG(OriginalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)){
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_CLASS_FLAGS_PAGING);
|
||||
}
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, (majorFunc==IRP_MJ_READ) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT);
|
||||
|
||||
/*
|
||||
* Allow caching only if this is not a write-through request.
|
||||
* If write-through and caching is enabled on the device, force
|
||||
* media access.
|
||||
*/
|
||||
if (TEST_FLAG(origCurSp->Flags, SL_WRITE_THROUGH)){
|
||||
if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE)){
|
||||
pCdb->CDB10.ForceUnitAccess = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember the buf and len in the SRB because miniports
|
||||
* can overwrite SRB.DataTransferLength and we may need it again
|
||||
* for the retry.
|
||||
*/
|
||||
Pkt->BufPtrCopy = Buf;
|
||||
Pkt->BufLenCopy = Len;
|
||||
Pkt->TargetLocationCopy = DiskLocation;
|
||||
|
||||
Pkt->OriginalIrp = OriginalIrp;
|
||||
Pkt->NumRetries = MAXIMUM_RETRIES;
|
||||
Pkt->SyncEventPtr = NULL;
|
||||
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SubmitTransferPacket
|
||||
*
|
||||
* Set up the IRP for the TRANSFER_PACKET submission and send it down.
|
||||
*/
|
||||
VOID SubmitTransferPacket(PTRANSFER_PACKET Pkt)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
|
||||
PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject;
|
||||
PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Pkt->Irp);
|
||||
|
||||
ASSERT(Pkt->Irp->CurrentLocation == Pkt->Irp->StackCount+1);
|
||||
|
||||
/*
|
||||
* Attach the SRB to the IRP.
|
||||
* The reused IRP's stack location has to be rewritten for each retry
|
||||
* call because IoCompleteRequest clears the stack locations.
|
||||
*/
|
||||
IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED);
|
||||
nextSp->MajorFunction = IRP_MJ_SCSI;
|
||||
nextSp->Parameters.Scsi.Srb = &Pkt->Srb;
|
||||
Pkt->Srb.ScsiStatus = Pkt->Srb.SrbStatus = 0;
|
||||
if (Pkt->CompleteOriginalIrpWhenLastPacketCompletes){
|
||||
/*
|
||||
* Only dereference the "original IRP"'s stack location
|
||||
* if its a real client irp (as opposed to a static irp
|
||||
* we're using just for result status for one of the non-IO scsi commands).
|
||||
*
|
||||
* For read/write, propagate the storage-specific IRP stack location flags
|
||||
* (e.g. SL_OVERRIDE_VERIFY_VOLUME, SL_WRITE_THROUGH).
|
||||
*/
|
||||
PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
|
||||
nextSp->Flags = origCurSp->Flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write MDL address to new IRP. In the port driver the SRB DataBuffer
|
||||
* field is used as the actual buffer pointer within the MDL,
|
||||
* so the same MDL can be used for each partial transfer.
|
||||
* This saves having to build a new MDL for each partial transfer.
|
||||
*/
|
||||
Pkt->Irp->MdlAddress = Pkt->OriginalIrp->MdlAddress;
|
||||
|
||||
IoSetCompletionRoutine(Pkt->Irp, TransferPktComplete, Pkt, TRUE, TRUE, TRUE);
|
||||
IoCallDriver(nextDevObj, Pkt->Irp);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context)
|
||||
{
|
||||
PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)Context;
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(pkt->OriginalIrp);
|
||||
BOOLEAN packetDone = FALSE;
|
||||
|
||||
/*
|
||||
* Put all the assertions and spew in here so we don't have to look at them.
|
||||
*/
|
||||
DBGCHECKRETURNEDPKT(pkt);
|
||||
|
||||
if (SRB_STATUS(pkt->Srb.SrbStatus) == SRB_STATUS_SUCCESS){
|
||||
|
||||
fdoData->LoggedTURFailureSinceLastIO = FALSE;
|
||||
|
||||
/*
|
||||
* The port driver should not have allocated a sense buffer
|
||||
* if the SRB succeeded.
|
||||
*/
|
||||
ASSERT(!PORT_ALLOCATED_SENSE(fdoExt, &pkt->Srb));
|
||||
|
||||
/*
|
||||
* Add this packet's transferred length to the original IRP's.
|
||||
*/
|
||||
InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information,
|
||||
(LONG)pkt->Srb.DataTransferLength);
|
||||
|
||||
if (pkt->InLowMemRetry){
|
||||
packetDone = StepLowMemRetry(pkt);
|
||||
}
|
||||
else {
|
||||
packetDone = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* The packet failed. We may retry it if possible.
|
||||
*/
|
||||
BOOLEAN shouldRetry;
|
||||
|
||||
/*
|
||||
* Make sure IRP status matches SRB error status (since we propagate it).
|
||||
*/
|
||||
if (NT_SUCCESS(Irp->IoStatus.Status)){
|
||||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpret the SRB error (to a meaningful IRP status)
|
||||
* and determine if we should retry this packet.
|
||||
* This call looks at the returned SENSE info to figure out what to do.
|
||||
*/
|
||||
shouldRetry = InterpretTransferPacketError(pkt);
|
||||
|
||||
/*
|
||||
* Sometimes the port driver can allocates a new 'sense' buffer
|
||||
* to report transfer errors, e.g. when the default sense buffer
|
||||
* is too small. If so, it is up to us to free it.
|
||||
* Now that we're done interpreting the sense info, free it if appropriate.
|
||||
*/
|
||||
if (PORT_ALLOCATED_SENSE(fdoExt, &pkt->Srb)) {
|
||||
DBGTRACE(ClassDebugSenseInfo, ("Freeing port-allocated sense buffer for pkt %ph.", pkt));
|
||||
FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExt, &pkt->Srb);
|
||||
pkt->Srb.SenseInfoBuffer = &pkt->SrbErrorSenseData;
|
||||
pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SRB queue is locked-up, release it.
|
||||
* Do this after calling the error handler.
|
||||
*/
|
||||
if (pkt->Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN){
|
||||
ClassReleaseQueue(pkt->Fdo);
|
||||
}
|
||||
|
||||
if (shouldRetry && (pkt->NumRetries > 0)){
|
||||
packetDone = RetryTransferPacket(pkt);
|
||||
}
|
||||
else {
|
||||
packetDone = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If the packet is completed, put it back in the free list.
|
||||
* If it is the last packet servicing the original request, complete the original irp.
|
||||
*/
|
||||
if (packetDone){
|
||||
LONG numPacketsRemaining;
|
||||
PIRP deferredIrp;
|
||||
PDEVICE_OBJECT Fdo = pkt->Fdo;
|
||||
UCHAR uniqueAddr;
|
||||
|
||||
/*
|
||||
* In case a remove is pending, bump the lock count so we don't get freed
|
||||
* right after we complete the original irp.
|
||||
*/
|
||||
ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddr);
|
||||
|
||||
/*
|
||||
* The original IRP should get an error code
|
||||
* if any one of the packets failed.
|
||||
*/
|
||||
if (!NT_SUCCESS(Irp->IoStatus.Status)){
|
||||
pkt->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
|
||||
|
||||
/*
|
||||
* If the original I/O originated in user space (i.e. it is thread-queued),
|
||||
* and the error is user-correctable (e.g. media is missing, for removable media),
|
||||
* alert the user.
|
||||
* Since this is only one of possibly several packets completing for the original IRP,
|
||||
* we may do this more than once for a single request. That's ok; this allows
|
||||
* us to test each returned status with IoIsErrorUserInduced().
|
||||
*/
|
||||
if (IoIsErrorUserInduced(Irp->IoStatus.Status) &&
|
||||
pkt->CompleteOriginalIrpWhenLastPacketCompletes &&
|
||||
pkt->OriginalIrp->Tail.Overlay.Thread){
|
||||
|
||||
IoSetHardErrorOrVerifyDevice(pkt->OriginalIrp, pkt->Fdo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We use a field in the original IRP to count
|
||||
* down the transfer pieces as they complete.
|
||||
*/
|
||||
numPacketsRemaining = InterlockedDecrement(
|
||||
(PLONG)&pkt->OriginalIrp->Tail.Overlay.DriverContext[0]);
|
||||
|
||||
if (numPacketsRemaining > 0){
|
||||
/*
|
||||
* More transfer pieces remain for the original request.
|
||||
* Wait for them to complete before completing the original irp.
|
||||
*/
|
||||
}
|
||||
else {
|
||||
|
||||
/*
|
||||
* All the transfer pieces are done.
|
||||
* Complete the original irp if appropriate.
|
||||
*/
|
||||
ASSERT(numPacketsRemaining == 0);
|
||||
if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){
|
||||
if (NT_SUCCESS(pkt->OriginalIrp->IoStatus.Status)){
|
||||
ASSERT((ULONG)pkt->OriginalIrp->IoStatus.Information == origCurrentSp->Parameters.Read.Length);
|
||||
ClasspPerfIncrementSuccessfulIo(fdoExt);
|
||||
}
|
||||
ClassReleaseRemoveLock(pkt->Fdo, pkt->OriginalIrp);
|
||||
|
||||
ClassCompleteRequest(pkt->Fdo, pkt->OriginalIrp, IO_DISK_INCREMENT);
|
||||
|
||||
/*
|
||||
* We may have been called by one of the class drivers (e.g. cdrom)
|
||||
* via the legacy API ClassSplitRequest.
|
||||
* This is the only case for which the packet engine is called for an FDO
|
||||
* with a StartIo routine; in that case, we have to call IoStartNextPacket
|
||||
* now that the original irp has been completed.
|
||||
*/
|
||||
if (fdoExt->CommonExtension.DriverExtension->InitData.ClassStartIo) {
|
||||
if (TEST_FLAG(pkt->Srb.SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET)){
|
||||
DBGTRAP(("SRB_FLAGS_DONT_START_NEXT_PACKET should never be set here (?)"));
|
||||
}
|
||||
else {
|
||||
KIRQL oldIrql;
|
||||
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
||||
IoStartNextPacket(pkt->Fdo, FALSE);
|
||||
KeLowerIrql(oldIrql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the packet was synchronous, write the final
|
||||
* result back to the issuer's status buffer and
|
||||
* signal his event.
|
||||
*/
|
||||
if (pkt->SyncEventPtr){
|
||||
KeSetEvent(pkt->SyncEventPtr, 0, FALSE);
|
||||
pkt->SyncEventPtr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the completed packet.
|
||||
*/
|
||||
pkt->OriginalIrp = NULL;
|
||||
pkt->InLowMemRetry = FALSE;
|
||||
EnqueueFreeTransferPacket(pkt->Fdo, pkt);
|
||||
|
||||
/*
|
||||
* Now that we have freed some resources,
|
||||
* try again to send one of the previously deferred irps.
|
||||
*/
|
||||
deferredIrp = DequeueDeferredClientIrp(fdoData);
|
||||
if (deferredIrp){
|
||||
DBGWARN(("... retrying deferred irp %xh.", deferredIrp));
|
||||
ServiceTransferRequest(pkt->Fdo, deferredIrp);
|
||||
}
|
||||
|
||||
ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddr);
|
||||
}
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetupEjectionTransferPacket
|
||||
*
|
||||
* Set up a transferPacket for a synchronous Ejection Control transfer.
|
||||
*/
|
||||
VOID SetupEjectionTransferPacket( TRANSFER_PACKET *Pkt,
|
||||
BOOLEAN PreventMediaRemoval,
|
||||
PKEVENT SyncEventPtr,
|
||||
PIRP OriginalIrp)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PCDB pCdb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
|
||||
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||||
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||||
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
||||
Pkt->Srb.CdbLength = 6;
|
||||
Pkt->Srb.OriginalRequest = Pkt->Irp;
|
||||
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
|
||||
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
|
||||
|
||||
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
|
||||
pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
pCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
|
||||
pCdb->MEDIA_REMOVAL.Prevent = PreventMediaRemoval;
|
||||
|
||||
Pkt->BufPtrCopy = NULL;
|
||||
Pkt->BufLenCopy = 0;
|
||||
|
||||
Pkt->OriginalIrp = OriginalIrp;
|
||||
Pkt->NumRetries = NUM_LOCKMEDIAREMOVAL_RETRIES;
|
||||
Pkt->SyncEventPtr = SyncEventPtr;
|
||||
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetupModeSenseTransferPacket
|
||||
*
|
||||
* Set up a transferPacket for a synchronous Mode Sense transfer.
|
||||
*/
|
||||
VOID SetupModeSenseTransferPacket( TRANSFER_PACKET *Pkt,
|
||||
PKEVENT SyncEventPtr,
|
||||
PVOID ModeSenseBuffer,
|
||||
UCHAR ModeSenseBufferLen,
|
||||
UCHAR PageMode,
|
||||
PIRP OriginalIrp)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PCDB pCdb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
|
||||
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||||
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||||
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
||||
Pkt->Srb.CdbLength = 6;
|
||||
Pkt->Srb.OriginalRequest = Pkt->Irp;
|
||||
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
|
||||
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
|
||||
Pkt->Srb.DataBuffer = ModeSenseBuffer;
|
||||
Pkt->Srb.DataTransferLength = ModeSenseBufferLen;
|
||||
|
||||
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
|
||||
pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
pCdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
|
||||
pCdb->MODE_SENSE.PageCode = PageMode;
|
||||
pCdb->MODE_SENSE.AllocationLength = (UCHAR)ModeSenseBufferLen;
|
||||
|
||||
Pkt->BufPtrCopy = ModeSenseBuffer;
|
||||
Pkt->BufLenCopy = ModeSenseBufferLen;
|
||||
|
||||
Pkt->OriginalIrp = OriginalIrp;
|
||||
Pkt->NumRetries = NUM_MODESENSE_RETRIES;
|
||||
Pkt->SyncEventPtr = SyncEventPtr;
|
||||
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetupDriveCapacityTransferPacket
|
||||
*
|
||||
* Set up a transferPacket for a synchronous Drive Capacity transfer.
|
||||
*/
|
||||
VOID SetupDriveCapacityTransferPacket( TRANSFER_PACKET *Pkt,
|
||||
PVOID ReadCapacityBuffer,
|
||||
ULONG ReadCapacityBufferLen,
|
||||
PKEVENT SyncEventPtr,
|
||||
PIRP OriginalIrp)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PCDB pCdb;
|
||||
|
||||
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
|
||||
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||||
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||||
Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
||||
Pkt->Srb.CdbLength = 10;
|
||||
Pkt->Srb.OriginalRequest = Pkt->Irp;
|
||||
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
|
||||
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
|
||||
Pkt->Srb.DataBuffer = ReadCapacityBuffer;
|
||||
Pkt->Srb.DataTransferLength = ReadCapacityBufferLen;
|
||||
|
||||
Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
||||
|
||||
pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
|
||||
|
||||
Pkt->BufPtrCopy = ReadCapacityBuffer;
|
||||
Pkt->BufLenCopy = ReadCapacityBufferLen;
|
||||
|
||||
Pkt->OriginalIrp = OriginalIrp;
|
||||
Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES;
|
||||
Pkt->SyncEventPtr = SyncEventPtr;
|
||||
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* SetupSendStartUnitTransferPacket
|
||||
*
|
||||
* Set up a transferPacket for a synchronous Send Start Unit transfer.
|
||||
*/
|
||||
VOID SetupSendStartUnitTransferPacket( TRANSFER_PACKET *Pkt,
|
||||
PIRP OriginalIrp)
|
||||
{
|
||||
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
|
||||
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
|
||||
PCDB pCdb;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
|
||||
|
||||
/*
|
||||
* Initialize the SRB.
|
||||
* Use a very long timeout value to give the drive time to spin up.
|
||||
*/
|
||||
Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
|
||||
Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||||
Pkt->Srb.TimeOutValue = START_UNIT_TIMEOUT;
|
||||
Pkt->Srb.CdbLength = 6;
|
||||
Pkt->Srb.OriginalRequest = Pkt->Irp;
|
||||
Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
|
||||
Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
|
||||
Pkt->Srb.Lun = 0;
|
||||
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
|
||||
SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
|
||||
|
||||
pCdb = (PCDB)Pkt->Srb.Cdb;
|
||||
pCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
|
||||
pCdb->START_STOP.Start = 1;
|
||||
pCdb->START_STOP.Immediate = 0;
|
||||
pCdb->START_STOP.LogicalUnitNumber = 0;
|
||||
|
||||
Pkt->OriginalIrp = OriginalIrp;
|
||||
Pkt->NumRetries = 0;
|
||||
Pkt->SyncEventPtr = NULL;
|
||||
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -16,4 +16,7 @@
|
|||
<directory name="scsiport">
|
||||
<xi:include href="scsiport/scsiport.rbuild" />
|
||||
</directory>
|
||||
<directory name="classpnp">
|
||||
<xi:include href="classpnp/classpnp.rbuild" />
|
||||
</directory>
|
||||
</group>
|
||||
|
|
374
reactos/drivers/storage/inc/class.h
Normal file
374
reactos/drivers/storage/inc/class.h
Normal file
|
@ -0,0 +1,374 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) 1991 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
class.h
|
||||
|
||||
Abstract:
|
||||
|
||||
These are the structures and defines that are used in the
|
||||
SCSI class drivers.
|
||||
|
||||
Author:
|
||||
|
||||
Mike Glass (mglass)
|
||||
Jeff Havens (jhavens)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _CLASS_
|
||||
|
||||
#include <ntdddisk.h>
|
||||
#include <ntddcdrm.h>
|
||||
#include <ntddtape.h>
|
||||
#include <ntddchgr.h>
|
||||
#include <ntddstor.h>
|
||||
#include "ntddscsi.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// begin_ntminitape
|
||||
|
||||
#if DBG
|
||||
|
||||
#define DebugPrint(x) ScsiDebugPrint x
|
||||
|
||||
#else
|
||||
|
||||
#define DebugPrint(x)
|
||||
|
||||
#endif // DBG
|
||||
|
||||
// end_ntminitape
|
||||
|
||||
#ifdef POOL_TAGGING
|
||||
#undef ExAllocatePool
|
||||
#undef ExAllocatePoolWithQuota
|
||||
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'HscS')
|
||||
#define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,'HscS')
|
||||
#endif
|
||||
|
||||
#define MAXIMUM_RETRIES 4
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(*PCLASS_ERROR) (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PSCSI_REQUEST_BLOCK Srb,
|
||||
IN OUT NTSTATUS *Status,
|
||||
IN OUT BOOLEAN *Retry
|
||||
);
|
||||
|
||||
typedef struct _DEVICE_EXTENSION {
|
||||
|
||||
//
|
||||
// Back pointer to device object
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
||||
//
|
||||
// Pointer to port device object
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT PortDeviceObject;
|
||||
|
||||
//
|
||||
// Length of partition in bytes
|
||||
//
|
||||
|
||||
LARGE_INTEGER PartitionLength;
|
||||
|
||||
//
|
||||
// Number of bytes before start of partition
|
||||
//
|
||||
|
||||
LARGE_INTEGER StartingOffset;
|
||||
|
||||
//
|
||||
// Bytes to skew all requests, since DM Driver has been placed on an IDE drive.
|
||||
//
|
||||
|
||||
ULONG DMByteSkew;
|
||||
|
||||
//
|
||||
// Sectors to skew all requests.
|
||||
//
|
||||
|
||||
ULONG DMSkew;
|
||||
|
||||
//
|
||||
// Flag to indicate whether DM driver has been located on an IDE drive.
|
||||
//
|
||||
|
||||
BOOLEAN DMActive;
|
||||
|
||||
//
|
||||
// Pointer to the specific class error routine.
|
||||
//
|
||||
|
||||
PCLASS_ERROR ClassError;
|
||||
|
||||
//
|
||||
// SCSI port driver capabilities
|
||||
//
|
||||
|
||||
PIO_SCSI_CAPABILITIES PortCapabilities;
|
||||
|
||||
//
|
||||
// Buffer for drive parameters returned in IO device control.
|
||||
//
|
||||
|
||||
PDISK_GEOMETRY DiskGeometry;
|
||||
|
||||
//
|
||||
// Back pointer to device object of physical device
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT PhysicalDevice;
|
||||
|
||||
//
|
||||
// Request Sense Buffer
|
||||
//
|
||||
|
||||
PSENSE_DATA SenseData;
|
||||
|
||||
//
|
||||
// Request timeout in seconds;
|
||||
//
|
||||
|
||||
ULONG TimeOutValue;
|
||||
|
||||
//
|
||||
// System device number
|
||||
//
|
||||
|
||||
ULONG DeviceNumber;
|
||||
|
||||
//
|
||||
// Add default Srb Flags.
|
||||
//
|
||||
|
||||
ULONG SrbFlags;
|
||||
|
||||
//
|
||||
// Total number of SCSI protocol errors on the device.
|
||||
//
|
||||
|
||||
ULONG ErrorCount;
|
||||
|
||||
//
|
||||
// Spinlock for split requests
|
||||
//
|
||||
|
||||
KSPIN_LOCK SplitRequestSpinLock;
|
||||
|
||||
//
|
||||
// Zone header and spin lock for zoned SRB requests.
|
||||
//
|
||||
|
||||
PZONE_HEADER SrbZone;
|
||||
|
||||
PKSPIN_LOCK SrbZoneSpinLock;
|
||||
|
||||
//
|
||||
// Lock count for removable media.
|
||||
//
|
||||
|
||||
LONG LockCount;
|
||||
|
||||
//
|
||||
// Scsi port number
|
||||
//
|
||||
|
||||
UCHAR PortNumber;
|
||||
|
||||
//
|
||||
// SCSI path id
|
||||
//
|
||||
|
||||
UCHAR PathId;
|
||||
|
||||
//
|
||||
// SCSI bus target id
|
||||
//
|
||||
|
||||
UCHAR TargetId;
|
||||
|
||||
//
|
||||
// SCSI bus logical unit number
|
||||
//
|
||||
|
||||
UCHAR Lun;
|
||||
|
||||
//
|
||||
// Log2 of sector size
|
||||
//
|
||||
|
||||
UCHAR SectorShift;
|
||||
|
||||
//
|
||||
// Flag to indicate that the device has write caching enabled.
|
||||
//
|
||||
|
||||
BOOLEAN WriteCache;
|
||||
|
||||
//
|
||||
// Build SCSI 1 or SCSI 2 CDBs
|
||||
//
|
||||
|
||||
BOOLEAN UseScsi1;
|
||||
|
||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||||
|
||||
//
|
||||
// Define context structure for asynchronous completions.
|
||||
//
|
||||
|
||||
typedef struct _COMPLETION_CONTEXT {
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
SCSI_REQUEST_BLOCK Srb;
|
||||
}COMPLETION_CONTEXT, *PCOMPLETION_CONTEXT;
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassGetCapabilities(
|
||||
IN PDEVICE_OBJECT PortDeviceObject,
|
||||
OUT PIO_SCSI_CAPABILITIES *PortCapabilities
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassGetInquiryData(
|
||||
IN PDEVICE_OBJECT PortDeviceObject,
|
||||
IN PSCSI_ADAPTER_BUS_INFO *ConfigInfo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassReadDriveCapacity(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
VOID
|
||||
ScsiClassReleaseQueue(
|
||||
IN PDEVICE_OBJECT DeviceObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassRemoveDevice(
|
||||
IN PDEVICE_OBJECT PortDeviceObject,
|
||||
IN UCHAR PathId,
|
||||
IN UCHAR TargetId,
|
||||
IN UCHAR Lun
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassAsynchronousCompletion(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp,
|
||||
PVOID Context
|
||||
);
|
||||
|
||||
VOID
|
||||
ScsiClassSplitRequest(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN ULONG MaximumBytes
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassDeviceControl(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassIoComplete(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassIoCompleteAssociated(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
ScsiClassInterpretSenseInfo(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PSCSI_REQUEST_BLOCK Srb,
|
||||
IN UCHAR MajorFunctionCode,
|
||||
IN ULONG IoDeviceCode,
|
||||
IN ULONG RetryCount,
|
||||
OUT NTSTATUS *Status
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassSendSrbSynchronous(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
PVOID BufferAddress,
|
||||
ULONG BufferLength,
|
||||
BOOLEAN WriteToDevice
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassSendSrbAsynchronous(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
PIRP Irp,
|
||||
PVOID BufferAddress,
|
||||
ULONG BufferLength,
|
||||
BOOLEAN WriteToDevice
|
||||
);
|
||||
|
||||
VOID
|
||||
ScsiClassBuildRequest(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp
|
||||
);
|
||||
|
||||
ULONG
|
||||
ScsiClassModeSense(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PCHAR ModeSenseBuffer,
|
||||
IN ULONG Length,
|
||||
IN UCHAR PageMode
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
ScsiClassModeSelect(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PCHAR ModeSelectBuffer,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN SavePage
|
||||
);
|
||||
|
||||
PVOID
|
||||
ScsiClassFindModePage(
|
||||
IN PCHAR ModeSenseBuffer,
|
||||
IN ULONG Length,
|
||||
IN UCHAR PageMode
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassClaimDevice(
|
||||
IN PDEVICE_OBJECT PortDeviceObject,
|
||||
IN PSCSI_INQUIRY_DATA LunInfo,
|
||||
IN BOOLEAN Release,
|
||||
OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiClassInternalIoControl (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
#endif /* _CLASS_ */
|
||||
|
495
reactos/drivers/storage/inc/ide.h
Normal file
495
reactos/drivers/storage/inc/ide.h
Normal file
|
@ -0,0 +1,495 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1999 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
ide.h
|
||||
|
||||
Abstract:
|
||||
|
||||
These are the structures and defines that are used in the
|
||||
PCI IDE mini drivers.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#if !defined (___ide_h___)
|
||||
#define ___ide_h___
|
||||
|
||||
#include "ideuser.h"
|
||||
|
||||
#define MAX_IDE_DEVICE 2
|
||||
#define MAX_IDE_LINE 2
|
||||
#define MAX_IDE_CHANNEL 2
|
||||
|
||||
//
|
||||
// Some miniports need this structure.
|
||||
// IdentifyData is passed to the miniport in
|
||||
// the XfermodeSelect structure
|
||||
//
|
||||
|
||||
//
|
||||
// IDENTIFY data
|
||||
//
|
||||
|
||||
#pragma pack (1)
|
||||
typedef struct _IDENTIFY_DATA {
|
||||
USHORT GeneralConfiguration; // 00 00
|
||||
USHORT NumCylinders; // 02 1
|
||||
USHORT Reserved1; // 04 2
|
||||
USHORT NumHeads; // 06 3
|
||||
USHORT UnformattedBytesPerTrack; // 08 4
|
||||
USHORT UnformattedBytesPerSector; // 0A 5
|
||||
USHORT NumSectorsPerTrack; // 0C 6
|
||||
USHORT VendorUnique1[3]; // 0E 7-9
|
||||
UCHAR SerialNumber[20]; // 14 10-19
|
||||
USHORT BufferType; // 28 20
|
||||
USHORT BufferSectorSize; // 2A 21
|
||||
USHORT NumberOfEccBytes; // 2C 22
|
||||
UCHAR FirmwareRevision[8]; // 2E 23-26
|
||||
UCHAR ModelNumber[40]; // 36 27-46
|
||||
UCHAR MaximumBlockTransfer; // 5E 47
|
||||
UCHAR VendorUnique2; // 5F
|
||||
USHORT DoubleWordIo; // 60 48
|
||||
USHORT Capabilities; // 62 49
|
||||
USHORT Reserved2; // 64 50
|
||||
UCHAR VendorUnique3; // 66 51
|
||||
UCHAR PioCycleTimingMode; // 67
|
||||
UCHAR VendorUnique4; // 68 52
|
||||
UCHAR DmaCycleTimingMode; // 69
|
||||
USHORT TranslationFieldsValid:3; // 6A 53
|
||||
USHORT Reserved3:13;
|
||||
USHORT NumberOfCurrentCylinders; // 6C 54
|
||||
USHORT NumberOfCurrentHeads; // 6E 55
|
||||
USHORT CurrentSectorsPerTrack; // 70 56
|
||||
ULONG CurrentSectorCapacity; // 72 57-58
|
||||
USHORT CurrentMultiSectorSetting; // 59
|
||||
ULONG UserAddressableSectors; // 60-61
|
||||
USHORT SingleWordDMASupport : 8; // 62
|
||||
USHORT SingleWordDMAActive : 8;
|
||||
USHORT MultiWordDMASupport : 8; // 63
|
||||
USHORT MultiWordDMAActive : 8;
|
||||
USHORT AdvancedPIOModes : 8; // 64
|
||||
USHORT Reserved4 : 8;
|
||||
USHORT MinimumMWXferCycleTime; // 65
|
||||
USHORT RecommendedMWXferCycleTime; // 66
|
||||
USHORT MinimumPIOCycleTime; // 67
|
||||
USHORT MinimumPIOCycleTimeIORDY; // 68
|
||||
USHORT Reserved5[11]; // 69-79
|
||||
USHORT MajorRevision; // 80
|
||||
USHORT MinorRevision; // 81
|
||||
USHORT Reserved6; // 82
|
||||
USHORT CommandSetSupport; // 83
|
||||
USHORT Reserved6a[2]; // 84-85
|
||||
USHORT CommandSetActive; // 86
|
||||
USHORT Reserved6b; // 87
|
||||
USHORT UltraDMASupport : 8; // 88
|
||||
USHORT UltraDMAActive : 8; //
|
||||
USHORT Reserved7[11]; // 89-99
|
||||
ULONG Max48BitLBA[2]; // 100-103
|
||||
USHORT Reserved7a[22]; // 104-125
|
||||
USHORT LastLun:3; // 126
|
||||
USHORT Reserved8:13;
|
||||
USHORT MediaStatusNotification:2; // 127
|
||||
USHORT Reserved9:6;
|
||||
USHORT DeviceWriteProtect:1;
|
||||
USHORT Reserved10:7;
|
||||
USHORT Reserved11[128]; // 128-255
|
||||
} IDENTIFY_DATA, *PIDENTIFY_DATA;
|
||||
|
||||
//
|
||||
// Identify data without the Reserved4.
|
||||
//
|
||||
|
||||
//typedef struct _IDENTIFY_DATA2 {
|
||||
// USHORT GeneralConfiguration; // 00 00
|
||||
// USHORT NumCylinders; // 02 1
|
||||
// USHORT Reserved1; // 04 2
|
||||
// USHORT NumHeads; // 06 3
|
||||
// USHORT UnformattedBytesPerTrack; // 08 4
|
||||
// USHORT UnformattedBytesPerSector; // 0A 5
|
||||
// USHORT NumSectorsPerTrack; // 0C 6
|
||||
// USHORT VendorUnique1[3]; // 0E 7-9
|
||||
// UCHAR SerialNumber[20]; // 14 10-19
|
||||
// USHORT BufferType; // 28 20
|
||||
// USHORT BufferSectorSize; // 2A 21
|
||||
// USHORT NumberOfEccBytes; // 2C 22
|
||||
// UCHAR FirmwareRevision[8]; // 2E 23-26
|
||||
// UCHAR ModelNumber[40]; // 36 27-46
|
||||
// UCHAR MaximumBlockTransfer; // 5E 47
|
||||
// UCHAR VendorUnique2; // 5F
|
||||
// USHORT DoubleWordIo; // 60 48
|
||||
// USHORT Capabilities; // 62 49
|
||||
// USHORT Reserved2; // 64 50
|
||||
// UCHAR VendorUnique3; // 66 51
|
||||
// UCHAR PioCycleTimingMode; // 67
|
||||
// UCHAR VendorUnique4; // 68 52
|
||||
// UCHAR DmaCycleTimingMode; // 69
|
||||
// USHORT TranslationFieldsValid:3; // 6A 53
|
||||
// USHORT Reserved3:13;
|
||||
// USHORT NumberOfCurrentCylinders; // 6C 54
|
||||
// USHORT NumberOfCurrentHeads; // 6E 55
|
||||
// USHORT CurrentSectorsPerTrack; // 70 56
|
||||
// ULONG CurrentSectorCapacity; // 72 57-58
|
||||
// USHORT CurrentMultiSectorSetting; // 59
|
||||
// ULONG UserAddressableSectors; // 60-61
|
||||
// USHORT SingleWordDMASupport : 8; // 62
|
||||
// USHORT SingleWordDMAActive : 8;
|
||||
// USHORT MultiWordDMASupport : 8; // 63
|
||||
// USHORT MultiWordDMAActive : 8;
|
||||
// USHORT AdvancedPIOModes : 8; // 64
|
||||
// USHORT Reserved4 : 8;
|
||||
// USHORT MinimumMWXferCycleTime; // 65
|
||||
// USHORT RecommendedMWXferCycleTime; // 66
|
||||
// USHORT MinimumPIOCycleTime; // 67
|
||||
// USHORT MinimumPIOCycleTimeIORDY; // 68
|
||||
// USHORT Reserved5[11]; // 69-79
|
||||
// USHORT MajorRevision; // 80
|
||||
// USHORT MinorRevision; // 81
|
||||
// USHORT Reserved6[6]; // 82-87
|
||||
// USHORT UltraDMASupport : 8; // 88
|
||||
// USHORT UltraDMAActive : 8; //
|
||||
// USHORT Reserved7[37]; // 89-125
|
||||
// USHORT LastLun:3; // 126
|
||||
// USHORT Reserved8:13;
|
||||
// USHORT MediaStatusNotification:2; // 127
|
||||
// USHORT Reserved9:6;
|
||||
// USHORT DeviceWriteProtect:1;
|
||||
// USHORT Reserved10:7;
|
||||
//} IDENTIFY_DATA2, *PIDENTIFY_DATA2;
|
||||
#pragma pack ()
|
||||
|
||||
#define IDENTIFY_DATA_SIZE sizeof(IDENTIFY_DATA)
|
||||
|
||||
|
||||
//
|
||||
// The structure is passed to pci ide mini driver
|
||||
// TransferModeSelect callback for selecting
|
||||
// proper transfer mode the the devices connected
|
||||
// to the given IDE channel
|
||||
//
|
||||
typedef struct _PCIIDE_TRANSFER_MODE_SELECT {
|
||||
|
||||
//
|
||||
// Input Parameters
|
||||
//
|
||||
|
||||
//
|
||||
// IDE Channel Number. 0 or 1
|
||||
//
|
||||
ULONG Channel;
|
||||
|
||||
//
|
||||
// Indicate whether devices are present
|
||||
//
|
||||
BOOLEAN DevicePresent[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Indicate whether devices are ATA harddisk
|
||||
//
|
||||
BOOLEAN FixedDisk[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Indicate whether devices support IO Ready Line
|
||||
//
|
||||
BOOLEAN IoReadySupported[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Indicate the data transfer modes devices support
|
||||
//
|
||||
ULONG DeviceTransferModeSupported[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Indicate devices' best timings for PIO, single word DMA,
|
||||
// multiword DMA, and Ultra DMA modes
|
||||
//
|
||||
ULONG BestPioCycleTime[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
ULONG BestSwDmaCycleTime[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
ULONG BestMwDmaCycleTime[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
ULONG BestUDmaCycleTime[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Indicate devices' current data transfer modes
|
||||
//
|
||||
ULONG DeviceTransferModeCurrent[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// The user's choice. This will allow pciidex to
|
||||
// default to a transfer mode indicated by the mini driver
|
||||
//
|
||||
ULONG UserChoiceTransferMode[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// This enables UDMA66 on the intel chipsets
|
||||
//
|
||||
ULONG EnableUDMA66;
|
||||
|
||||
//
|
||||
//Some miniports need this
|
||||
// The miniport will save this data in their deviceExtension
|
||||
//
|
||||
IDENTIFY_DATA IdentifyData[MAX_IDE_DEVICE];
|
||||
|
||||
|
||||
//
|
||||
// Output Parameters
|
||||
//
|
||||
|
||||
//
|
||||
// Indicate devices' data transfer modes chosen by
|
||||
// the pcii ide mini drive
|
||||
//
|
||||
ULONG DeviceTransferModeSelected[MAX_IDE_DEVICE * MAX_IDE_LINE];
|
||||
|
||||
//
|
||||
// Transfermode timings
|
||||
//
|
||||
PULONG TransferModeTimingTable;
|
||||
ULONG TransferModeTableLength;
|
||||
|
||||
} PCIIDE_TRANSFER_MODE_SELECT, *PPCIIDE_TRANSFER_MODE_SELECT;
|
||||
|
||||
//
|
||||
// possible ide channel state
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
ChannelDisabled = 0,
|
||||
ChannelEnabled,
|
||||
ChannelStateUnknown
|
||||
} IDE_CHANNEL_STATE;
|
||||
|
||||
|
||||
//
|
||||
// Prototype for different PCI IDE mini driver
|
||||
// callbacks
|
||||
//
|
||||
typedef IDE_CHANNEL_STATE
|
||||
(*PCIIDE_CHANNEL_ENABLED) (
|
||||
IN PVOID DeviceExtension,
|
||||
IN ULONG Channel
|
||||
);
|
||||
|
||||
typedef BOOLEAN
|
||||
(*PCIIDE_SYNC_ACCESS_REQUIRED) (
|
||||
IN PVOID DeviceExtension
|
||||
);
|
||||
|
||||
typedef NTSTATUS
|
||||
(*PCIIDE_TRANSFER_MODE_SELECT_FUNC) (
|
||||
IN PVOID DeviceExtension,
|
||||
IN OUT PPCIIDE_TRANSFER_MODE_SELECT TransferModeSelect
|
||||
);
|
||||
|
||||
typedef ULONG
|
||||
(*PCIIDE_USEDMA_FUNC)(
|
||||
IN PVOID deviceExtension,
|
||||
IN PVOID cdbCmd,
|
||||
IN UCHAR targetID
|
||||
);
|
||||
|
||||
typedef NTSTATUS
|
||||
(*PCIIDE_UDMA_MODES_SUPPORTED) (
|
||||
IDENTIFY_DATA IdentifyData,
|
||||
PULONG BestXferMode,
|
||||
PULONG CurrentMode
|
||||
);
|
||||
//
|
||||
// This structure is for the PCI IDE mini driver to
|
||||
// return its properties
|
||||
//
|
||||
typedef struct _IDE_CONTROLLER_PROPERTIES {
|
||||
|
||||
//
|
||||
// sizeof (IDE_CONTROLLER_PROPERTIES)
|
||||
//
|
||||
ULONG Size;
|
||||
|
||||
//
|
||||
// Indicate the amount of memory PCI IDE mini driver
|
||||
// needs for its private data
|
||||
//
|
||||
ULONG ExtensionSize;
|
||||
|
||||
//
|
||||
// Indicate all the data transfer modes the PCI IDE
|
||||
// controller supports
|
||||
//
|
||||
ULONG SupportedTransferMode[MAX_IDE_CHANNEL][MAX_IDE_DEVICE];
|
||||
|
||||
//
|
||||
// callback to query whether a IDE channel is enabled
|
||||
//
|
||||
PCIIDE_CHANNEL_ENABLED PciIdeChannelEnabled;
|
||||
|
||||
//
|
||||
// callback to query whether both IDE channels requires
|
||||
// synchronized access. (one channel at a time)
|
||||
//
|
||||
PCIIDE_SYNC_ACCESS_REQUIRED PciIdeSyncAccessRequired;
|
||||
|
||||
//
|
||||
// callback to select proper transfer modes for the
|
||||
// given devices
|
||||
//
|
||||
PCIIDE_TRANSFER_MODE_SELECT_FUNC PciIdeTransferModeSelect;
|
||||
|
||||
//
|
||||
// at the end of a ATA data transfer, ignores busmaster
|
||||
// status active bit. Normally, it should be FALSE
|
||||
//
|
||||
BOOLEAN IgnoreActiveBitForAtaDevice;
|
||||
|
||||
//
|
||||
// always clear the busmaster interrupt on every interrupt
|
||||
// generated by the device. Normnally, it should be FALSE
|
||||
//
|
||||
BOOLEAN AlwaysClearBusMasterInterrupt;
|
||||
|
||||
//
|
||||
// callback to determine whether DMA should be used or not
|
||||
// called for every IO
|
||||
//
|
||||
PCIIDE_USEDMA_FUNC PciIdeUseDma;
|
||||
|
||||
|
||||
//
|
||||
// if the miniport needs a different alignment
|
||||
//
|
||||
ULONG AlignmentRequirement;
|
||||
|
||||
ULONG DefaultPIO;
|
||||
|
||||
//
|
||||
// retrieves the supported udma modes from the Identify data
|
||||
//
|
||||
PCIIDE_UDMA_MODES_SUPPORTED PciIdeUdmaModesSupported;
|
||||
|
||||
} IDE_CONTROLLER_PROPERTIES, *PIDE_CONTROLLER_PROPERTIES;
|
||||
|
||||
//
|
||||
// callback to query PCI IDE controller properties
|
||||
//
|
||||
typedef
|
||||
NTSTATUS (*PCONTROLLER_PROPERTIES) (
|
||||
IN PVOID DeviceExtension,
|
||||
IN PIDE_CONTROLLER_PROPERTIES ControllerProperties
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// To initailize PCI IDE mini driver
|
||||
//
|
||||
NTSTATUS
|
||||
PciIdeXInitialize(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath,
|
||||
IN PCONTROLLER_PROPERTIES PciIdeGetControllerProperties,
|
||||
IN ULONG ExtensionSize
|
||||
);
|
||||
|
||||
//
|
||||
// To query PCI IDE config space data
|
||||
//
|
||||
NTSTATUS
|
||||
PciIdeXGetBusData(
|
||||
IN PVOID DeviceExtension,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG ConfigDataOffset,
|
||||
IN ULONG BufferLength
|
||||
);
|
||||
|
||||
//
|
||||
// To save PCI IDE config space data
|
||||
//
|
||||
NTSTATUS
|
||||
PciIdeXSetBusData(
|
||||
IN PVOID DeviceExtension,
|
||||
IN PVOID Buffer,
|
||||
IN PVOID DataMask,
|
||||
IN ULONG ConfigDataOffset,
|
||||
IN ULONG BufferLength
|
||||
);
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _PCIIDE_CONFIG_HEADER {
|
||||
|
||||
USHORT VendorID; // (ro)
|
||||
USHORT DeviceID; // (ro)
|
||||
|
||||
//
|
||||
// Command
|
||||
//
|
||||
union {
|
||||
|
||||
struct {
|
||||
|
||||
USHORT IoAccessEnable:1; // Device control
|
||||
USHORT MemAccessEnable:1;
|
||||
USHORT MasterEnable:1;
|
||||
USHORT SpecialCycle:1;
|
||||
USHORT MemWriteInvalidateEnable:1;
|
||||
USHORT VgaPaletteSnoopEnable:1;
|
||||
USHORT ParityErrorResponse:1;
|
||||
USHORT WaitCycleEnable:1;
|
||||
USHORT SystemErrorEnable:1;
|
||||
USHORT FastBackToBackEnable:1;
|
||||
USHORT CommandReserved:6;
|
||||
} b;
|
||||
|
||||
USHORT w;
|
||||
|
||||
} Command;
|
||||
|
||||
|
||||
USHORT Status;
|
||||
UCHAR RevisionID; // (ro)
|
||||
|
||||
//
|
||||
// Program Interface
|
||||
//
|
||||
UCHAR Chan0OpMode:1;
|
||||
UCHAR Chan0Programmable:1;
|
||||
UCHAR Chan1OpMode:1;
|
||||
UCHAR Chan1Programmable:1;
|
||||
UCHAR ProgIfReserved:3;
|
||||
UCHAR MasterIde:1;
|
||||
|
||||
UCHAR SubClass; // (ro)
|
||||
UCHAR BaseClass; // (ro)
|
||||
UCHAR CacheLineSize; // (ro+)
|
||||
UCHAR LatencyTimer; // (ro+)
|
||||
UCHAR HeaderType; // (ro)
|
||||
UCHAR BIST; // Built in self test
|
||||
|
||||
struct _PCI_HEADER_TYPE_0 type0;
|
||||
|
||||
} PCIIDE_CONFIG_HEADER, *PPCIIDE_CONFIG_HEADER;
|
||||
#pragma pack()
|
||||
|
||||
//
|
||||
// Debug Print
|
||||
//
|
||||
#if DBG
|
||||
|
||||
VOID
|
||||
PciIdeXDebugPrint(
|
||||
ULONG DebugPrintLevel,
|
||||
PCCHAR DebugMessage,
|
||||
...
|
||||
);
|
||||
|
||||
#define PciIdeXDebugPrint(x) PciIdeXDebugPrint x
|
||||
|
||||
#else
|
||||
|
||||
#define PciIdeXDebugPrint(x)
|
||||
|
||||
#endif // DBG
|
||||
|
||||
#endif // ___ide_h___
|
||||
|
132
reactos/drivers/storage/inc/ideuser.h
Normal file
132
reactos/drivers/storage/inc/ideuser.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1999 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
ideuser.h
|
||||
|
||||
Abstract:
|
||||
|
||||
These are the structures and defines that are used in the
|
||||
PCI IDE mini drivers.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#if !defined (___ideuser_h___)
|
||||
#define ___ideuser_h___
|
||||
|
||||
|
||||
#define PIO_MODE0 (1 << 0)
|
||||
#define PIO_MODE1 (1 << 1)
|
||||
#define PIO_MODE2 (1 << 2)
|
||||
#define PIO_MODE3 (1 << 3)
|
||||
#define PIO_MODE4 (1 << 4)
|
||||
|
||||
#define SWDMA_MODE0 (1 << 5)
|
||||
#define SWDMA_MODE1 (1 << 6)
|
||||
#define SWDMA_MODE2 (1 << 7)
|
||||
|
||||
#define MWDMA_MODE0 (1 << 8)
|
||||
#define MWDMA_MODE1 (1 << 9)
|
||||
#define MWDMA_MODE2 (1 << 10)
|
||||
|
||||
#define UDMA_MODE0 (1 << 11)
|
||||
#define UDMA_MODE1 (1 << 12)
|
||||
#define UDMA_MODE2 (1 << 13)
|
||||
#define UDMA_MODE3 (1 << 14)
|
||||
#define UDMA_MODE4 (1 << 15)
|
||||
#define UDMA_MODE5 (1 << 16)
|
||||
|
||||
#define PIO_SUPPORT (PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4)
|
||||
#define SWDMA_SUPPORT (SWDMA_MODE0 | SWDMA_MODE1 | SWDMA_MODE2)
|
||||
#define MWDMA_SUPPORT (MWDMA_MODE0 | MWDMA_MODE1 | MWDMA_MODE2)
|
||||
#define UDMA33_SUPPORT (UDMA_MODE0 | UDMA_MODE1 | UDMA_MODE2)
|
||||
#define UDMA66_SUPPORT (UDMA_MODE3 | UDMA_MODE4)
|
||||
#define UDMA100_SUPPORT (UDMA_MODE5 )
|
||||
#define UDMA_SUPPORT (UNINITIALIZED_TRANSFER_MODE & (~(PIO_SUPPORT | SWDMA_SUPPORT | MWDMA_SUPPORT)))
|
||||
|
||||
#define DMA_SUPPORT (SWDMA_SUPPORT | MWDMA_SUPPORT | UDMA_SUPPORT)
|
||||
#define ALL_MODE_SUPPORT (PIO_SUPPORT | DMA_SUPPORT)
|
||||
|
||||
#define PIO0 0
|
||||
#define PIO1 1
|
||||
#define PIO2 2
|
||||
#define PIO3 3
|
||||
#define PIO4 4
|
||||
#define SWDMA0 5
|
||||
#define SWDMA1 6
|
||||
#define SWDMA2 7
|
||||
#define MWDMA0 8
|
||||
#define MWDMA1 9
|
||||
#define MWDMA2 10
|
||||
#define UDMA0 11
|
||||
|
||||
#define MAX_XFER_MODE 17
|
||||
#define UNINITIALIZED_CYCLE_TIME 0xffffffff
|
||||
#define UNINITIALIZED_TRANSFER_MODE 0x7fffffff
|
||||
#define IS_DEFAULT(mode) (!(mode & 0x80000000))
|
||||
|
||||
#define GenTransferModeMask(i, mode) {\
|
||||
ULONG temp=0xffffffff; \
|
||||
mode |= (temp >> (31-(i)));\
|
||||
}
|
||||
|
||||
//
|
||||
// mode should not be 0
|
||||
//
|
||||
#define GetHighestTransferMode(mode, i) {\
|
||||
ULONG temp=(mode); \
|
||||
ASSERT(temp); \
|
||||
i=0; \
|
||||
while ( temp) { \
|
||||
temp = (temp >> 1);\
|
||||
i++;\
|
||||
} \
|
||||
i--; \
|
||||
}
|
||||
|
||||
#define GetHighestDMATransferMode(mode, i) {\
|
||||
ULONG temp=mode >> 5;\
|
||||
i=5; \
|
||||
while ( temp) { \
|
||||
temp = (temp >> 1); \
|
||||
i++; \
|
||||
} \
|
||||
i--; \
|
||||
}
|
||||
#define GetHighestPIOTransferMode(mode, i) { \
|
||||
ULONG temp = (mode & PIO_SUPPORT); \
|
||||
i=0; \
|
||||
temp = temp >> 1; \
|
||||
while (temp) { \
|
||||
temp = temp >> 1; \
|
||||
i++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SetDefaultTiming(timingTable, length) {\
|
||||
timingTable[0]=PIO_MODE0_CYCLE_TIME; \
|
||||
timingTable[1]=PIO_MODE1_CYCLE_TIME; \
|
||||
timingTable[2]=PIO_MODE2_CYCLE_TIME; \
|
||||
timingTable[3]=PIO_MODE3_CYCLE_TIME; \
|
||||
timingTable[4]=PIO_MODE4_CYCLE_TIME; \
|
||||
timingTable[5]=SWDMA_MODE0_CYCLE_TIME; \
|
||||
timingTable[6]=SWDMA_MODE1_CYCLE_TIME; \
|
||||
timingTable[7]=SWDMA_MODE2_CYCLE_TIME; \
|
||||
timingTable[8]=MWDMA_MODE0_CYCLE_TIME; \
|
||||
timingTable[9]=MWDMA_MODE1_CYCLE_TIME; \
|
||||
timingTable[10]=MWDMA_MODE2_CYCLE_TIME; \
|
||||
timingTable[11]=UDMA_MODE0_CYCLE_TIME; \
|
||||
timingTable[12]=UDMA_MODE1_CYCLE_TIME; \
|
||||
timingTable[13]=UDMA_MODE2_CYCLE_TIME; \
|
||||
timingTable[14]=UDMA_MODE3_CYCLE_TIME; \
|
||||
timingTable[15]=UDMA_MODE4_CYCLE_TIME; \
|
||||
timingTable[16]=UDMA_MODE5_CYCLE_TIME; \
|
||||
length = MAX_XFER_MODE; \
|
||||
}
|
||||
|
||||
#endif // ___ideuser_h___
|
||||
|
115
reactos/drivers/storage/inc/physlogi.h
Normal file
115
reactos/drivers/storage/inc/physlogi.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) 1992 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
physlogi.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains structures and defines that are used
|
||||
specifically for the tape drivers. Contains #define's,
|
||||
function protypes, etc. for use in calling functions in
|
||||
physlogi.c that do physical to pseudo-logical and pseudo-
|
||||
logical to physical tape block address/position translation.
|
||||
|
||||
Author:
|
||||
|
||||
Mike Colandreo (Maynard)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
// begin_ntminitape
|
||||
|
||||
//
|
||||
// defines for QIC tape density codes
|
||||
//
|
||||
|
||||
#define QIC_XX 0 // ????
|
||||
#define QIC_24 5 // 0x05
|
||||
#define QIC_120 15 // 0x0F
|
||||
#define QIC_150 16 // 0x10
|
||||
#define QIC_525 17 // 0x11
|
||||
#define QIC_1350 18 // 0x12
|
||||
#define QIC_1000 21 // 0x15
|
||||
#define QIC_1000C 30 // 0x1E
|
||||
#define QIC_2100 31 // 0x1F
|
||||
#define QIC_2GB 34 // 0x22
|
||||
#define QIC_5GB 40 // 0x28
|
||||
|
||||
//
|
||||
// defines for QIC tape media codes
|
||||
//
|
||||
|
||||
#define DCXXXX 0
|
||||
#define DC300 1
|
||||
#define DC300XLP 2
|
||||
#define DC615 3
|
||||
#define DC600 4
|
||||
#define DC6037 5
|
||||
#define DC6150 6
|
||||
#define DC6250 7
|
||||
#define DC6320 8
|
||||
#define DC6525 9
|
||||
#define DC9135SL 33 //0x21
|
||||
#define DC9210 34 //0x22
|
||||
#define DC9135 35 //0x23
|
||||
#define DC9100 36 //0x24
|
||||
#define DC9120 37 //0x25
|
||||
#define DC9120SL 38 //0x26
|
||||
#define DC9164 39 //0x27
|
||||
#define DCXXXXFW 48 //0x30
|
||||
#define DC9200SL 49 //0x31
|
||||
#define DC9210XL 50 //0x32
|
||||
#define DC10GB 51 //0x33
|
||||
#define DC9200 52 //0x34
|
||||
#define DC9120XL 53 //0x35
|
||||
#define DC9210SL 54 //0x36
|
||||
#define DC9164XL 55 //0x37
|
||||
#define DC9200XL 64 //0x40
|
||||
#define DC9400 65 //0x41
|
||||
#define DC9500 66 //0x42
|
||||
#define DC9500SL 70 //0x46
|
||||
|
||||
//
|
||||
// defines for translation reference point
|
||||
//
|
||||
|
||||
#define NOT_FROM_BOT 0
|
||||
#define FROM_BOT 1
|
||||
|
||||
//
|
||||
// info/structure returned by/from
|
||||
// TapeLogicalBlockToPhysicalBlock( )
|
||||
//
|
||||
|
||||
typedef struct _TAPE_PHYS_POSITION {
|
||||
ULONG SeekBlockAddress;
|
||||
ULONG SpaceBlockCount;
|
||||
} TAPE_PHYS_POSITION, PTAPE_PHYS_POSITION;
|
||||
|
||||
//
|
||||
// function prototypes
|
||||
//
|
||||
|
||||
TAPE_PHYS_POSITION
|
||||
TapeClassLogicalBlockToPhysicalBlock(
|
||||
IN UCHAR DensityCode,
|
||||
IN ULONG LogicalBlockAddress,
|
||||
IN ULONG BlockLength,
|
||||
IN BOOLEAN FromBOT
|
||||
);
|
||||
|
||||
ULONG
|
||||
TapeClassPhysicalBlockToLogicalBlock(
|
||||
IN UCHAR DensityCode,
|
||||
IN ULONG PhysicalBlockAddress,
|
||||
IN ULONG BlockLength,
|
||||
IN BOOLEAN FromBOT
|
||||
);
|
||||
|
||||
// end_ntminitape
|
||||
|
180
reactos/drivers/storage/inc/rbc.h
Normal file
180
reactos/drivers/storage/inc/rbc.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*++
|
||||
|
||||
Copyright (C) Microsoft Corporation, 1998 - 1999
|
||||
|
||||
Module Name:
|
||||
|
||||
rbc.h
|
||||
|
||||
Abstract:
|
||||
|
||||
These are the structures and defines used in the Reduced Block Command set
|
||||
|
||||
Authors:
|
||||
|
||||
George Chrysanthakopoulos(georgioc) - April 1998
|
||||
|
||||
Revision History:
|
||||
|
||||
Dan Knudson (DanKn), 23 Sep 1999 - updated per rev 10 of RBC spec
|
||||
|
||||
--*/
|
||||
#ifndef _NTRBC_
|
||||
#define _NTRBC_
|
||||
|
||||
#include "scsi.h"
|
||||
|
||||
//
|
||||
// Command Descriptor Block. encapsulated under the bus/protocol specific request block
|
||||
//
|
||||
|
||||
typedef union _CDB_RBC {
|
||||
|
||||
//
|
||||
// format unit
|
||||
//
|
||||
|
||||
struct _FORMAT_RBC {
|
||||
UCHAR OperationCode;
|
||||
UCHAR VendorSpecific;
|
||||
UCHAR Increment : 1;
|
||||
UCHAR Percent_Time : 1;
|
||||
UCHAR Reserved1 : 1;
|
||||
UCHAR VendorSpecific1 : 5;
|
||||
UCHAR Reserved2[2];
|
||||
UCHAR Control;
|
||||
} FORMAT_RBC, *PFORMAT_RBC;
|
||||
|
||||
//
|
||||
// prevent/allow medium removal
|
||||
//
|
||||
|
||||
struct _MEDIA_REMOVAL_RBC {
|
||||
UCHAR OperationCode;
|
||||
UCHAR Reserved[3];
|
||||
|
||||
UCHAR Prevent : 1;
|
||||
UCHAR Persistant : 1;
|
||||
UCHAR Reserved3 : 6;
|
||||
|
||||
UCHAR Control;
|
||||
} MEDIA_REMOVAL_RBC, *PMEDIA_REMOVAL_RBC;
|
||||
|
||||
//
|
||||
// START_STOP_UNIT
|
||||
//
|
||||
|
||||
struct _START_STOP_RBC {
|
||||
UCHAR OperationCode;
|
||||
UCHAR Immediate: 1;
|
||||
UCHAR Reserved1 : 7;
|
||||
UCHAR Reserved2[2];
|
||||
UCHAR Start : 1;
|
||||
UCHAR LoadEject : 1;
|
||||
UCHAR Reserved3 : 2;
|
||||
UCHAR PowerConditions : 4;
|
||||
UCHAR Control;
|
||||
} START_STOP_RBC, *PSTART_STOP_RBC;
|
||||
|
||||
struct _SYNCHRONIZE_CACHE_RBC {
|
||||
|
||||
UCHAR OperationCode; // 0x35
|
||||
UCHAR Reserved[8];
|
||||
UCHAR Control;
|
||||
|
||||
} SYNCHRONIZE_CACHE_RBC, *PSYNCHRONIZE_CACHE_RBC;
|
||||
|
||||
|
||||
} CDB_RBC, *PCDB_RBC;
|
||||
|
||||
|
||||
//
|
||||
// START_STOP_UNIT Power Condition descriptions
|
||||
//
|
||||
|
||||
#define START_STOP_RBC_POWER_CND_NO_CHANGE 0
|
||||
#define START_STOP_RBC_POWER_CND_ACTIVE 1
|
||||
#define START_STOP_RBC_POWER_CND_IDLE 2
|
||||
#define START_STOP_RBC_POWER_CND_STANDBY 3
|
||||
#define START_STOP_RBC_POWER_CND_SLEEP 5
|
||||
#define START_STOP_RBC_POWER_CND_DEVICE_CTRL 7
|
||||
|
||||
|
||||
//
|
||||
// Mode Sense/Select page constants.
|
||||
//
|
||||
|
||||
#define MODE_PAGE_RBC_DEVICE_PARAMETERS 0x06
|
||||
|
||||
|
||||
//
|
||||
// DeviceType field in inquiry Data
|
||||
//
|
||||
|
||||
#define RBC_DEVICE 0x0E
|
||||
|
||||
//
|
||||
// Define Device Capabilities page.
|
||||
//
|
||||
|
||||
typedef struct _MODE_RBC_DEVICE_PARAMETERS_PAGE {
|
||||
UCHAR PageCode : 6;
|
||||
UCHAR Reserved : 1;
|
||||
UCHAR PageSavable : 1;
|
||||
UCHAR PageLength;
|
||||
UCHAR WriteCacheDisable : 1;
|
||||
UCHAR Reserved1 : 7;
|
||||
UCHAR LogicalBlockSize[2];
|
||||
UCHAR NumberOfLogicalBlocks[5];
|
||||
UCHAR PowerPerformance;
|
||||
UCHAR LockDisabled : 1;
|
||||
UCHAR FormatDisabled : 1;
|
||||
UCHAR WriteDisabled : 1;
|
||||
UCHAR ReadDisabled : 1;
|
||||
UCHAR Reserved2 : 4;
|
||||
UCHAR Reserved3;
|
||||
|
||||
}MODE_RBC_DEVICE_PARAMETERS_PAGE, *PMODE_RBC_DEVICE_PARAMETERS_PAGE;
|
||||
|
||||
typedef struct _MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE {
|
||||
|
||||
MODE_PARAMETER_HEADER Header;
|
||||
MODE_RBC_DEVICE_PARAMETERS_PAGE Page;
|
||||
|
||||
}MODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE,
|
||||
*PMODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE;
|
||||
|
||||
|
||||
//
|
||||
// unsolicited status sense code qualifier values
|
||||
//
|
||||
|
||||
#define RBC_UNSOLICITED_STATUS 0x02
|
||||
#define RBC_UNSOLICITED_SENSE_KEY 0x06
|
||||
|
||||
#define RBC_UNSOLICITED_SC_PWR_STATE_CHNG 0xFF
|
||||
#define RBC_UNSOLICITED_SC_EVENT_STATUS 0xFE
|
||||
|
||||
#define RBC_UNSOLICITED_CLASS_ASQ_DEVICE 0x06
|
||||
#define RBC_UNSOLICITED_CLASS_ASQ_MEDIA 0x04
|
||||
#define RBC_UNSOLICITED_CLASS_ASQ_POWER 0x02
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Translation routine used to convert SCSI requests that differ from RBC
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
Rbc_Scsi_Conversion(
|
||||
IN PSCSI_REQUEST_BLOCK Srb,
|
||||
IN PSCSI_REQUEST_BLOCK *OriginalSrb,
|
||||
IN PMODE_RBC_DEVICE_PARAMETERS_HEADER_AND_PAGE RbcHeaderAndPage,
|
||||
IN BOOLEAN OutgoingRequest,
|
||||
IN BOOLEAN RemovableMedia
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
|
312
reactos/drivers/storage/inc/tape.h
Normal file
312
reactos/drivers/storage/inc/tape.h
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*++
|
||||
|
||||
Copyright (c) 1992 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
tape.h
|
||||
|
||||
Abstract:
|
||||
|
||||
These are the structures and defines that are used in the
|
||||
SCSI tape class drivers. The tape class driver is separated
|
||||
into two modules. Tape.c contains code common to all tape
|
||||
class drivers including the driver's major entry points.
|
||||
The major entry point names each begin with the prefix
|
||||
'ScsiTape.' The second module is the device specific code.
|
||||
It provides support for a set of functions. Each device
|
||||
specific function name is prefixed by 'Tape.'
|
||||
|
||||
Author:
|
||||
|
||||
Mike Glass
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include "scsi.h"
|
||||
#include "class.h"
|
||||
|
||||
//
|
||||
// Define the maximum inquiry data length.
|
||||
//
|
||||
|
||||
#define MAXIMUM_TAPE_INQUIRY_DATA 252
|
||||
|
||||
//
|
||||
// Tape device data
|
||||
//
|
||||
|
||||
typedef struct _TAPE_DATA {
|
||||
ULONG Flags;
|
||||
ULONG CurrentPartition;
|
||||
PVOID DeviceSpecificExtension;
|
||||
PSCSI_INQUIRY_DATA InquiryData;
|
||||
} TAPE_DATA, *PTAPE_DATA;
|
||||
|
||||
#define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(TAPE_DATA)
|
||||
|
||||
|
||||
//
|
||||
// Define Device Configuration Page
|
||||
//
|
||||
|
||||
typedef struct _MODE_DEVICE_CONFIGURATION_PAGE {
|
||||
|
||||
UCHAR PageCode : 6;
|
||||
UCHAR Reserved1 : 1;
|
||||
UCHAR PS : 1;
|
||||
UCHAR PageLength;
|
||||
UCHAR ActiveFormat : 5;
|
||||
UCHAR CAFBit : 1;
|
||||
UCHAR CAPBit : 1;
|
||||
UCHAR Reserved2 : 1;
|
||||
UCHAR ActivePartition;
|
||||
UCHAR WriteBufferFullRatio;
|
||||
UCHAR ReadBufferEmptyRatio;
|
||||
UCHAR WriteDelayTime[2];
|
||||
UCHAR REW : 1;
|
||||
UCHAR RBO : 1;
|
||||
UCHAR SOCF : 2;
|
||||
UCHAR AVC : 1;
|
||||
UCHAR RSmk : 1;
|
||||
UCHAR BIS : 1;
|
||||
UCHAR DBR : 1;
|
||||
UCHAR GapSize;
|
||||
UCHAR Reserved3 : 3;
|
||||
UCHAR SEW : 1;
|
||||
UCHAR EEG : 1;
|
||||
UCHAR EODdefined : 3;
|
||||
UCHAR BufferSize[3];
|
||||
UCHAR DCAlgorithm;
|
||||
UCHAR Reserved4;
|
||||
|
||||
} MODE_DEVICE_CONFIGURATION_PAGE, *PMODE_DEVICE_CONFIGURATION_PAGE;
|
||||
|
||||
//
|
||||
// Define Medium Partition Page
|
||||
//
|
||||
|
||||
typedef struct _MODE_MEDIUM_PARTITION_PAGE {
|
||||
|
||||
UCHAR PageCode : 6;
|
||||
UCHAR Reserved1 : 1;
|
||||
UCHAR PSBit : 1;
|
||||
UCHAR PageLength;
|
||||
UCHAR MaximumAdditionalPartitions;
|
||||
UCHAR AdditionalPartitionDefined;
|
||||
UCHAR Reserved2 : 3;
|
||||
UCHAR PSUMBit : 2;
|
||||
UCHAR IDPBit : 1;
|
||||
UCHAR SDPBit : 1;
|
||||
UCHAR FDPBit : 1;
|
||||
UCHAR MediumFormatRecognition;
|
||||
UCHAR Reserved3[2];
|
||||
UCHAR Partition0Size[2];
|
||||
UCHAR Partition1Size[2];
|
||||
|
||||
} MODE_MEDIUM_PARTITION_PAGE, *PMODE_MEDIUM_PARTITION_PAGE;
|
||||
|
||||
//
|
||||
// Define Data Compression Page
|
||||
//
|
||||
|
||||
typedef struct _MODE_DATA_COMPRESSION_PAGE {
|
||||
|
||||
UCHAR PageCode : 6;
|
||||
UCHAR Reserved1 : 2;
|
||||
UCHAR PageLength;
|
||||
UCHAR Reserved2 : 6;
|
||||
UCHAR DCC : 1;
|
||||
UCHAR DCE : 1;
|
||||
UCHAR Reserved3 : 5;
|
||||
UCHAR RED : 2;
|
||||
UCHAR DDE : 1;
|
||||
UCHAR CompressionAlgorithm[4];
|
||||
UCHAR DecompressionAlgorithm[4];
|
||||
UCHAR Reserved4[4];
|
||||
|
||||
} MODE_DATA_COMPRESSION_PAGE, *PMODE_DATA_COMPRESSION_PAGE;
|
||||
|
||||
//
|
||||
// Mode parameter list header and medium partition page -
|
||||
// used in creating partitions
|
||||
//
|
||||
|
||||
typedef struct _MODE_MEDIUM_PART_PAGE {
|
||||
|
||||
MODE_PARAMETER_HEADER ParameterListHeader;
|
||||
MODE_MEDIUM_PARTITION_PAGE MediumPartPage;
|
||||
|
||||
} MODE_MEDIUM_PART_PAGE, *PMODE_MEDIUM_PART_PAGE;
|
||||
|
||||
|
||||
//
|
||||
// Mode parameters for retrieving tape or media information
|
||||
//
|
||||
|
||||
typedef struct _MODE_TAPE_MEDIA_INFORMATION {
|
||||
|
||||
MODE_PARAMETER_HEADER ParameterListHeader;
|
||||
MODE_PARAMETER_BLOCK ParameterListBlock;
|
||||
MODE_MEDIUM_PARTITION_PAGE MediumPartPage;
|
||||
|
||||
} MODE_TAPE_MEDIA_INFORMATION, *PMODE_TAPE_MEDIA_INFORMATION;
|
||||
|
||||
//
|
||||
// Mode parameter list header and device configuration page -
|
||||
// used in retrieving device configuration information
|
||||
//
|
||||
|
||||
typedef struct _MODE_DEVICE_CONFIG_PAGE {
|
||||
|
||||
MODE_PARAMETER_HEADER ParameterListHeader;
|
||||
MODE_DEVICE_CONFIGURATION_PAGE DeviceConfigPage;
|
||||
|
||||
} MODE_DEVICE_CONFIG_PAGE, *PMODE_DEVICE_CONFIG_PAGE;
|
||||
|
||||
|
||||
//
|
||||
// Mode parameter list header and data compression page -
|
||||
// used in retrieving data compression information
|
||||
//
|
||||
|
||||
typedef struct _MODE_DATA_COMPRESS_PAGE {
|
||||
|
||||
MODE_PARAMETER_HEADER ParameterListHeader;
|
||||
MODE_DATA_COMPRESSION_PAGE DataCompressPage;
|
||||
|
||||
} MODE_DATA_COMPRESS_PAGE, *PMODE_DATA_COMPRESS_PAGE;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The following routines are the exported entry points for
|
||||
// all tape class drivers. Note all these routines name start
|
||||
// with 'ScsiTape.'
|
||||
//
|
||||
|
||||
NTSTATUS
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiTapeInitialize(
|
||||
IN PDRIVER_OBJECT DriverObject
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiTapeCreate (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiTapeReadWrite (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
ScsiTapeDeviceControl(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The following routines are provided by the tape
|
||||
// device-specific module. Each routine name is
|
||||
// prefixed with 'Tape.'
|
||||
|
||||
NTSTATUS
|
||||
TapeCreatePartition(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeErase(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
VOID
|
||||
TapeError(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PSCSI_REQUEST_BLOCK Srb,
|
||||
NTSTATUS *Status,
|
||||
BOOLEAN *Retry
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeGetDriveParameters(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeGetMediaParameters(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeGetPosition(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeGetStatus(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapePrepare(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeReadWrite(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeSetDriveParameters(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeSetMediaParameters(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeSetPosition(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
TapeVerifyInquiry(
|
||||
IN PSCSI_INQUIRY_DATA LunInfo
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
TapeWriteMarks(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp
|
||||
);
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue