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)¶
分配 target 驱动程序私有数据
参数
struct se_session *se_sess
会话指针。
unsigned int tag_num
发起方和 target 之间的最大未完成命令数。
unsigned int tag_size
target 驱动程序与每个命令关联的私有数据的大小(以字节为单位)。
-
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 sense 缓冲区的指针
u64 unpacked_lun
用于引用 struct se_lun 的解包 LUN
u32 data_length
fabric 期望的数据传输长度
int task_attr
SAM 任务属性
int data_dir
DMA 数据方向
int flags
来自 target_sc_flags_tables 的命令提交标志
描述
如果调用者设置了 se_cmd->tag,则支持任务标签。
如果 fabric 驱动程序调用 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)¶
准备提交 cmd
参数
struct se_cmd *se_cmd
要准备的命令描述符
unsigned char *cdb
指向 SCSI CDB 的指针
struct scatterlist *sgl
用于单向映射的 struct scatterlist 内存
u32 sgl_count
用于单向映射的 scatterlist 计数
struct scatterlist *sgl_bidi
用于双向 READ 映射的 struct scatterlist 内存
u32 sgl_bidi_count
用于双向 READ 映射的 scatterlist 计数
struct scatterlist *sgl_prot
struct scatterlist 内存保护信息
u32 sgl_prot_count
保护信息的 scatterlist 计数
gfp_t gfp
gfp 分配类型
返回
小于零表示失败。
成功时返回零。
描述
如果返回失败,lio 将调用 queue_status 来完成 cmd。
-
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 sense 缓冲区的指针
u64 unpacked_lun
用于引用 struct se_lun 的解包 LUN
u32 data_length
fabric 期望的数据传输长度
int task_attr
SAM 任务属性
int data_dir
DMA 数据方向
int flags
来自 target_sc_flags_tables 的命令提交标志
描述
如果调用者设置了 se_cmd->tag,则支持任务标签。
这只能从进程上下文中调用,并且当前还假设 target-core 内部分配 fabric 有效负载缓冲区。
它还假设内部 target 核心 SGL 内存分配。
此函数只能由在关闭期间执行自己的同步并且不使用 target_stop_session 的驱动程序使用。 如果发生故障,此函数将使用 CHECK_CONDITION 调用 fabric 驱动程序的 queue_status。
参数
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 sense 缓冲区的指针
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)¶
等待未完成的 cmds。
参数
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*() 失败时才调用此函数。
Target 支持的用户空间 I/O¶
用户空间 I/O¶
定义 LIO 的共享内存接口,用于将 SCSI 命令和数据传递到用户空间进行处理。 这是为了允许后端过于复杂,无法进行内核支持。
它使用 UIO 框架来为我们完成大量设备创建和内省工作。
有关环的布局,请参见 .h 文件。 请注意,尽管定义了命令环,但数据区域的细节并未定义。 命令条目中的偏移值指向 mmap 区域内的其他位置。 在命令环之外有单独的空间用于数据缓冲区。 这为移动缓冲区分配,甚至页面翻转或其他分配技术留下了最大的灵活性,而无需更改命令环布局。
安全性:必须假定用户进程是恶意的。 如果它愿意,没有办法阻止它破坏命令环协议,但为了防止其他问题,我们必须始终仅从共享内存区域读取*data*,而不是偏移量或大小。 这适用于命令环条目以及邮箱。 为此需要的额外代码可能带有“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 命令中查找适当的 data_offset。
此函数在获取连接锁时调用。
-
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 cmd 的 iscsi 任务
uint32_t exp_cmdsn
cpu 格式的预期 cmd sn
uint32_t max_cmdsn
cpu 格式的最大 cmd sn
描述
当驱动程序不需要或无法执行较低级别的 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
描述
这应该用于 mgmt 任务,例如登录和 nops,或者如果 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 conn
struct iscsi_hdr *hdr
iscsi 标头
char *data
数据缓冲区
int datalen
数据缓冲区的长度
描述
通过释放 queuecommand 或发送通用命令时分配的任何资源来完成 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
描述
这应该用于 cmd 任务。
必须持有会话 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 conn
描述
这会获取会话 frwd_lock 以确保没有人位于 xmit_task/queuecommand 中,然后设置 suspend 以防止新命令排队。 只有需要同步路径的卸载驱动程序(例如 ep 断开连接)才能使用 iscsi_queuecommand/xmit_task 调用此选项。 要再次启动 IO,libiscsi 将在 FFP 中调用 iscsi_start_tx 和 iscsi_unblock_session。
-
void iscsi_suspend_tx(struct iscsi_conn *conn)¶
暂停 iscsi_data_xmit
参数
struct iscsi_conn *conn
iscsi conn 以停止处理 IO。
描述
此函数设置暂停位以防止 iscsi_data_xmit 发送新的 IO,如果工作在 xmit 线程上排队,它将等待它完成。
-
void iscsi_suspend_rx(struct iscsi_conn *conn)¶
阻止 recvwork 再次运行。
参数
struct iscsi_conn *conn
iscsi conn 以停止。
-
void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active)¶
防止排队到 conn。
参数
struct iscsi_cls_conn *cls_conn
iscsi conn ep 绑定到。
bool is_active
conn 是否用于启动,或者这是否用于 EH/终止
描述
实现 ep_disconnect callout 的驱动程序必须调用此选项。 它禁用从 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
如果从驱动程序关闭 callout 调用,则为 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 设置为它们支持的最大总任务数(管理 + 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)
属性显示函数
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)
属性显示函数
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)
属性显示函数
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)
属性显示函数
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 主机的 host number
-
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 - offset
参数
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
如果从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连接
描述
此函数总是为crcp参数传递NULL,因为当调用此函数时,我们还不知道header的最终大小,并希望延迟摘要处理,直到我们知道为止。
-
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)¶
测试我们是否正在读取header
参数
struct iscsi_tcp_conn *tcp_conn
iscsi tcp 连接
描述
如果我们当前正在处理或设置为处理header,则返回非零值。
-
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
带有header和/或数据段的网络缓冲区
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)¶
xmit正常PDU任务
参数
struct iscsi_task *task
iscsi命令任务
描述
如果一切都成功传输,我们应该返回0;如果队列中仍然有数据,则返回-EAGAIN;对于任何其他类型的错误,则返回!= 0。