SCSI FC 傳輸

日期:2008 年 11 月 18 日

功能相關的核心修訂

rports : <<TBS>>
vports : 2.6.22
bsg support : 2.6.30 (?TBD?)

引言

本檔案記錄了 SCSI FC 傳輸的功能和元件。它還提供了傳輸與 FC LLDD 之間的 API 文件。

FC 傳輸可在以下位置找到:

drivers/scsi/scsi_transport_fc.c
include/scsi/scsi_transport_fc.h
include/scsi/scsi_netlink_fc.h
include/scsi/scsi_bsg_fc.h

此檔案位於 SCSI FC 傳輸

FC 遠端埠 (rports)

<< 待補充 >>

FC 虛擬埠 (vports)

概述

新的 FC 標準定義了允許單個物理埠顯示為多個通訊埠的機制。使用 N_Port ID 虛擬化 (NPIV) 機制,可以為到 Fabric 的點對點連線分配多個 N_Port_ID。每個 N_Port_ID 在 Fabric 上顯示為獨立的埠,儘管它共享一個物理鏈路與交換機進行通訊。每個 N_Port_ID 可以根據 Fabric 分割槽和陣列 LUN 掩碼擁有獨特的 Fabric 檢視(就像一個普通的非 NPIV 介面卡一樣)。使用虛擬 Fabric (VF) 機制,為每個幀新增 Fabric 頭部允許埠與 Fabric 埠互動以加入多個 Fabric。埠將在其加入的每個 Fabric 上獲取一個 N_Port_ID。每個 Fabric 將擁有其自身獨特的端點和配置引數檢視。NPIV 可以與 VF 一起使用,以便埠可以在每個虛擬 Fabric 上獲取多個 N_Port_ID。

FC 傳輸現在識別一個新的物件——vport(虛擬埠)。vport 是一個具有全球唯一埠名稱 (WWPN) 和全球節點名稱 (WWNN) 的實體。傳輸還允許為 vport 指定 FC4 角色,其中 FCP_Initiator 是預期的主要角色。一旦透過上述方法之一例項化,它將擁有一個獨特的 N_Port_ID 和 Fabric 端點及儲存實體的檢視。與物理介面卡關聯的 fc_host 將匯出建立 vports 的能力。傳輸將在 Linux 裝置樹中建立 vport 物件,並指示 fc_host 的驅動程式例項化虛擬埠。通常,驅動程式將在 vport 上建立一個新的 scsi_host 例項,從而為 vport 形成一個唯一的 <H,C,T,L> 名稱空間。因此,無論 FC 埠是基於物理埠還是基於虛擬埠,每個都將作為唯一的 scsi_host 出現,擁有自己的目標和 LUN 空間。

注意

目前,傳輸層僅支援建立基於 NPIV 的 vport。然而,我們已考慮了基於 VF 的 vport,如果需要,新增支援應僅需少量修改。接下來的討論將集中在 NPIV 上。

注意

全球名稱的分配(和唯一性保證)由控制 vport 的管理實體負責。例如,如果 vports 要與虛擬機器關聯,XEN 管理工具將負責為 vport 建立 WWPN/WWNN,使用其自身的命名許可權和 OUI。(注意:它已經為虛擬 MAC 地址做了這些。)

裝置樹和 Vport 物件:

如今,裝置樹通常包含 scsi_host 物件,其下方有 rport 和 SCSI 目標物件。目前,FC 傳輸層會建立 vport 物件並將其放置在與物理介面卡對應的 scsi_host 物件之下。LLDD 將為 vport 分配一個新的 scsi_host,並將其物件連結到 vport 之下。vport 的 scsi_host 之下樹的其餘部分與非 NPIV 情況相同。當前編寫的傳輸層易於允許 vport 的父級是 scsi_host 以外的其他物件。這在未來可用於將物件連結到虛擬機器特定的裝置樹。如果 vport 的父級不是物理埠的 scsi_host,則指向 vport 物件的符號連結將放置在物理埠的 scsi_host 中。

