Chinese translation docs for 6.19

This is the Chinese translation subtree for 6.19. It includes
 the following changes:
         - Add block part translations
         - Update kbuild.rst translations
         - Add more scsi translations and fixes
 
 Above patches are tested by 'make htmldocs'
 
 Signed-off-by: Alex Shi <alexs@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEZFWMuCq1F2HcVvoPesqFB/fkdOYFAmkmovQRHGFsZXhzQGtl
 cm5lbC5vcmcACgkQesqFB/fkdOYFwA//bX8ln3fKDkFvslipWbYcJIltAKunjHoh
 RxdSxieH3A/Q95qCXeNhTaty1+mx4AqCBGrTp9jCDUQMiWSP+Sy+Zpro6TrvV9nU
 suC8S5uvzM6HZibpMMv7vKGaR3zhSwBQbx/Mh2BRktHdtMCPKrxVCW0l14cl2lM5
 l7TSldBpjclaskYOCjV+FG5SxdUFhmrvMuKGT0vjN2NCF2NRNho8nJ/H2PSkUVN9
 ZjNpzVOlGMZbzyAR0fp2hjUGZKdhC/TdubM9f93E2Za9DOu7L+ZP1mkwhp85mKMd
 OBlyozfuk4iZHhgCY6svtwkaQJgkMRU+G7fHrrlEM3oaZyaiaqR9y+hlx7FNwUL3
 MWCpux6JMYTAxiIhZ2jIVYZqBe6tp8D/Zvd/9OuT/aTO3DGtyeS9kw3PKF/SJk5l
 Z8yoIQk6Y718j//n/uxR/KmSfTmo5AZ3EoZfUWg5YBfXNAfa2EwsZG8ir6irE/RP
 LAVttTGb1eoYpJlUJBvNF6es7OEPjaxLp+l3pkHeftO7hittN6Mih1YKD8xBhqrh
 D8iIDDfUre40pe38jGCdxA+y6LaLUPmEFT7T8cMvS82H7dza6V0Gx9w65obuFgwX
 rOw7cHOozdHUM0QdZxk2apHTmq2VHMykXNQiI/K+/s7T6WuGUGLVFrZRvAxPNFVs
 eraJLQNC5wY=
 =adk6
 -----END PGP SIGNATURE-----

Merge tag 'Chinese-docs-6.19' of gitolite.kernel.org:pub/scm/linux/kernel/git/alexs/linux into tmp

Chinese translation docs for 6.19

This is the Chinese translation subtree for 6.19. It includes
the following changes:
        - Add block part translations
        - Update kbuild.rst translations
        - Add more scsi translations and fixes

Above patches are tested by 'make htmldocs'

Signed-off-by: Alex Shi <alexs@kernel.org>
This commit is contained in:
Jonathan Corbet 2025-11-29 08:09:58 -07:00
commit 0dd5cf95b7
9 changed files with 851 additions and 14 deletions

View File

