[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:
Sir Richard 2010-10-16 15:24:08 +00:00
parent 8047296236
commit 73c1c7f232
40 changed files with 37419 additions and 0 deletions

File diff suppressed because it is too large Load diff

View 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__

View 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"

View 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>

View 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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"

View 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;
}

View file

@ -0,0 +1,11 @@
/*--
Copyright (C) Microsoft Corporation, 1999
--*/
#include "ntddk.h"
#include "classpnp.h"
#include "cdrom.h"

View 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,...))

View 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 */ \
)

View file

@ -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>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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

View 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"

View 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);

View 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>

View 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()

View 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;
}

View 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);
}

View 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

View 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

View 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

View 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;
}

View 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()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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;
}

View 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

View 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

View 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

View file

@ -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>

View 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_ */

View 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___

View 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___

View 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

View 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

View 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
);