以下是裝置樹中預期的結構:

典型的物理埠 Scsi_Host

/sys/devices/.../host17/

並且它具有典型的子樹結構

/sys/devices/.../host17/rport-17:0-0/target17:0:0/17:0:0:0:

然後 vport 在物理埠上建立

/sys/devices/.../host17/vport-17:0-0

然後 vport 的 Scsi_Host 被建立

/sys/devices/.../host17/vport-17:0-0/host18

然後樹的其餘部分繼續,例如

/sys/devices/.../host17/vport-17:0-0/host18/rport-18:0-0/target18:0:0/18:0:0:0:

以下是 sysfs 樹中預期的結構

scsi_hosts:
  /sys/class/scsi_host/host17                physical port's scsi_host
  /sys/class/scsi_host/host18                vport's scsi_host
fc_hosts:
  /sys/class/fc_host/host17                  physical port's fc_host
  /sys/class/fc_host/host18                  vport's fc_host
fc_vports:
  /sys/class/fc_vports/vport-17:0-0          the vport's fc_vport
fc_rports:
  /sys/class/fc_remote_ports/rport-17:0-0    rport on the physical port
  /sys/class/fc_remote_ports/rport-18:0-0    rport on the vport

Vport 屬性

新的 fc_vport 類物件具有以下屬性:

node_name: 只讀

vport 的 WWNN

port_name: 只讀

vport 的 WWPN

roles: 只讀

指示 vport 上啟用的 FC4 角色。

symbolic_name: 讀寫

一個字串,附加到驅動程式的符號埠名稱字串後,並在交換機上註冊以識別 vport。例如,一個管理程式可以將此字串設定為“Xen Domain 2 VM 5 Vport 2”,並且這組識別符號可以在交換機管理螢幕上看到,用於識別該埠。

vport_delete: 只寫

當寫入“1”時,將銷燬 vport。

vport_disable: 只寫

當寫入“1”時,將把 vport 轉換到停用狀態。vport 仍將在 Linux 核心中例項化,但不會在 FC 鏈路上處於活動狀態。當寫入“0”時,將啟用 vport。

vport_last_state: 只讀

指示 vport 的前一狀態。請參閱下面關於“Vport 狀態”的部分。

vport_state: 只讀

指示 vport 的當前狀態。請參閱下面關於“Vport 狀態”的部分。

vport_type: 只讀

反映用於建立虛擬埠的 FC 機制。目前僅支援 NPIV。

對於 fc_host 類物件,為 vports 添加了以下屬性:

max_npiv_vports: 只讀

指示驅動程式/介面卡在 fc_host 上支援的最大 NPIV vport 數量。

npiv_vports_inuse: 只讀

指示在 fc_host 上已例項化的 NPIV vport 數量。

vport_create: 只寫

一個“簡單”的建立介面,用於在 fc_host 上例項化一個 vport。將一個“<WWPN>:<WWNN>”字串寫入屬性。傳輸層隨後例項化 vport 物件並呼叫 LLDD 以 FCP_Initiator 角色建立 vport。每個 WWN 都指定為 16 個十六進位制字元,並且 *不能* 包含任何字首(例如 0x, x 等)。

vport_delete: 只寫

一個“簡單”的刪除介面,用於銷燬 vport。將一個“<WWPN>:<WWNN>”字串寫入屬性。傳輸層將定位 fc_host 上具有相同 WWN 的 vport 並將其銷燬。每個 WWN 都指定為 16 個十六進位制字元,並且 *不能* 包含任何字首(例如 0x, x 等)。

Vport 狀態

Vport 例項化包括兩部分:

  • 在核心和 LLDD 中建立。這意味著所有傳輸和驅動程式資料結構都已構建,並且裝置物件已建立。這等同於驅動程式在介面卡上的“附加”,這與介面卡的鏈路狀態無關。

  • 透過 ELS 流量等方式在 FC 鏈路上例項化 vport。這等同於“鏈路啟用”和成功的鏈路初始化。

