스토리지 클래스 드라이버의 SplitTransferRequest 루틴
GetDescriptor 루틴으로 반환된 STORAGE_ADAPTER_DESCRIPTOR 데이터는 지정된 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을 호출하고 원래 IRP를 사용하여 SplitTransferRequest 루틴을 호출한 직후 STATUS_PENDING 반환합니다.
원래 전송 요청을 수행하기 위해 드라이버의 SplitTransferRequest 루틴은 HBA의 기능에 맞게 크기가 조정된 서브퍼를 처리하기 위해 하나 이상의 IRP를 만듭니다. 이러한 각 IRP에 대해 SplitTransferRequest 루틴은 다음과 같습니다.
일반적으로 내부 BuildRequest 루틴을 호출하여 SRB를 설정합니다( 스토리지 클래스 드라이버의 BuildRequest 루틴 참조).
원래 IRP에서 새 IRP로 MDL 주소를 복사합니다.
전송의 이 부분에 대해 SRB의 DataBuffer 를 MDL에 대한 오프셋(바이트)로 설정합니다.
IoCallDriver를 사용하여 포트 드라이버에 IRP를 보내기 전에 IoCompletion 루틴을 설정합니다.
전송의 각 부분을 추적하기 위해 SplitTransferRequest 는 드라이버가 할당한 각 IRP에 대해 다음 하위 드라이버로 보내는 IoCompletion 루틴을 등록합니다. IoCompletion 루틴은 InterlockedIncrement 및 InterlockedDecrement를 사용하여 원래 IRP에서 완료된 부분 전송 요청 수를 유지 관리하여 개수가 정확한지 확인합니다.
이러한 IoCompletion 루틴은 드라이버가 할당한 모든 IRP 및/또는 SRB를 해제해야 하며, 요청된 모든 데이터가 전송되었거나 클래스 드라이버가 IRP의 재시도를 모두 소진하고 디바이스 전송 오류로 인해 실패해야 하는 경우 원래 IRP를 완료해야 합니다.