target 和 iSCSI 接口指南¶
简介和概述¶
待定
Target 核心设备接口¶
此部分为空,因为没有将 kerneldoc 注释添加到 drivers/target/target_core_device.c。
Target 核心传输接口¶
-
void transport_init_session(struct se_session *se_sess)¶
初始化会话对象
参数
struct se_session *se_sess
会话对象指针。
描述
调用方必须在调用此函数之前将 se_sess 初始化为零。
-
struct se_session *transport_alloc_session(enum target_prot_op sup_prot_ops)¶
分配会话对象并初始化它
参数
enum target_prot_op sup_prot_ops
定义支持哪些 T10-PI 模式的位掩码。
-
int transport_alloc_session_tags(struct se_session *se_sess, unsigned int tag_num, unsigned int tag_size)¶
分配目标驱动程序私有数据
参数
struct se_session *se_sess
会话指针。
unsigned int tag_num
发起程序和目标之间正在进行的命令的最大数量。
unsigned int tag_size
目标驱动程序与每个命令关联的私有数据的字节大小。
-
int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags)¶
初始化 se_cmd
参数
struct se_cmd *se_cmd
要初始化的命令描述符
struct se_session *se_sess
端点的关联 se_sess
unsigned char *sense
指向 SCSI 感知缓冲区的指针
u64 unpacked_lun
用于引用 struct se_lun 的解包 LUN
u32 data_length
结构预期的数据传输长度
int task_attr
SAM 任务属性
int data_dir
DMA 数据方向
int flags
来自 target_sc_flags_tables 的命令提交标志
描述
如果调用方已设置 se_cmd->tag,则支持任务标签。
如果结构驱动程序调用 target_stop_session,则必须检查返回代码并处理失败。对于其他驱动程序,这永远不会失败,并且可以忽略返回代码。
返回
小于零以表示活动 I/O 关闭失败。
成功时返回零。
-
int target_submit_prep(struct se_cmd *se_cmd, unsigned char *cdb, struct scatterlist *sgl, u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count, struct scatterlist *sgl_prot, u32 sgl_prot_count, gfp_t gfp)¶
准备要提交的命令
参数
struct se_cmd *se_cmd
要准备的命令描述符
unsigned char *cdb
指向 SCSI CDB 的指针
struct scatterlist *sgl
用于单向映射的 struct scatterlist 内存
u32 sgl_count
单向映射的 scatterlist 计数
struct scatterlist *sgl_bidi
用于双向读取映射的 struct scatterlist 内存
u32 sgl_bidi_count
双向读取映射的 scatterlist 计数
struct scatterlist *sgl_prot
struct scatterlist 内存保护信息
u32 sgl_prot_count
保护信息的 scatterlist 计数
gfp_t gfp
gfp 分配类型
返回
小于零以表示失败。
成功时返回零。
描述
如果返回失败,则 lio 将调用方的 queue_status 完成命令。
-
void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *cdb, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags)¶
查找解包的 LUN 并提交未初始化的 se_cmd
参数
struct se_cmd *se_cmd
要提交的命令描述符
struct se_session *se_sess
端点的关联 se_sess
unsigned char *cdb
指向 SCSI CDB 的指针
unsigned char *sense
指向 SCSI 感知缓冲区的指针
u64 unpacked_lun
用于引用 struct se_lun 的解包 LUN
u32 data_length
结构预期的数据传输长度
int task_attr
SAM 任务属性
int data_dir
DMA 数据方向
int flags
来自 target_sc_flags_tables 的命令提交标志
描述
如果调用方已设置 se_cmd->tag,则支持任务标签。
此函数只能从进程上下文中调用,并且目前假设目标核心内部分配 fabric 有效负载缓冲区。
它还假设内部目标核心 SGL 内存分配。
此函数只能由在关闭期间执行自己的同步且不使用 target_stop_session 的驱动程序使用。如果发生故障,此函数将调用 fabric 驱动程序的 queue_status,并返回 CHECK_CONDITION。
参数
struct se_cmd *se_cmd
要提交的命令描述符
描述
必须在 cmd 上调用过 target_submit_prep 或类似函数,并且必须从进程上下文中调用此函数。
-
int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u64 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t gfp, u64 tag, int flags)¶
查找解包的 LUN 并提交用于 TMR CDB 的未初始化 se_cmd
参数
struct se_cmd *se_cmd
要提交的命令描述符
struct se_session *se_sess
端点的关联 se_sess
unsigned char *sense
指向 SCSI 感知缓冲区的指针
u64 unpacked_lun
用于引用 struct se_lun 的解包 LUN
void *fabric_tmr_ptr
TMR 请求的 fabric 上下文
unsigned char tm_type
TM 请求的类型
gfp_t gfp
调用者的 gfp 类型
u64 tag
TMR_ABORT_TASK 的引用任务标记
int flags
提交 cmd 标志
描述
可从所有上下文中调用。
参数
struct se_cmd *se_cmd
要添加的命令描述符
bool ack_kref
发出 fabric 将执行 ack
target_put_sess_cmd()
的信号
-
void target_stop_cmd_counter(struct target_cmd_counter *cmd_cnt)¶
停止向计数器添加新的 IO。
参数
struct target_cmd_counter *cmd_cnt
要停止的计数器
-
void target_stop_session(struct se_session *se_sess)¶
停止将新的 IO 排队到会话中。
参数
struct se_session *se_sess
要停止的会话
-
void target_wait_for_cmds(struct target_cmd_counter *cmd_cnt)¶
等待未完成的 cmd。
参数
struct target_cmd_counter *cmd_cnt
要等待活动的 I/O 的计数器。
-
void target_wait_for_sess_cmds(struct se_session *se_sess)¶
等待未完成的命令
参数
struct se_session *se_sess
要等待活动 I/O 的会话
-
bool transport_wait_for_tasks(struct se_cmd *cmd)¶
设置 CMD_T_STOP 并等待 t_transport_stop_comp
参数
struct se_cmd *cmd
要等待的命令
-
int target_send_busy(struct se_cmd *cmd)¶
将 SCSI BUSY 状态发送回启动器
参数
struct se_cmd *cmd
要发送 BUSY 回复的 SCSI 命令。
注意
仅当 target_submit_cmd*() 失败时才调用此函数。
目标支持的用户空间 I/O¶
用户空间 I/O¶
定义一个共享内存接口,供 LIO 将 SCSI 命令和数据传递给用户空间进行处理。这是为了允许后端过于复杂而无法实现内核支持。
它使用 UIO 框架为我们完成大量设备创建和内省工作。
有关环的布局方式,请参阅 .h 文件。请注意,虽然定义了命令环,但数据区域的具体细节没有定义。命令条目中的偏移值指向 mmap 区域内部的其他位置。在命令环外部有单独的空间用于数据缓冲区。这为移动缓冲区分配(甚至页面翻转或其他分配技术)提供了最大的灵活性,而不会更改命令环布局。
安全性:必须假定用户进程是恶意的。无法阻止它破坏命令环协议(如果它愿意),但为了防止其他问题,我们必须只从共享内存区域读取数据,而不是偏移量或大小。这适用于命令环条目以及邮箱。此额外代码可能带有“UAM”注释。
环设计¶
mmap 区域分为三个部分:1) 邮箱(下面的 struct tcmu_mailbox);2) 命令环;3) 命令环之外的所有内容(数据)。
邮箱告诉用户空间命令环相对于共享内存区域起点的偏移量以及命令环的大小。
内核通过将 struct tcmu_cmd_entry 放入环中、更新 mailbox->cmd_head,并通过 UIO 的中断机制触发用户空间来将 SCSI 命令传递给用户空间。
tcmu_cmd_entry 包含一个标头。如果标头类型为 PAD,用户空间应跳过 hdr->length 字节(mod cmdr_size)以查找下一个 cmd_entry。
否则,该条目将包含指向 mmap 区域的偏移量,该区域包含 cdb 和数据缓冲区,后者可通过 iov 数组访问。iov 地址也是共享区域的偏移量。
当用户空间完成处理命令时,设置 entry->rsp.scsi_status,如果适用,则填充 rsp.sense_buffer,并将 mailbox->cmd_tail 设置为等于旧的 cmd_tail 加上 hdr->length,mod cmdr_size。如果 cmd_tail 不等于 cmd_head,它应以相同方式处理下一个数据包,依此类推。
iSCSI 辅助函数¶
-
void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t, struct iscsi_data *hdr)¶
初始化 Data-Out
参数
struct iscsi_task *task
SCSI 命令任务
struct iscsi_r2t_info *r2t
R2T 信息
struct iscsi_data *hdr
iscsi 数据输出 PDU
说明
在此 R2T 序列中初始化 Data-Out,并在此 SCSI 命令中查找正确的数据偏移量。
此函数在获取连接锁时调用。
-
void __iscsi_put_task(struct iscsi_task *task)¶
减少任务的引用计数
参数
struct iscsi_task *task
要减少引用计数的 iscsi_task
描述
调用时必须持有 back_lock,以防它释放任务。
-
void iscsi_complete_scsi_task(struct iscsi_task *task, uint32_t exp_cmdsn, uint32_t max_cmdsn)¶
正常完成 SCSI 任务
参数
struct iscsi_task *task
SCSI 命令的 iscsi 任务
uint32_t exp_cmdsn
CPU 格式的预期命令序列号
uint32_t max_cmdsn
CPU 格式的最大命令序列号
描述
当驱动程序不需要或无法执行较低级别的 PDU 处理时,会使用此方法。
使用会话 back_lock 调用
-
struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)¶
通过 itt 查找任务
参数
struct iscsi_conn *conn
iSCSI 连接
itt_t itt
itt
描述
这应该用于管理任务(如登录和 NOP),或者当 LDD 的 itt 空间不包含会话期限时。
必须持有会话 back_lock。
-
int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen)¶
完成 PDU
参数
struct iscsi_conn *conn
iSCSI 连接
struct iscsi_hdr *hdr
iSCSI 标头
char *data
数据缓冲区
int datalen
数据缓冲区的长度
描述
通过释放 queuecommand 或 send generic 时分配的任何资源来完成 PDU 处理。必须持有会话 back_lock,并且必须调用 verify itt。
-
struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)¶
通过 itt 查找 ctask
参数
struct iscsi_conn *conn
iSCSI 连接
itt_t itt
itt
描述
这应该用于命令任务。
必须持有会话 back_lock。
-
void iscsi_requeue_task(struct iscsi_task *task)¶
将任务重新排队以从会话工作队列运行
参数
struct iscsi_task *task
要重新排队的任务
描述
调用方必须已对要重新排队的任务进行了引用。
-
void iscsi_suspend_queue(struct iscsi_conn *conn)¶
挂起 iscsi_queuecommand
参数
struct iscsi_conn *conn
停止在其上排队 IO 的 iscsi 连接
描述
这会获取会话 frwd_lock 以确保没有人在 xmit_task/queuecommand 中,然后设置挂起以防止新命令排队。这只需要由需要同步路径的卸载驱动程序调用,例如 ep 断开连接和 iscsi_queuecommand/xmit_task。要再次启动 IO,当处于 FFP 时,libiscsi 将调用 iscsi_start_tx 和 iscsi_unblock_session。
-
void iscsi_suspend_tx(struct iscsi_conn *conn)¶
挂起 iscsi_data_xmit
参数
struct iscsi_conn *conn
停止在其上处理 IO 的 iSCSI 连接。
描述
此函数设置挂起位以防止 iscsi_data_xmit 发送新的 IO,并且如果工作在 xmit 线程上排队,它将等待它完成。
-
void iscsi_suspend_rx(struct iscsi_conn *conn)¶
防止 recvwork 再次运行。
参数
struct iscsi_conn *conn
要停止的 iSCSI 连接。
-
void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active)¶
防止向连接排队。
参数
struct iscsi_cls_conn *cls_conn
iSCSI 连接 EP 绑定到。
bool is_active
连接是否用于启动,还是用于 EH/终止
描述
必须由实现 ep_disconnect 调用驱动程序调用。它会禁用来自 libiscsi 的连接排队,为 ep_disconnect 调用做准备。
-
int iscsi_eh_session_reset(struct scsi_cmnd *sc)¶
删除会话并尝试重新登录
参数
struct scsi_cmnd *sc
SCSI 命令
描述
此函数将等待重新登录、来自用户空间的会话终止或恢复/替换超时。
-
int iscsi_eh_recover_target(struct scsi_cmnd *sc)¶
重置目标,并可能重置会话
参数
struct scsi_cmnd *sc
SCSI 命令
描述
这将尝试发送热目标重置。如果失败,我们将升级到 ERL0 会话恢复。
参数
struct Scsi_Host *shost
SCSI 主机
struct device *pdev
父设备
描述
部分卸载和软件 iSCSI 驱动程序应调用此函数,以便将主机添加到系统中。
-
struct Scsi_Host *iscsi_host_alloc(const struct scsi_host_template *sht, int dd_data_size, bool xmit_can_sleep)¶
分配主机和驱动程序数据
参数
const struct scsi_host_template *sht
SCSI 主机模板
int dd_data_size
驱动程序主机数据大小
bool xmit_can_sleep
一个布尔值,指示 LLD 是否将从工作队列中排队 IO
描述
部分卸载和软件 iSCSI 驱动程序应调用此函数。要访问驱动程序特定的内存,请使用 iscsi_host_priv() 宏。
-
void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown)¶
移除主机和会话
参数
struct Scsi_Host *shost
SCSI 主机
bool is_shutdown
如果从驱动程序关闭回调中调用,则为 true
描述
如果有任何会话剩余,这将启动移除并等待完成。
-
struct iscsi_cls_session *iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, uint16_t cmds_max, int dd_size, int cmd_task_size, uint32_t initial_cmdsn, unsigned int id)¶
创建 iSCSI cls 会话以及主机和会话
参数
struct iscsi_transport *iscsit
iSCSI 传输模板
struct Scsi_Host *shost
SCSI 主机
uint16_t cmds_max
会话可以排队
int dd_size
私有驱动程序数据大小,添加到会话分配大小
int cmd_task_size
LLD 任务私有数据大小
uint32_t initial_cmdsn
初始 CmdSN
unsigned int id
要添加到此会话的目标 ID
描述
这可以被每个 SCSI 主机分配一个会话的软件 iscsi_transports 使用。
调用者应将 cmds_max 设置为它们支持的最大任务总数(mgmt + scsi)。iSCSI 层为 nop 处理和登录/注销请求保留 ISCSI_MGMT_CMDS_MAX 任务。
-
void iscsi_session_free(struct iscsi_cls_session *cls_session)¶
释放 iSCSI 会话及其资源
参数
struct iscsi_cls_session *cls_session
iSCSI 会话
-
void iscsi_session_teardown(struct iscsi_cls_session *cls_session)¶
销毁会话和 cls_session
参数
struct iscsi_cls_session *cls_session
iSCSI 会话
-
struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, uint32_t conn_idx)¶
创建 iscsi_cls_conn 和 iscsi_conn
参数
struct iscsi_cls_session *cls_session
iSCSI_cls_session
int dd_size
私有驱动程序数据大小
uint32_t conn_idx
cid
-
void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)¶
拆卸 iSCSI 连接
参数
struct iscsi_cls_conn *cls_conn
iSCSI 类连接
描述
TODO: 我们可能需要将其转换为两步过程,如 scsi-mls remove + put host
iSCSI 启动信息¶
-
struct iscsi_boot_kobj *iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show)(void *data, int type, char *buf), umode_t (*is_visible)(void *data, int type), void (*release)(void *data))¶
创建启动目标 sysfs 目录
参数
struct iscsi_boot_kset *boot_kset
启动 kset
int index
目标 ID
void *data
目标的驱动程序特定数据
ssize_t (*show) (void *data, int type, char *buf)
属性 show 函数
umode_t (*is_visible) (void *data, int type)
属性可见性函数
void (*release) (void *data)
释放函数
注意
当目标kobject的所有引用都被释放后,引导 sysfs 库将释放为调用者传入的数据。
-
struct iscsi_boot_kobj *iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show)(void *data, int type, char *buf), umode_t (*is_visible)(void *data, int type), void (*release)(void *data))¶
创建引导发起程序 sysfs 目录
参数
struct iscsi_boot_kset *boot_kset
启动 kset
int index
发起程序 ID
void *data
驱动程序特定数据
ssize_t (*show) (void *data, int type, char *buf)
属性 show 函数
umode_t (*is_visible) (void *data, int type)
属性可见性函数
void (*release) (void *data)
释放函数
注意
当所有对发起程序 kobject 的引用都被释放后,引导 sysfs 库将释放为调用者传入的数据。
-
struct iscsi_boot_kobj *iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show)(void *data, int type, char *buf), umode_t (*is_visible)(void *data, int type), void (*release)(void *data))¶
创建引导以太网 sysfs 目录
参数
struct iscsi_boot_kset *boot_kset
启动 kset
int index
以太网设备 ID
void *data
驱动程序特定数据
ssize_t (*show) (void *data, int type, char *buf)
属性 show 函数
umode_t (*is_visible) (void *data, int type)
属性可见性函数
void (*release) (void *data)
释放函数
注意
当所有对以太网 kobject 的引用都被释放后,引导 sysfs 库将释放为调用者传入的数据。
-
struct iscsi_boot_kobj *iscsi_boot_create_acpitbl(struct iscsi_boot_kset *boot_kset, int index, void *data, ssize_t (*show)(void *data, int type, char *buf), umode_t (*is_visible)(void *data, int type), void (*release)(void *data))¶
创建引导 acpi 表 sysfs 目录
参数
struct iscsi_boot_kset *boot_kset
启动 kset
int index
未使用
void *data
驱动程序特定数据
ssize_t (*show)(void *data, int type, char *buf)
属性 show 函数
umode_t (*is_visible)(void *data, int type)
属性可见性函数
void (*release)(void *data)
释放函数
注意
当所有对 acpitbl kobject 的引用都被释放后,引导 sysfs 库将释放为调用者传入的数据。
-
struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)¶
创建根 sysfs 树
参数
const char *set_name
根目录名称
-
struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)¶
为 scsi 主机创建根 sysfs 树
参数
unsigned int hostno
scsi 主机的主机号
-
void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)¶
销毁 kset 及其下的 kobject
参数
struct iscsi_boot_kset *boot_kset
启动 kset
描述
这将移除 kset 及其下的 kobject 和属性。
iSCSI TCP 接口¶
-
int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int offset, size_t len)¶
以 sendfile 方式接收 TCP 数据
参数
read_descriptor_t *rd_desc
读取描述符
struct sk_buff *skb
套接字缓冲区
unsigned int offset
skb 中的偏移量
size_t len
skb->len - 偏移量
参数
struct sock *sk
套接字
描述
如果套接字处于 CLOSE 或 CLOSE_WAIT 状态,如果仍有数据挂起,我们不应关闭连接。
必须使用 sk_callback_lock 调用。
参数
struct sock *sk
套接字空间可用于
-
int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment)¶
传输段
参数
struct iscsi_tcp_conn *tcp_conn
iSCSI TCP 连接
struct iscsi_segment *segment
要传输的缓冲区
描述
此函数传输网络层将接受的缓冲区中的尽可能多的数据,并返回传输的字节数。
如果启用了 CRC 哈希,该函数将在传输过程中计算哈希。当整个段传输完毕后,它将检索哈希值并将其发送。
-
int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)¶
TCP 传输
参数
struct iscsi_conn *conn
iSCSI 连接
-
int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn)¶
返回排队等待 xmit 的字节数
参数
struct iscsi_conn *conn
iSCSI 连接
-
int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment, int recv, unsigned copied)¶
检查段是否完成
参数
struct iscsi_tcp_conn *tcp_conn
iscsi tcp 连接
struct iscsi_segment *segment
要检查的 iscsi 段
int recv
如果从接收路径调用此函数,则设置为 1
unsigned copied
复制的字节数
描述
检查我们是否已完成接收此段。如果接收缓冲区已满但我们期望更多数据,请转到散列表中的下一个条目。
如果我们收到的数据量不是 4 的倍数,我们也会透明地接收填充字节。
此函数必须是可重入的。
-
void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)¶
准备用于 hdr 接收的段
参数
struct iscsi_tcp_conn *tcp_conn
要准备的 iscsi 连接
描述
此函数始终为哈希参数传递 NULL,因为当调用此函数时,我们还不知道标头的最终大小,并希望延迟摘要处理,直到我们知道为止。
-
void iscsi_tcp_cleanup_task(struct iscsi_task *task)¶
释放 tcp_task 资源
参数
struct iscsi_task *task
iscsi 任务
描述
必须使用会话 back_lock 调用
-
int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn)¶
测试我们是否正在读取标头
参数
struct iscsi_tcp_conn *tcp_conn
iscsi tcp 连接
描述
如果当前正在处理或设置为处理标头,则返回非零值。
-
int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, unsigned int offset, bool offloaded, int *status)¶
处理 skb
参数
struct iscsi_conn *conn
iSCSI 连接
struct sk_buff *skb
带有标头和/或数据段的网络缓冲区
unsigned int offset
skb 中的偏移量
bool offloaded
指示传输是否被卸载的布尔值
int *status
iscsi TCP 状态结果
描述
将在 status 中返回传输状态。并返回复制的字节数。
-
int iscsi_tcp_task_init(struct iscsi_task *task)¶
初始化 iSCSI SCSI_READ 或 SCSI_WRITE 命令
参数
struct iscsi_task *task
SCSI 命令任务
-
int iscsi_tcp_task_xmit(struct iscsi_task *task)¶
传输正常 PDU 任务
参数
struct iscsi_task *task
iscsi 命令任务
描述
当一切传输成功时,我们应该返回 0,如果队列中仍然有数据,则返回 -EAGAIN,对于任何其他类型的错误,则返回 != 0。