有關 Vport 建立的更多資訊,請參閱下面的介面部分。

一旦 vport 在核心/LLDD 中例項化,其狀態可以透過 sysfs 屬性報告。存在以下狀態:

FC_VPORT_UNKNOWN - 未知

一個臨時狀態,通常只在 vport 正在核心和 LLDD 中例項化時設定。

FC_VPORT_ACTIVE - 活動

vport 已在 FC 鏈路上成功建立。它功能齊全。

FC_VPORT_DISABLED - 停用

vport 已例項化,但處於“停用”狀態。vport 未在 FC 鏈路上例項化。這等同於物理埠的鏈路“已斷開”。

FC_VPORT_LINKDOWN - 鏈路斷開

vport 無法執行,因為物理鏈路未執行。

FC_VPORT_INITIALIZING - 初始化中

vport 正在 FC 鏈路上例項化。LLDD 將在開始 ELS 流量以建立 vport 之前設定此狀態。此狀態將持續到 vport 成功建立(狀態變為 FC_VPORT_ACTIVE)或失敗(狀態為以下值之一)。由於此狀態是暫時的,它不會保留在“vport_last_state”中。

FC_VPORT_NO_FABRIC_SUPP - 無 Fabric 支援

vport 無法執行。遇到以下條件之一:

  • FC 拓撲不是點對點

  • FC 埠未連線到 F_Port

  • F_Port 已指示不支援 NPIV。

FC_VPORT_NO_FABRIC_RSCS - 無 Fabric 資源

vport 無法執行。Fabric 的 FDISC 操作失敗,狀態指示其沒有足夠的資源完成該操作。

FC_VPORT_FABRIC_LOGOUT - Fabric 登出

vport 無法執行。Fabric 已登出與 vport 關聯的 N_Port_ID。

FC_VPORT_FABRIC_REJ_WWN - Fabric 拒絕 WWN

vport 無法執行。Fabric 的 FDISC 操作失敗,狀態指示 WWN 無效。

FC_VPORT_FAILED - VPort 失敗

vport 無法執行。這是所有其他錯誤條件的通用捕獲。

下表顯示了不同的狀態轉換:

狀態

事件

新狀態

不適用

初始化

未知

未知

鏈路斷開

鏈路斷開

鏈路啟用 & 環路

無 Fabric 支援

鏈路啟用 & 無 Fabric

無 Fabric 支援

鏈路啟用 & FLOGI 響應指示不支援 NPIV

無 Fabric 支援

鏈路啟用 & 正在傳送 FDISC

初始化中

停用請求

停用

鏈路斷開

鏈路啟用

未知

初始化中

FDISC ACC

活動

FDISC LS_RJT(無資源)

無 Fabric 資源

FDISC LS_RJT(pname 或 nport_id 無效)

Fabric 拒絕 WWN

FDISC LS_RJT 因其他原因失敗

Vport 失敗

鏈路斷開

鏈路斷開

停用請求

停用

停用

啟用請求

未知

活動

從 Fabric 收到 LOGO

Fabric 登出

鏈路斷開

鏈路斷開

停用請求

停用

Fabric 登出

鏈路仍啟用

未知

以下 4 種錯誤狀態都具有相同的轉換:

No Fabric Support:
No Fabric Resources:
Fabric Rejected WWN:
Vport Failed:
                    Disable request                 Disable
                    Link goes down                  Linkdown

傳輸 <-> LLDD 介面

LLDD 對 Vport 的支援

LLDD 透過在傳輸模板中提供 `vport_create()` 函式來表明對 vport 的支援。此函式的存在將導致在 fc_host 上建立新的屬性。作為物理埠相對於傳輸層完成初始化的一部分,它應該設定 `max_npiv_vports` 屬性,以指示驅動程式和/或介面卡支援的最大 vport 數量。

Vport 建立

LLDD `vport_create()` 語法為:

