Подпрограмма SplitTransferRequest драйвера класса хранилища
Данные STORAGE_ADAPTER_DESCRIPTOR, возвращаемые в подпрограмму GetDescriptor , указывают на возможности передачи данного адаптера HBA в драйвер класса. В частности, эти данные указывают MaximumTransferLength в байтах и MaximumPhysicalPages, т. е. количество несмежных страниц, которыми может управлять HBA в физической памяти, поддерживающей системный буфер (т. е. степень его поддержки точечной и сборной).
Большинство драйверов классов хранят указатель на эти данные конфигурации в расширении каждого объекта устройства, так как драйверы класса хранения отвечают за разделение всех запросов на передачу, которые превышают возможности HBA для передачи данных. Другими словами, подпрограмма DispatchReadWrite драйвера класса должна определять, запрашивает ли каждый IRP передачу, которая больше, чем может обработать HBA в одной операции передачи.
Например, такая подпрограмма DispatchReadWrite может иметь код, аналогичный следующему:
PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor =
commonExtension->PartitionZeroExtension->AdapterDescriptor;
ULONG transferPages;
ULONG maximumTransferLength =
adapterDescriptor->MaximumTransferLength;
: :
//
// Calculate number of pages in this transfer
//
transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
MmGetMdlVirtualAddress(Irp->MdlAddress),
currentIrpStack->Parameters.Read.Length);
//
// Check whether requested length is greater than the maximum number
// of bytes that can be transferred in a single operation
//
if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
transferPages > adapterDescriptor->MaximumPhysicalPages) {
transferPages = adapterDescriptor->MaximumPhysicalPages - 1;
if (maximumTransferLength > transferPages << PAGE_SHIFT) {
maximumTransferLength = transferPages << PAGE_SHIFT;
}
IoMarkIrpPending(Irp);
SplitTransferRequest(DeviceObject,
Irp,
maximumTransferLength);
return STATUS_PENDING;
}
: :
Драйвер класса не может определить, сколько физических разрывов будет иметь буфер после сопоставления, поэтому он должен предполагать, что каждая страница в передаче является нечетким, и сравнить количество страниц с числом разрешенных физических разрывов.
Обратите внимание, что подпрограмма DispatchReadWrite такого драйвера вызывает IoMarkIrpPending и возвращает STATUS_PENDING сразу после вызова подпрограммы SplitTransferRequest с исходным IRP.
Чтобы выполнить исходный запрос на передачу, подпрограмма SplitTransferRequest драйвера создает один или несколько irP для обработки вложенных отсутсвий, размер которых соответствует возможностям HBA. Для каждого такого IRP подпрограмма SplitTransferRequest :
Настраивает SRB, как правило, путем вызова внутренней подпрограммы BuildRequest (см. раздел Подпрограмма BuildRequest драйвера класса хранилища).
Копирует MDL-адрес из исходного IRP в новый IRP.
Задает для DataBuffer в SRB смещение в байтах в MDL для этого фрагмента передачи.
Настройка процедуры IoCompletion перед отправкой IRP в драйвер порта с помощью IoCallDriver
Чтобы отслеживать каждую часть передачи, SplitTransferRequest регистрирует подпрограмму IoCompletion для каждого выделенного драйвера IRP, отправляемого следующему ниже драйверу. Подпрограмма IoCompletion поддерживает количество завершенных частичных запросов на передачу в исходном IRP, используя InterlockedIncrement и InterlockedDecrement для обеспечения точности счетчика.
Такая подпрограмма IoCompletion должна освободить все выделенные драйвером irP и (или) SRB и завершить исходный IRP, когда все запрошенные данные были переданы или когда драйвер класса исчерпал повторные попытки IRP и должен завершить их из-за ошибок передачи устройства.