@ -0,0 +1,130 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/block/blk-mq.rst
:翻译:
柯子杰 kezijie <kezijie@leap-io-kernel.com>
:校译:
================================================
多队列块设备 I/O 排队机制 (blk-mq)
================================================
多队列块设备 I/O 排队机制提供了一组 API使高速存储设备能够同时在多个队列中
处理并发的 I/O 请求并将其提交到块设备,从而实现极高的每秒输入/输出操作次数
(IOPS),充分发挥现代存储设备的并行能力。
介绍
====
背景
----
磁盘从 Linux 内核开发初期就已成为事实上的标准。块 I/O 子系统的目标是尽可能
为此类设备提供最佳性能,因为它们在进行随机访问时代价极高,性能瓶颈主要在机械
运动部件上,其速度远低于存储栈中其他任何层。其中一个软件优化例子是根据硬盘磁
头当前的位置重新排序读/写请求。
然而,随着固态硬盘和非易失性存储的发展,它们没有机械部件,也不存在随机访问代
码,并能够进行高速并行访问,存储栈的瓶颈从存储设备转移到了操作系统。为了充分
利用这些设备设计中的并行性,引入了多队列机制。
原来的设计只有一个队列来存储块设备 I/O 请求,并且只使用一个锁。由于缓存中的
脏数据和多处理器共享单锁的瓶颈,这种设计在 SMP 系统中扩展性不佳。当不同进程
(或同一进程在不同 CPU 上)同时执行块设备 I/O 时,该单队列模型还会出现严重
的拥塞问题。为了解决这些问题blk-mq API 引入了多个队列,每个队列在本地 CPU
上拥有独立的入口点,从而消除了对全局锁的需求。关于其具体工作机制的更深入说明,
请参见下一节( `工作原理`_ )。
工作原理
--------
当用户空间执行对块设备的 I/O例如读写文件blk-mq 便会介入:它将存储和
管理发送到块设备的 I/O 请求,充当用户空间(文件系统,如果存在的话)与块设备驱
动之间的中间层。
blk-mq 由两组队列组成:软件暂存队列和硬件派发队列。当请求到达块层时,它会尝
试最短路径:直接发送到硬件队列。然而,有两种情况下可能不会这样做:如果该层有
IO 调度器或者是希望合并请求。在这两种情况下,请求将被发送到软件队列。
随后,在软件队列中的请求被处理后,请求会被放置到硬件队列。硬件队列是第二阶段
的队列,硬件可以直接访问并处理这些请求。然而,如果硬件没有足够的资源来接受更
多请求blk-mq 会将请求放置在临时队列中,待硬件资源充足时再发送。
软件暂存队列
~~~~~~~~~~~~
在这些请求未直接发送到驱动时,块设备 I/O 子系统会将请求添加到软件暂存队列中
(由 struct blk_mq_ctx 表示)。一个请求可能包含一个或多个 BIO。它们通过 struct bio
数据结构到达块层。块层随后会基于这些 BIO 构建新的结构体 struct request用于
与设备驱动通信。每个队列都有自己的锁,队列数量由每个 CPU 和每个 node 为基础
来决定。
暂存队列可用于合并相邻扇区的请求。例如对扇区3-6、6-7、7-9的请求可以合并
为对扇区3-9的一个请求。即便 SSD 或 NVM 的随机访问和顺序访问响应时间相同,
合并顺序访问的请求仍可减少单独请求的数量。这种合并请求的技术称为 plugging。
此外I/O 调度器还可以对请求进行重新排序以确保系统资源的公平性(例如防止某
个应用出现“饥饿”现象)或是提高 I/O 性能。
I/O 调度器
^^^^^^^^^^
块层实现了多种调度器,每种调度器都遵循一定启发式规则以提高 I/O 性能。它们是
“可插拔”的(plug and play),可在运行时通过 sysfs 选择。你可以在这里阅读更
多关于 Linux IO 调度器知识 `here
<https://www.kernel.org/doc/html/latest/block/index.html>`_。调度只发
生在同一队列内的请求之间,因此无法合并不同队列的请求,否则会造成缓存冲突并需
要为每个队列加锁。调度后,请求即可发送到硬件。可能选择的调度器之一是 NONE 调
度器,这是最直接的调度器:它只将请求放到进程所在的软件队列,不进行重新排序。
当设备开始处理硬件队列中的请求时(运行硬件队列),映射到该硬件队列的软件队列
会按映射顺序依次清空。
硬件派发队列
~~~~~~~~~~~~~
硬件队列(由 struct blk_mq_hw_ctx 表示)是设备驱动用来映射设备提交队列
(或设备 DMA 环缓存)的结构体,它是块层提交路径在底层设备驱动接管请求之前的
最后一个阶段。运行此队列时,块层会从相关软件队列中取出请求,并尝试派发到硬件。
如果请求无法直接发送到硬件,它们会被加入到请求的链表(``hctx->dispatch``) 中。
随后,当块层下次运行该队列时,会优先发送位于 ``dispatch`` 链表中的请求,
以确保那些最早准备好发送的请求能够得到公平调度。硬件队列的数量取决于硬件及
其设备驱动所支持的硬件上下文数但不会超过系统的CPU核心数。在这个阶段不
会发生重新排序,每个软件队列都有一组硬件队列来用于提交请求。
.. note::
块层和设备协议都不保证请求完成顺序。此问题需由更高层处理,例如文件系统。
基于标识的完成机制
~~~~~~~~~~~~~~~~~~~
为了指示哪一个请求已经完成,每个请求都会被分配一个整数标识,该标识的取值范围
是从0到分发队列的大小。这个标识由块层生成并在之后由设备驱动使用从而避
免了为每个请求再单独创建冗余的标识符。当请求在驱动中完成时,驱动会将该标识返
回给块层,以通知该请求已完成。这样,块层就无需再进行线性搜索来确定是哪一个
I/O 请求完成了。
更多阅读
--------
- `Linux 块 I/O多队列 SSD 并发访问简介 <http://kernel.dk/blk-mq.pdf>`_
- `NOOP 调度器 <https://en.wikipedia.org/wiki/Noop_scheduler>`_
- `Null 块设备驱动程序 <https://www.kernel.org/doc/html/latest/block/null_blk.html>`_
源代码
======
该API在以下内核代码中:
include/linux/blk-mq.h
block/blk-mq.c

View File