int vport_create(struct fc_vport *vport, bool disable)

其中

vport

是新分配的 vport 物件

disable

如果為“true”,vport 將在停用狀態下建立。如果為“false”,vport 將在建立時啟用。

當請求建立新的 vport 時(透過 sgio/netlink,或 vport_create fc_host 屬性),傳輸層將驗證 LLDD 是否可以支援另一個 vport(例如 `max_npiv_vports` > `npiv_vports_inuse`)。如果不支援,建立請求將失敗。如果仍有空間,傳輸層將增加 vport 計數,建立 vport 物件,然後呼叫 LLDD 的 `vport_create()` 函式,傳入新分配的 vport 物件。

如上所述,vport 建立分為兩部分:

  • 在核心和 LLDD 中建立。這意味著所有傳輸和驅動程式資料結構都已構建,並且裝置物件已建立。這等同於驅動程式在介面卡上的“附加”,這與介面卡的鏈路狀態無關。

  • 透過 ELS 流量等方式在 FC 鏈路上例項化 vport。這等同於“鏈路啟用”和成功的鏈路初始化。

LLDD 的 `vport_create()` 函式不會在返回之前同步等待兩部分完全完成。它必須驗證支援 NPIV 的基礎設施是否存在,並在返回之前完成 vport 建立的第一部分(資料結構構建)。我們不將 `vport_create()` 依賴於鏈路側操作,主要是因為:

  • 鏈路可能已斷開。如果鏈路斷開,這不是故障。它僅表示 vport 處於不可操作狀態,直到鏈路啟用。這與 vport 建立後鏈路跳動的情況一致。

  • vport 可以在停用狀態下建立。

  • 這與以下模型一致:vport 等同於一個 FC 介面卡。`vport_create` 與驅動程式附加到介面卡同義,而這與鏈路狀態無關。

注意

已定義了特殊的錯誤程式碼,以區分基礎設施故障情況,從而加快解決速度。

LLDD `vport_create()` 函式的預期行為是:

  • 驗證基礎設施

    • 如果驅動程式或介面卡不能支援另一個 vport,無論是因為

      韌體不正確、(虛報)`max_npiv`,或缺少其他資源——則返回 `VPCERR_UNSUPPORTED`。

    • 如果驅動程式針對已在介面卡上活動的 WWN 驗證新 WWN,並檢測到重疊——則返回 `VPCERR_BAD_WWN`。

      介面卡並檢測到重疊 - 返回 VPCERR_BAD_WWN。

    • 如果驅動程式檢測到拓撲是環路、非 Fabric,或者

      FLOGI 不支援 NPIV——則返回 `VPCERR_NO_FABRIC_SUPP`。

  • 分配資料結構。如果遇到錯誤,例如記憶體不足,則返回相應的負數 `Exxx` 錯誤程式碼。

    記憶體狀況,返回相應的負 Exxx 錯誤程式碼。

  • 如果角色是 FCP Initiator,LLDD 應:

    • 呼叫 scsi_host_alloc() 為 vport 分配一個 `scsi_host`。

    • 呼叫 `scsi_add_host(new_shost, &vport->dev)` 以啟動 `scsi_host` 並將其繫結為 vport 裝置的子級。

    • 初始化 `fc_host` 屬性值。

  • 根據停用標誌和鏈路狀態啟動進一步的 vport 狀態轉換——並返回成功(零)。

    鏈路狀態 - 並返回成功(零)。

LLDD 實現者注意事項

  • 建議物理埠和虛擬埠使用不同的 `fc_function_templates`。物理埠的模板將包含 `vport_create`、`vport_delete` 和 `vport_disable` 函式,而 vport 則不包含。

  • 建議物理埠和虛擬埠使用不同的 `scsi_host_templates`。很可能有些驅動程式屬性(如鏈路速度、拓撲設定等)嵌入在 `scsi_host_template` 中,僅適用於物理埠。這確保了屬性適用於各自的 `scsi_host`。

