分割 DMA 傳輸要求

任何驅動程式可能需要分割傳輸要求,並執行一個以上的 DMA 傳輸作業來滿足指定的 IRP,視下列情況而定:

  • IoGetDmaAdapter傳回的對應暫存器數目

  • 要傳輸的資料位元組,包含在 IRP 驅動程式 I/O 堆疊位置的 Length 成員中

  • 系統實體記憶體中的頁面界限數目,用於驅動程式要從中傳輸資料或從其中傳輸資料的緩衝區

  • 驅動程式 DMA 作業的裝置特定條件約束。 例如,系統 「AT」 磁片磁碟機必須分割超過 256 個磁區的傳輸要求,因為磁碟控制卡的限制。

驅動程式可以判斷傳輸 IRP 指定之所有資料所需的地圖暫存器數目,如下所示:

  1. 呼叫 MmGetMdlVirtualAddress,將指標傳遞至 Irp-MdlAddress > 上的 MDL,以取得緩衝區的起始虛擬位址。 請注意,驅動程式不得嘗試使用此虛擬位址來存取記憶體。 MmGetMdlVirtualAddress傳回的值是 MDL 中的索引,不一定是有效的位址。

  2. 將傳回的索引和 IRP 驅動程式 I/O 堆疊位置的 Length 值傳遞至 ADDRESS_AND_SIZE_TO_SPAN_PAGES 宏。

如果ADDRESS_AND_SIZE_TO_SPAN_PAGES傳回的值大於IoGetDmaAdapter所傳回的 NumberOfMapRegisters值,驅動程式就無法在單一 DMA 作業中傳送此 IRP 的所有要求資料。 相反地,它必須執行下列動作:

  1. 將緩衝區分割成大小以符合可用地圖暫存器數目的片段, (和任何裝置特定的 DMA 條件約束) 。

  2. 執行滿足傳輸要求所需的 DMA 作業數目。

例如,假設ADDRESS_AND_SIZE_TO_SPAN_PAGES表示需要 12 個對應暫存器來滿足傳輸要求,但IoGetDmaAdapter傳回的 NumberOfMapRegisters值只有五個。 (假設沒有裝置特定的 DMA 條件約束。) 在此情況下,驅動程式必須執行三個 DMA 傳輸作業,呼叫 MapTransfer 三次以傳輸 IRP 所要求的所有資料。

當沒有足夠的對應暫存器滿足具有單一 I/O 作業的 IRP 時,系統的 DMA 設備磁碟機會使用各種技術來分割 DMA 傳輸。 使用其中一個技巧如下:

  1. 呼叫 IoAllocateMdl 以配置描述使用者緩衝區部分的 MDL。

  2. 呼叫 MmProbeAndLockPages 以鎖定該部分的使用者緩衝區。

  3. 傳輸緩衝區該部分的資料。

  4. 呼叫 MmUnlockPages 並執行下列任一動作:

    • 如果步驟 1 中驅動程式配置的 MDL 足以用於下一個傳輸片段,請呼叫 MmPrepareMdlForReuse ,然後重複步驟 2 到 4。
    • 否則,請呼叫 IoFreeMdl 並重複步驟 1 到 4。
  5. 在傳輸所有資料時,呼叫 MmUnlockPagesIoFreeMdl

如果最高層級驅動程式無法在具有有限記憶體的機器中使用 MmProbeAndLockPages 鎖定整個使用者緩衝區,它可以執行下列動作:

  1. 呼叫 IoBuildSynchronousFsdRequest 以配置部分傳輸 IRP,並鎖定使用者緩衝區的一部分。 鎖定的區域通常是 多個PAGE_SIZE 或調整大小,以符合基礎裝置的傳輸容量。

  2. 針對部分傳輸 IRP 呼叫 IoCallDriver ,並呼叫 KeWaitForSingleObject 以等候驅動程式設定與其部分傳輸 IRP 相關聯的事件物件,如果較低的驅動程式傳回STATUS_PENDING。

  3. 當重新取得控制權時,請重複步驟 1 和 2,直到傳輸所有資料為止,然後完成原始的 IRP。

當儲存體類別驅動程式分割基礎 SCSI 埠/迷你埠驅動程式的大型傳輸要求時,它會為每個傳輸要求的每個部分配置額外的 IRP。 它會為每個驅動程式配置的 IRP 註冊 IoCompletion 常式,以追蹤完整傳輸要求的狀態,以及釋放驅動程式配置的 IRP。 然後,它會使用 IoCallDriver將這些 IRP 傳送至埠驅動程式。

其他類別/埠驅動程式只有在類別驅動程式可以判斷埠驅動程式可以使用多少對應暫存器時,才能使用這項技術。 埠驅動程式必須將此組態資訊儲存在配對類別驅動程式的登錄中,或者配對的驅動程式必須使用內部裝置 I/O 控制要求來定義私人介面,以將埠驅動程式中可用對應暫存器數目的組態資訊傳遞至類別驅動程式。

整合型驅動程式 (,也就是說,DMA 裝置不屬於類別/埠配對) 的驅動程式必須分割本身的大型傳輸要求。 這類驅動程式通常會將大型要求分割成片段,並執行一連串的 DMA 作業,以滿足 IRP。

如果傳輸要求太大,讓基礎設備磁碟機無法處理,較高層級的驅動程式可以呼叫 MmGetMdlVirtualAddressIoBuildPartialMdl,然後為基礎設備磁碟機設定一連串的部分傳輸 IRP。