@ -0,0 +1,192 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/block/data-integrity.rst
:翻译:
柯子杰 kezijie <kezijie@leap-io-kernel.com>
:校译:
==========
数据完整性
==========
1. 引言
=======
现代文件系统对数据和元数据都进行了校验和保护以防止数据损坏。然而,这种损坏的
检测是在读取时才进行,这可能发生在数据写入数月之后。到那时,应用程序尝试写入
的原始数据很可能已经丢失。
解决方案是确保磁盘实际存储的内容就是应用程序想存储的。SCSI 协议族(如 SBC
数据完整性字段、SCC 保护提案)以及 SATA/T13外部路径保护最近新增的功能
通过在 I/O 中附加完整性元数据的方式,试图解决这一问题。完整性元数据(在
SCSI 术语中称为保护信息)包括每个扇区的校验和,以及一个递增计数器,用于确保
各扇区按正确顺序被写入盘。在某些保护方案中,还能保证 I/O 写入磁盘的正确位置。
当前的存储控制器和设备实现了多种保护措施,例如校验和和数据清理。但这些技术通
常只在各自的独立域内工作,或最多仅在 I/O 路径的相邻节点之间发挥作用。DIF 及
其它数据完整性拓展有意思的点在于保护格式定义明确I/O 路径上的每个节点都可以
验证 I/O 的完整性,如检测到损坏可直接拒绝。这不仅可以防止数据损坏,还能够隔
离故障点。
2. 数据完整性拓展
=================
如上所述,这些协议扩展只保护控制器与存储设备之间的路径。然而,许多控制器实际
上允许操作系统与完整性元数据(IMD)交互。我们一直与多家 FC/SAS HBA 厂商合作,
使保护信息能够在其控制器与操作系统之间传输。
SCSI 数据完整性字段通过在每个扇区后附加8字节的保护信息来实现。数据 + 完整
性元数据存储在磁盘的520字节扇区中。数据 + IMD 在控制器与目标设备之间传输
时是交错组合在一起的。T13 提案的方式类似。
由于操作系统处理520字节甚至 4104 字节)扇区非常不便,我们联系了多家 HBA
厂商,并鼓励它们分离数据与完整性元数据的 scatter-gather lists。
控制器在写入时会将数据缓冲区和完整性元数据缓冲区的数据交错在一起,并在读取时
会拆分它们。这样Linux 就能直接通过 DMA 将数据缓冲区传输到主机内存或从主机
内存读取,而无需修改页缓存。
此外SCSI 与 SATA 规范要求的16位 CRC 校验在软件中计算代价较高。基准测试发
现,计算此校验在高负载情形下显著影响系统性能。一些控制器允许在操作系统接口处
使用轻量级校验。例如 Emulex 支持 TCP/IP 校验。操作系统提供的 IP 校验在写入
时会转换为16位 CRC读取时则相反。这允许 Linux 或应用程序以极低的开销生成
完整性元数据(与软件 RAID5 相当)。
IP 校验在检测位错误方面比 CRC 弱,但关键在于数据缓冲区与完整性元数据缓冲区
的分离。只有这两个不同的缓冲区匹配I/O 才能完成。
数据与完整性元数据缓冲区的分离以及校验选择被称为数据完整性扩展。由于这些扩展
超出了协议主体(T10、T13)的范围Oracle 及其合作伙伴正尝试在存储网络行业协
会内对其进行标准化。
3. 内核变更
===========
Linux 中的数据完整性框架允许将保护信息固定到 I/O 上,并在支持该功能的控制器
之间发送和接收。
SCSI 和 SATA 中完整性扩展的优势在于,它们能够保护从应用程序到存储设备的整个
路径。然而,这同时也是最大的劣势。这意味着保护信息必须采用磁盘可以理解的格式。
通常Linux/POSIX 应用程序并不关心所访问存储设备的具体细节。虚拟文件系统层
和块层会让硬件扇区大小和传输协议对应用程序完全透明。
然而,在准备发送到磁盘的保护信息时,就需要这种细节。因此,端到端保护方案的概
念实际上违反了层次结构。应用程序完全不应该知道它访问的是 SCSI 还是 SATA 磁盘。
Linux 中实现的数据完整性支持尝试将这些细节对应用程序隐藏。就应用程序(以及在
某种程度上内核)而言,完整性元数据是附加在 I/O 上的不透明信息。
当前实现允许块层自动为任何 I/O 生成保护信息。最终目标是将用户数据的完整性元
数据计算移至用户空间。内核中产生的元数据和其他 I/O 仍将使用自动生成接口。
一些存储设备允许为每个硬件扇区附加一个16位的标识值。这个标识空间的所有者是
块设备的所有者,也就是在多数情况下由文件系统掌控。文件系统可以利用这额外空间
按需为扇区附加标识。由于标识空间有限,块接口允许通过交错方式对更大的数据块标
识。这样8*16位的信息可以附加到典型的 4KB 文件系统块上。
这也意味着诸如 fsck 和 mkfs 等应用程序需要能够从用户空间访问并操作这些标记。
为此,正在开发一个透传接口。
4. 块层实现细节
===============
4.1 Bio
--------
当启用 CONFIG_BLK_DEV_INTEGRITY 时,数据完整性补丁会在 struct bio 中添加
一个新字段。调用 bio_integrity(bio) 会返回一个指向 struct bip 的指针,该
结构体包含了该 bio 的完整性负载。本质上bip 是一个精简版的 struct bio
中包含一个 bio_vec用于保存完整性元数据以及所需的维护信息bvec 池、向量计
数等)。
内核子系统可以通过调用 bio_integrity_alloc(bio) 来为某个 bio 启用数据完整
性保护。该函数会分配并附加一个 bip 到该 bio 上。
随后使用 bio_integrity_add_page() 将包含完整性元数据的单独页面附加到该 bio。
调用 bio_free() 会自动释放bip。
4.2 块设备
-----------
块设备可以在 queue_limits 结构中的 integrity 子结构中设置完整性信息。
对于分层块设备,需要选择一个适用于所有子设备的完整性配置文件。可以使用
queue_limits_stack_integrity() 来协助完成该操作。目前DM 和 MD linear、
RAID0 和 RAID1 已受支持。而RAID4/5/6因涉及应用标签仍需额外的开发工作。
5.0 块层完整性API
==================
5.1 普通文件系统
-----------------
普通文件系统并不知道其下层块设备具备发送或接收完整性元数据的能力。
在执行写操作时,块层会在调用 submit_bio() 时自动生成完整性元数据。
在执行读操作时I/O 完成后会触发完整性验证。
IMD 的生成与验证行为可以通过以下开关控制::
/sys/block/<bdev>/integrity/write_generate
and::
/sys/block/<bdev>/integrity/read_verify
flags.
5.2 具备完整性感知的文件系统
----------------------------
具备完整性感知能力的文件系统可以在准备 I/O 时附加完整性元数据,
并且如果底层块设备支持应用标签空间,也可以加以利用。
`bool bio_integrity_prep(bio);`
要为写操作生成完整性元数据或为读操作设置缓冲区,文件系统必须调用
bio_integrity_prep(bio)。
在调用此函数之前,必须先设置好 bio 的数据方向和起始扇区,并确
保该 bio 已经添加完所有的数据页。调用者需要自行保证,在 I/O 进行
期间 bio 不会被修改。如果由于某种原因准备失败,则应当以错误状态
完成该 bio。
5.3 传递已有的完整性元数据
--------------------------
能够自行生成完整性元数据或可以从用户空间传输完整性元数据的文件系统,
可以使用如下接口:
`struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages);`
为 bio 分配完整性负载并挂载到 bio 上。nr_pages 表示需要在
integrity bio_vec list 中存储多少页保护数据(类似 bio_alloc
完整性负载将在 bio_free() 被调用时释放。
`int bio_integrity_add_page(bio, page, len, offset);`
将包含完整性元数据的一页附加到已有的 bio 上。该 bio 必须已有 bip
即必须先调用 bio_integrity_alloc()。对于写操作,页中的完整
性元数据必须采用目标设备可识别的格式,但有一个例外,当请求在 I/O 栈
中传递时,扇区号会被重新映射。这意味着通过此接口添加的页在 I/O 过程
中可能会被修改!完整性元数据中的第一个引用标签必须等于 bip->bip_sector。
只要 bip bio_vec arraynr_pages有空间就可以继续通过
bio_integrity_add_page()添加页。
当读操作完成后,附加的页将包含从存储设备接收到的完整性元数据。
接收方需要处理这些元数据,并在操作完成时验证数据完整性
----------------------------------------------------------------------
2007-12-24 Martin K. Petersen <martin.petersen@oracle.com>

View File

@ -0,0 +1,35 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/block/index.rst
:翻译:
柯子杰 ke zijie <kezijie@leap-io-kernel.com>
:校译:
=====
Block
=====
.. toctree::
:maxdepth: 1
blk-mq
data-integrity
TODOList:
* bfq-iosched
* biovecs
* cmdline-partition
* deadline-iosched
* inline-encryption
* ioprio
* kyber-iosched
* null_blk
* pr
* stat
* switching-sched
* writeback_cache_control
* ublk

View File

@ -93,6 +93,16 @@ HOSTRUSTFLAGS
-------------
在构建主机程序时传递给 $(HOSTRUSTC) 的额外标志。
PROCMACROLDFLAGS
----------------
用于链接 Rust 过程宏的标志。由于过程宏是由 rustc 在构建时加载的,
因此必须以与当前使用的 rustc 工具链兼容的方式进行链接。
例如,当 rustc 使用的 C 库与用户希望用于主机程序的 C 库不同时,
此设置会非常有用。
如果未设置,则默认使用链接主机程序时传递的标志。
HOSTLDFLAGS
-----------
链接主机程序时传递的额外选项。
@ -135,12 +145,18 @@ KBUILD_OUTPUT
指定内核构建的输出目录。
在单独的构建目录中为预构建内核构建外部模块时,这个变量也可以指向内核输出目录。请注意,
这并不指定外部模块本身的输出目录。
这并不指定外部模块本身的输出目录(使用 KBUILD_EXTMOD_OUTPUT 来达到这个目的)
输出目录也可以使用 "O=..." 指定。
设置 "O=..." 优先于 KBUILD_OUTPUT。
KBUILD_EXTMOD_OUTPUT
--------------------
指定外部模块的输出目录
设置 "MO=..." 优先于 KBUILD_EXTMOD_OUTPUT.
KBUILD_EXTRA_WARN
-----------------
指定额外的构建检查。也可以通过在命令行传递 "W=..." 来设置相同的值。
@ -290,8 +306,13 @@ IGNORE_DIRS
KBUILD_BUILD_TIMESTAMP
----------------------
将该环境变量设置为日期字符串,可以覆盖在 UTS_VERSION 定义中使用的时间戳
(运行内核时的 uname -v。该值必须是一个可以传递给 date -d 的字符串。默认值是
内核构建某个时刻的 date 命令输出。
(运行内核时的 uname -v) 。该值必须是一个可以传递给 date -d 的字符串。例如::
$ KBUILD_BUILD_TIMESTAMP="Mon Oct 13 00:00:00 UTC 2025" make
默认值是内核构建某个时刻的 date 命令输出。如果提供该时戳,它还用于任何 initramfs 归
档文件中的 mtime 字段。 Initramfs mtimes 是 32 位的,因此早于 Unix 纪元 1970 年,或
晚于协调世界时 (UTC) 2106 年 2 月 7 日 6 时 28 分 15 秒的日期是无效的。
KBUILD_BUILD_USER, KBUILD_BUILD_HOST
------------------------------------

View File

@ -50,7 +50,9 @@ SCSI主机适配器驱动
.. toctree::
:maxdepth: 1
libsas
sd-parameters
wd719x
Todolist:
@ -71,7 +73,6 @@ Todolist:
* g_NCR5380
* hpsa
* hptiop
* libsas
* lpfc
* megaraid
* ncr53c8xx
@ -87,6 +88,5 @@ Todolist:
* sym53c8xx_2
* tcm_qla2xxx
* ufs
* wd719x
* scsi_transport_srp/figures

View File

@ -0,0 +1,425 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/scsi/libsas.rst
:翻译:
张钰杰 Yujie Zhang <yjzhang@leap-io-kernel.com>
:校译:
======
SAS 层
======
SAS 层是一个管理基础架构,用于管理 SAS LLDD。它位于 SCSI Core
与 SAS LLDD 之间。 体系结构如下: SCSI Core 关注的是 SAM/SPC 相
关的问题SAS LLDD 及其序列控制器负责 PHY 层、OOB 信号以及链路
管理;而 SAS 层则负责以下任务::
* SAS Phy、Port 和主机适配器HA事件管理事件由 LLDD
生成,由 SAS 层处理);
* SAS 端口的管理(创建与销毁);
* SAS 域的发现与重新验证;
* SAS 域内设备的管理;
* SCSI 主机的注册与注销;
* 将设备注册到 SCSI CoreSAS 设备)或 libataSATA 设备);
* 扩展器的管理,并向用户空间导出扩展器控制接口。
SAS LLDD 是一种 PCI 设备驱动程序。它负责 PHY 层和 OOB带外
信号的管理、厂商特定的任务,并向 SAS 层上报事件。
SAS 层实现了 SAS 1.1 规范中定义的大部分 SAS 功能。
sas_ha_struct 结构体用于向 SAS 层描述一个 SAS LLDD。该结构的
大部分字段由 SAS 层使用,但其中少数字段需要由 LLDD 进行初始化。
在完成硬件初始化之后,应当在驱动的 probe() 函数中调用
sas_register_ha()。该函数会将 LLDD 注册到 SCSI 子系统中,创
建一个对应的 SCSI 主机,并将你的 SAS 驱动程序注册到其在 sysfs
下创建的 SAS 设备树中。随后该函数将返回。接着,你需要使能 PHY
以启动实际的 OOB带外过程此时驱动将开始调用 notify_* 系
列事件回调函数。
结构体说明
==========
``struct sas_phy``
------------------
通常情况下,该结构体会被静态地嵌入到驱动自身定义的 PHY 结构体中,
例如::
struct my_phy {
blah;
struct sas_phy sas_phy;
bleh;
}
随后在主机适配器HA的结构体中所有的 PHY 通常以 my_phy
数组的形式存在(如下文所示)。
在初始化各个 PHY 时,除了初始化驱动自定义的 PHY 结构体外,还
需要同时初始化其中的 sas_phy 结构体。
一般来说PHY 的管理由 LLDD 负责而端口port的管理由 SAS
层负责。因此PHY 的初始化与更新由 LLDD 完成,而端口的初始化与
更新则由 SAS 层完成。系统设计中规定,某些字段可由 LLDD 进行读
写,而 SAS 层只能读取这些字段;反之亦然。其设计目的是为了避免不
必要的锁操作。
在该设计中,某些字段可由 LLDD 进行读写RW而 SAS 层仅可读
取这些字段;反之亦然。这样设计的目的在于避免不必要的锁操作。
enabled
- 必须设置(0/1)
id
- 必须设置[0,MAX_PHYS)]
class, proto, type, role, oob_mode, linkrate
- 必须设置。
oob_mode
- 当 OOB带外信号完成后设置此字段然后通知 SAS 层。
sas_addr
- 通常指向一个保存该 PHY 的 SAS 地址的数组,该数组可能位于
驱动自定义的 my_phy 结构体中。
attached_sas_addr
- 当 LLDD 接收到 IDENTIFY 帧或 FIS 帧时,应在通知 SAS 层
之前设置该字段。其设计意图在于:有时 LLDD 可能需要伪造或
提供一个与实际不同的 SAS 地址用于该 PHY/端口,而该机制允许
LLDD 这样做。理想情况下,应将 SAS 地址从 IDENTIFY 帧中
复制过来;对于直接连接的 SATA 设备,也可以由 LLDD 生成一
个 SAS 地址。后续的发现过程可能会修改此字段。
frame_rcvd
- 当接收到 IDENTIFY 或 FIS 帧时,将该帧复制到此处。正确的
操作流程是获取锁 → 复制数据 → 设置 frame_rcvd_size → 释
放锁 → 调用事件通知。该字段是一个指针,因为驱动无法精确确
定硬件帧的大小;因此,实际的帧数据数组应定义在驱动自定义的
PHY 结构体中,然后让此指针指向该数组。在持锁状态下,将帧从
DMA 可访问内存区域复制到该数组中。
sas_prim
- 用于存放接收到的原语primitive。参见 sas.h。操作流程同
样是:获取锁 → 设置 primitive → 释放锁 → 通知事件。
port
- 如果该 PHY 属于某个端口port此字段指向对应的 sas_port
结构体。LLDD 仅可读取此字段。它由 SAS 层设置,用于指向当前
PHY 所属的 sas_port。
ha
- 可以由 LLDD 设置但无论是否设置SAS 层都会再次对其进行赋值。
lldd_phy
- LLDD 应将此字段设置为指向自身定义的 PHY 结构体,这样当 SAS
层调用某个回调并传入 sas_phy 时,驱动可以快速定位自身的 PHY
结构体。如果 sas_phy 是嵌入式成员,也可以使用 container_of()
宏进行访问——两种方式均可。
``struct sas_port``
-------------------
LLDD 不应修改该结构体中的任何字段——它只能读取这些字段。这些字段的
含义应当是不言自明的。
phy_mask 为 32 位,目前这一长度已足够使用,因为尚未听说有主机适配
器拥有超过8 个 PHY。
lldd_port
- 目前尚无明确用途。不过,对于那些希望在 LLDD 内部维护自身端
口表示的驱动,实现时可以利用该字段。
``struct sas_ha_struct``
------------------------
它通常静态声明在你自己的 LLDD 结构中,用于描述您的适配器::
struct my_sas_ha {
blah;
struct sas_ha_struct sas_ha;
struct my_phy phys[MAX_PHYS];
struct sas_port sas_ports[MAX_PHYS]; /* (1) */
bleh;
};
(1) 如果你的 LLDD 没有自己的端口表示
需要初始化(示例函数如下所示)。
pcidev
^^^^^^
sas_addr
- 由于 SAS 层不想弄乱内存分配等, 因此这指向静态分配的数
组中的某个位置(例如,在您的主机适配器结构中),并保存您或
制造商等给出的主机适配器的 SAS 地址。
sas_port
^^^^^^^^
sas_phy
- 指向结构体的指针数组(参见上文关于 sas_addr 的说明)。
这些指针必须设置。更多细节见下文说明。
num_phys
- 表示 sas_phy 数组中 PHY 的数量,同时也表示 sas_port
数组中的端口数量。一个端口最多对应一个 PHY因此最大端口数
等于 num_phys。因此结构中不再单独使用 num_ports 字段,
而仅使用 num_phys。
事件接口::
/* LLDD 调用以下函数来通知 SAS 类层发生事件 */
void sas_notify_port_event(struct sas_phy *, enum port_event, gfp_t);
void sas_notify_phy_event(struct sas_phy *, enum phy_event, gfp_t);
端口事件通知::
/* SAS 类层调用以下回调来通知 LLDD 端口事件 */
void (*lldd_port_formed)(struct sas_phy *);
void (*lldd_port_deformed)(struct sas_phy *);
如果 LLDD 希望在端口形成或解散时接收通知,则应将上述回调指针设
置为符合函数类型定义的处理函数。
SAS LLDD 还应至少实现 SCSI 协议中定义的一种任务管理函数TMFs::
/* 任务管理函数. 必须在进程上下文中调用 */
int (*lldd_abort_task)(struct sas_task *);
int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
int (*lldd_I_T_nexus_reset)(struct domain_device *);
int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
int (*lldd_query_task)(struct sas_task *);
如需更多信息,请参考 T10.org。
端口与适配器管理::
/* 端口与适配器管理 */
int (*lldd_clear_nexus_port)(struct sas_port *);
int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
SAS LLDD 至少应实现上述函数中的一个。
PHY 管理::
/* PHY 管理 */
int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
lldd_ha
- 应设置为指向驱动的主机适配器HA结构体的指针。如果 sas_ha_struct
被嵌入到更大的结构体中,也可以通过 container_of() 宏来获取。
一个示例的初始化与注册函数可以如下所示:(该函数应在 probe()
函数的最后调用)但必须在使能 PHY 执行 OOB 之前调用::
static int register_sas_ha(struct my_sas_ha *my_ha)
{
int i;
static struct sas_phy *sas_phys[MAX_PHYS];
static struct sas_port *sas_ports[MAX_PHYS];
my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
for (i = 0; i < MAX_PHYS; i++) {
sas_phys[i] = &my_ha->phys[i].sas_phy;
sas_ports[i] = &my_ha->sas_ports[i];
}
my_ha->sas_ha.sas_phy = sas_phys;
my_ha->sas_ha.sas_port = sas_ports;
my_ha->sas_ha.num_phys = MAX_PHYS;
my_ha->sas_ha.lldd_port_formed = my_port_formed;
my_ha->sas_ha.lldd_dev_found = my_dev_found;
my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
my_ha->sas_ha.lldd_execute_task = my_execute_task;
my_ha->sas_ha.lldd_abort_task = my_abort_task;
my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
my_ha->sas_ha.lldd_lu_reset = my_lu_reset;
my_ha->sas_ha.lldd_query_task = my_query_task;
my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
my_ha->sas_ha.lldd_control_phy = my_control_phy;
return sas_register_ha(&my_ha->sas_ha);
}
(2) SAS 1.1 未定义 I_T Nexus Reset TMF任务管理功能
事件
====
事件是 SAS LLDD 唯一的通知 SAS 层发生任何情况的方式。
LLDD 没有其他方法可以告知 SAS 层其内部或 SAS 域中发生的事件。
Phy 事件::
PHYE_LOSS_OF_SIGNAL, (C)
PHYE_OOB_DONE,
PHYE_OOB_ERROR, (C)
PHYE_SPINUP_HOLD.
端口事件,通过 _phy_ 传递::
PORTE_BYTES_DMAED, (M)
PORTE_BROADCAST_RCVD, (E)
PORTE_LINK_RESET_ERR, (C)
PORTE_TIMER_EVENT, (C)
PORTE_HARD_RESET.
主机适配器事件:
HAE_RESET
SAS LLDD 应能够生成以下事件::
- 来自 C 组的至少一个事件(可选),
- 标记为 M必需的事件为必需事件至少一种
- 若希望 SAS 层处理域重新验证domain revalidation
应生成标记为 E扩展器的事件仅需一种
- 未标记的事件为可选事件。
含义
HAE_RESET
- 当 HA 发生内部错误并被复位时。
PORTE_BYTES_DMAED
- 在接收到 IDENTIFY/FIS 帧时。
PORTE_BROADCAST_RCVD
- 在接收到一个原语时。
PORTE_LINK_RESET_ERR
- 定时器超时、信号丢失、丢失 DWS 等情况。 [1]_
PORTE_TIMER_EVENT
- DWS 复位超时定时器到期时。[1]_
PORTE_HARD_RESET
- 收到 Hard Reset 原语。
PHYE_LOSS_OF_SIGNAL
- 设备已断开连接。 [1]_
PHYE_OOB_DONE
- OOB 过程成功完成oob_mode 有效。
PHYE_OOB_ERROR
- 执行 OOB 过程中出现错误,设备可能已断开。 [1]_
PHYE_SPINUP_HOLD
- 检测到 SATA 设备,但未发送 COMWAKE 信号。
.. [1] 应设置或清除 phy 中相应的字段,或者从 tasklet 中调用
内联函数 sas_phy_disconnected(),该函数只是一个辅助函数。
执行命令 SCSI RPC::
int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
用于将任务排队提交给 SAS LLDD@task 为要执行的任务,@gfp_mask
为定义调用者上下文的 gfp 掩码。
此函数应实现 执行 SCSI RPC 命令。
也就是说,当调用 lldd_execute_task() 时,命令应当立即在传输
层发出。SAS LLDD 中在任何层级上都不应再进行队列排放。
返回值::
* 返回 -SAS_QUEUE_FULL 或 -ENOMEM 表示未排入队列;
* 返回 0 表示任务已成功排入队列。
::
struct sas_task {
dev —— 此任务目标设备;
task_proto —— 协议类型,为 enum sas_proto 中的一种;
scatter —— 指向散布/聚集SG列表数组的指针
num_scatter —— SG 列表元素数量;
total_xfer_len —— 预计传输的总字节数;
data_dir —— 数据传输方向(PCI_DMA_*)
task_done —— 任务执行完成时的回调函数。
};
发现
====
sysfs 树有以下用途::
a) 它显示当前时刻 SAS 域的物理布局,即展示当前物理世界中
域的实际结构。
b) 显示某些设备的参数。 _at_discovery_time_.
下面是一个指向 tree(1) 程序的链接,该工具在查看 SAS 域时非常
有用:
ftp://mama.indstate.edu/linux/tree/
我期望用户空间的应用程序最终能够为此创建一个图形界面。
也就是说sysfs 域树不会显示或保存某些状态变化,例如,如果你更
改了 READY LED 含义的设置sysfs 树不会反映这种状态变化;但它
确实会显示域设备的当前连接状态。
维护内部设备状态变化的职责由上层(命令集驱动)和用户空间负责。
当某个设备或多个设备从域中拔出时,这一变化会立即反映在 sysfs
树中,并且这些设备会从系统中移除。
结构体 domain_device 描述了 SAS 域中的任意设备。它完全由 SAS
层管理。一个任务会指向某个域设备SAS LLDD 就是通过这种方式知
道任务应发送到何处。SAS LLDD 只读取 domain_device 结构的内容,
但不会创建或销毁它。
用户空间中的扩展器管理
======================
在 sysfs 中的每个扩展器目录下,都有一个名为 "smp_portal" 的
文件。这是一个二进制的 sysfs 属性文件,它实现了一个 SMP 入口
(注意:这并不是一个 SMP 端口),用户空间程序可以通过它发送
SMP 请求并接收 SMP 响应。
该功能的实现方式看起来非常简单:
1. 构建要发送的 SMP 帧。其格式和布局在 SAS 规范中有说明。保持
CRC 字段为 0。
open(2)
2. 以读写模式打开该扩展器的 SMP portal sysfs 文件。
write(2)
3. 将第 1 步中构建的帧写入文件。
read(2)
4. 读取与所构建帧预期返回长度相同的数据量。如果读取的数据量与
预期不符,则表示发生了某种错误。
close(2)
整个过程在 "expander_conf.c" 文件中的函数 do_smp_func()
及其调用者中有详细展示。
对应的内核实现位于 "sas_expander.c" 文件中。
程序 "expander_conf.c" 实现了上述逻辑。它接收一个参数——扩展器
SMP portal 的 sysfs 文件名,并输出扩展器的信息,包括路由表内容。
SMP portal 赋予了你对扩展器的完全控制权,因此请谨慎操作。