Vport 停用/啟用

LLDD `vport_disable()` 語法為:

int vport_disable(struct fc_vport *vport, bool disable)

其中

vport

vport 是啟用還是停用

disable

如果為“true”,vport 將被停用。如果為“false”,vport 將被啟用。

當請求更改 vport 的停用狀態時,傳輸層將根據現有 vport 狀態驗證該請求。如果請求是停用,且 vport 已被停用,則請求將失敗。類似地,如果請求是啟用,而 vport 不處於停用狀態,則請求也將失敗。如果請求對於 vport 狀態有效,傳輸層將呼叫 LLDD 更改 vport 的狀態。

在 LLDD 內部,如果 vport 被停用,它仍將在核心和 LLDD 中例項化,但不會以任何方式在 FC 鏈路上活動或可見。(參見 Vport 建立和兩部分例項化討論)。vport 將保持此狀態,直到被刪除或重新啟用。啟用 vport 時,LLDD 將在 FC 鏈路上重新例項化 vport——本質上是重啟 LLDD 狀態機(參見上面的 Vport 狀態)。

Vport 刪除

LLDD `vport_delete()` 語法為:

int vport_delete(struct fc_vport *vport)

其中

vport: 要刪除的 vport

當請求刪除 vport 時(透過 sgio/netlink,或透過 `fc_host` 或 `fc_vport` 的 `vport_delete` 屬性),傳輸層將呼叫 LLDD 以終止 FC 鏈路上的 vport,並銷燬所有其他資料結構和引用。如果 LLDD 成功完成,傳輸層將銷燬 vport 物件並完成 vport 刪除。如果 LLDD 刪除請求失敗,vport 物件將保留,但會處於不確定狀態。

在 LLDD 內部,應遵循 `scsi_host` 拆卸的常規程式碼路徑。例如,如果 vport 具有 FCP Initiator 角色,LLDD 將為 vport 的 `scsi_host` 呼叫 fc_remove_host(),然後呼叫 scsi_remove_host()scsi_host_put()

其他
fc_host 的 `port_type` 屬性

新增了一個 `fc_host` `port_type` 值 - `FC_PORTTYPE_NPIV`。此值必須設定在所有基於 vport 的 `fc_host` 上。通常,在物理埠上,`port_type` 屬性會根據拓撲型別和 Fabric 的存在設定為 NPORT、NLPORT 等。由於這不適用於 vport,因此報告用於建立 vport 的 FC 機制更有意義。

驅動程式解除安裝

FC 驅動程式必須在呼叫 scsi_remove_host() 之前呼叫 fc_remove_host()。這允許 `fc_host` 在 `scsi_host` 拆卸之前拆卸所有遠端埠。`fc_remove_host()` 呼叫已更新,以同時刪除 `fc_host` 的所有 vport。

傳輸層提供的函式

以下函式由 FC 傳輸層提供給 LLD 使用。

`fc_vport_create`

建立 vport

`fc_vport_terminate`

分離並移除 vport

詳情

/**
* fc_vport_create - Admin App or LLDD requests creation of a vport
* @shost:     scsi host the virtual port is connected to.
* @ids:       The world wide names, FC4 port roles, etc for
*              the virtual port.
*
* Notes:
*     This routine assumes no locks are held on entry.
*/
struct fc_vport *
fc_vport_create(struct Scsi_Host *shost, struct fc_vport_identifiers *ids)

/**
* fc_vport_terminate - Admin App or LLDD requests termination of a vport
* @vport:      fc_vport to be terminated
*
* Calls the LLDD vport_delete() function, then deallocates and removes
* the vport from the shost and object tree.
*
* Notes:
*      This routine assumes no locks are held on entry.
*/
int
fc_vport_terminate(struct fc_vport *vport)

FC BSG 支援 (CT & ELS 透傳等)

<< 待補充 >>

致謝

以下人員對本文件做出了貢獻:

James Smart james.smart@broadcom.com