다음을 통해 공유


스토리지 클래스 드라이버의 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 루틴은 InterlockedIncrementInterlockedDecrement를 사용하여 원래 IRP에서 완료된 부분 전송 요청 수를 유지 관리하여 개수가 정확한지 확인합니다.

이러한 IoCompletion 루틴은 드라이버가 할당한 모든 IRP 및/또는 SRB를 해제해야 하며, 요청된 모든 데이터가 전송되었거나 클래스 드라이버가 IRP의 재시도를 모두 소진하고 디바이스 전송 오류로 인해 실패해야 하는 경우 원래 IRP를 완료해야 합니다.