View File

@ -31,16 +31,16 @@ SCSI内核参数
请查阅 drivers/scsi/advansys.c 文件头部。
aha152x= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/aha152x.rst。
请查阅 Documentation/scsi/aha152x.rst。
aha1542= [HW,SCSI]
格式:<portbase>[,<buson>,<busoff>[,<dmaspeed>]]
aic7xxx= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/aic7xxx.rst。
请查阅 Documentation/scsi/aic7xxx.rst。
aic79xx= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/aic79xx.rst。
请查阅 Documentation/scsi/aic79xx.rst。
atascsi= [HW,SCSI]
请查阅 drivers/scsi/atari_scsi.c。
@ -69,19 +69,19 @@ SCSI内核参数
请查阅 drivers/scsi/NCR_D700.c 文件头部。
ncr5380= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
请查阅 Documentation/scsi/g_NCR5380.rst。
ncr53c400= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
请查阅 Documentation/scsi/g_NCR5380.rst。
ncr53c400a= [HW,SCSI]
请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
请查阅 Documentation/scsi/g_NCR5380.rst。
ncr53c8xx= [HW,SCSI]
osst= [HW,SCSI] SCSI磁带驱动
格式:<buffer_size>,<write_threshold>
另请查阅 Documentation/translations/zh_CN/scsi/st.rst。
另请查阅 Documentation/scsi/st.rst。
scsi_debug_*= [SCSI]
请查阅 drivers/scsi/scsi_debug.c。
@ -112,7 +112,7 @@ SCSI内核参数
请查阅 drivers/scsi/sim710.c 文件头部。
st= [HW,SCSI] SCSI磁带参数缓冲区大小等
请查阅 Documentation/translations/zh_CN/scsi/st.rst。
请查阅 Documentation/scsi/st.rst。
wd33c93= [HW,SCSI]
请查阅 drivers/scsi/wd33c93.c 文件头部。

