3.3.3 Splitting Transfer Requests
Any NT driver might need to split up a transfer request and carry out more than one DMA transfer operation to satisfy a given IRP, depending on the following:
·The NumberOfMapRegisters returned by HalGetAdapter on a given platform
·The value of Length (bytes of data to be transferred) in the driver’s I/O stack location in the current IRP
·The number of page boundaries in system physical memory for the buffer into which or from which the driver is to transfer data
·Any device-specific constraints on the driver’s DMA operations
NT drivers can use the macro ADDRESS_AND_SIZE_TO_SPAN_PAGES to determine how many map registers are needed to transfer all the data requested in a given IRP, as follows:
1.Call MmGetMdlVirtualAddress, passing a pointer to the MDL at Irp->MdlAddress, to get the starting virtual address for the buffer. Note that a driver must not attempt to access memory using this virtual address. The value returned by MmGetMdlVirtualAddress is an index into the MDL, not necessarily a valid address.
2.Pass the returned index and the value of Length in the driver’s I/O stack location of the IRP to ADDRESS_AND_SIZE_TO_SPAN_PAGES.
If the value returned by ADDRESS_AND_SIZE_TO_SPAN_PAGES is greater than the NumberOfMapRegisters returned by HalGetAdapter, the driver cannot transfer all requested data for this IRP in a single DMA operation. Instead, it must do the following:
·Split the buffer into pieces that are sized to suit the number of available map registers and any device-specific DMA constraints.
·Carry out as many DMA operations as it takes to satisfy the current transfer request.
For example, suppose ADDRESS_AND_SIZE_TO_SPAN_PAGES indicates that twelve map registers are needed to satisfy a given transfer request but a driver has only five available map registers on this platform and no device-specific DMA constraints. Such a driver must carry out three (12/5 + 1 = 3) DMA transfer operations (and call IoMapTransfer at least three times) in order to transfer all the data requested by this IRP.
The system DMA device drivers use various techniques to split up a DMA transfer when there are not enough map registers to satisfy a given IRP with a single DMA transfer operation. For example, the SCSI class drivers are required to split up large transfer requests for the underlying NT SCSI port/miniport drivers. A system SCSI class driver allocates an additional IRP for each piece of a given transfer request, registers its IoCompletion routine with each IRP to track the status of the full transfer request and to free the driver-allocated IRP(s), and sends the IRP(s) on to the port driver with IoCallDriver, as explained in Chapter 2.
However, other class/port drivers can use this technique only if the class driver can determine how many map registers are available to the port driver on each Windows NT platform. In other words, the port driver must store this configuration information in the registry for the paired class driver, or such a pair of drivers must define a private interface, using internal device I/O control requests, to pass configuration information about the number of available map registers from the port driver to the class driver.
Other class/port drivers need not use this technique, and a monolithic DMA device driver must split up large transfer requests for itself. Such drivers usually split a large request into pieces and carry out a sequence of DMA operations in order to satisfy the current IRP.
The following sections, which describe how monolithic drivers of DMA devices use support routines to satisfy transfer requests, assumes the following:
·The driver has a standard StartIo routine, rather than setting up and managing an internal queue of IRPs.
·The driver has an internal routine to split those transfer requests for which an insufficient number of map registers is available and has no device-specific DMA constraints.
In other words, these sections describe the simplest possible technique for NT device drivers’ DMA operations, but individual NT drivers do not necessarily use exactly the same techniques. For any NT driver of a DMA device, the driver writer determines which driver routine(s) should split up large DMA transfer requests, depending on the driver model (class/port, monolithic, etc.), on the device’s features, and on any device-specific DMA constraints that driver must handle.