typedef struct _IO_STACK_LOCATION { UCHAR MajorFunction; UCHAR MinorFunction; UCHAR Flags; UCHAR Control; // // The following Parameters depend on the IRP_MJ_XXX that is set // in MajorFunction. This declaration shows examples for IRP_MJ_READ, // IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL or, possibly, // IRP_MJ_INTERNAL_DEVICE_CONTROL requests, as well as for IRP_MJ_SCSI, // which is equivalent to IRP_MJ_INTERNAL_DEVICE_CONTROL. // union { . . struct { ULONG Length; ULONG Key; LARGE_INTEGER ByteOffset; } Read; struct { ULONG Length; ULONG Key; LARGE_INTEGER ByteOffset; } Write; . . struct { ULONG OutputBufferLength; ULONG InputBufferLength; ULONG IoControlCode; // IOCTL_XXX PVOID Type3InputBuffer; } DeviceIoControl; . . struct { struct _SCSI_REQUEST_BLOCK *Srb; } Scsi; . . } Parameters; PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject; . . } IO_STACK_LOCATION, *PIO_STACK_LOCATION;
Each I/O stack location in a given IRP has some common members and some request-type-specific members. The following summarizes the general structure of every stack location.
Every higher-level driver is responsible for setting up the I/O stack location for the next-lower driver in each IRP.
In some cases, a higher-level driver layered over a mass-storage device driver is responsible for splitting up large transfer requests for the underlying device driver. In particular, SCSI class drivers must check the Parameters.Read.Length and Parameters.Write.Length, determine whether the size of the requested transfer exceeds the underlying HBA’s transfer capabilities, and, if so, split the Length of the original request into a sequence of partial transfers to satisfy the original IRP.
A higher-level driver’s call to IoCallDriver sets up the DeviceObject pointer to the next-lower-level driver’s target device object in the I/O stack location of the lower driver. The I/O Manager passes each higher-level driver’s IoCompletion routine a pointer to its own DeviceObject when or if the IoCompletion routine is called on completion of the IRP.
If a higher-level driver allocates IRPs to make requests of its own, its IoCompletion routine is passed a NULL DeviceObject pointer if that driver neither allocates a stack location for itself nor sets up the DeviceObject pointer in its own stack location of the newly allocated IRP.
IoCallDriver, IoGetCurrentIrpStackLocation, IoGetNextIrpStackLocation, IoSetCompletionRoutine, IoSetNextIrpStackLocation, IO_STATUS_BLOCK, IRP