View File

@ -0,0 +1,35 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/scsi/libsas.rst
:翻译:
张钰杰 Yujie Zhang <yjzhang@leap-io-kernel.com>
:校译:
====================================================
Western Digital WD7193, WD7197 和 WD7296 SCSI 卡驱动
====================================================
这些卡需要加载固件。固件可从 WD 提供下载的 Windows NT 驱动程
序中提取。地址如下:
http://support.wdc.com/product/download.asp?groupid=801&sid=27&lang=en
该文件或网页上都未包含任何许可声明,因此该固件可能无法被收录到
linux-firmware 项目中。
提供的脚本可用于下载并提取固件,生成 wd719x-risc.bin 和
wd719x-wcs.bin 文件。请将它们放置在 /lib/firmware/ 目录下。
脚本内容如下:
#!/bin/sh
wget http://support.wdc.com/download/archive/pciscsi.exe
lha xi pciscsi.exe pci-scsi.exe
lha xi pci-scsi.exe nt/wd7296a.sys
rm pci-scsi.exe
dd if=wd7296a.sys of=wd719x-risc.bin bs=1 skip=5760 count=14336
dd if=wd7296a.sys of=wd719x-wcs.bin bs=1 skip=20096 count=514
rm wd7296a.sys

View File

@ -75,7 +75,6 @@ TODOList:
TODOList:
* block/index
* cdrom/index
* target/index