* [PATCH] docs/zh_CN: add translation of scsi subsystem
@ 2025-06-30 2:29 haodongdong
2025-06-30 3:03 ` Yanteng Si
0 siblings, 1 reply; 4+ messages in thread
From: haodongdong @ 2025-06-30 2:29 UTC (permalink / raw)
To: alexs, si.yanteng; +Cc: dzm91, corbet, linux-doc
This patch introduces the Chinese translation
of the following SCSI subsystem documentation
files:
../scsi/index.rst
../scsi/link_power_management_policy.rst
../scsi/scsi_eh.rst
../scsi/scsi_mid_low_api.rst
../scsi/scsi-parameters.rst
../scsi/scsi.rst
../scsi/sd-parameters.rst
Signed-off-by: haodongdong <doubled@leap-io.com>
---
.../translations/zh_CN/scsi/index.rst | 92 ++
.../scsi/link_power_management_policy.rst | 32 +
.../zh_CN/scsi/scsi-parameters.rst | 118 ++
.../translations/zh_CN/scsi/scsi.rst | 48 +
.../translations/zh_CN/scsi/scsi_eh.rst | 482 +++++++
.../zh_CN/scsi/scsi_mid_low_api.rst | 1174 +++++++++++++++++
.../translations/zh_CN/scsi/sd-parameters.rst | 38 +
.../translations/zh_CN/subsystem-apis.rst | 2 +-
8 files changed, 1985 insertions(+), 1 deletion(-)
create mode 100644 Documentation/translations/zh_CN/scsi/index.rst
create mode 100644 Documentation/translations/zh_CN/scsi/link_power_management_policy.rst
create mode 100644 Documentation/translations/zh_CN/scsi/scsi-parameters.rst
create mode 100644 Documentation/translations/zh_CN/scsi/scsi.rst
create mode 100644 Documentation/translations/zh_CN/scsi/scsi_eh.rst
create mode 100644 Documentation/translations/zh_CN/scsi/scsi_mid_low_api.rst
create mode 100644 Documentation/translations/zh_CN/scsi/sd-parameters.rst
diff --git a/Documentation/translations/zh_CN/scsi/index.rst b/Documentation/translations/zh_CN/scsi/index.rst
new file mode 100644
index 000000000000..0ee76039118b
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/index.rst
@@ -0,0 +1,92 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/index.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+==========
+SCSI子系统
+==========
+
+.. toctree::
+ :maxdepth: 1
+
+简介
+====
+
+.. toctree::
+ :maxdepth: 1
+
+ scsi
+
+SCSI驱动接口
+============
+
+.. toctree::
+ :maxdepth: 1
+
+ scsi_mid_low_api
+ scsi_eh
+
+SCSI驱动参数
+============
+
+.. toctree::
+ :maxdepth: 1
+
+ scsi-parameters
+ link_power_management_policy
+
+SCSI主机适配器驱动
+==================
+
+.. toctree::
+ :maxdepth: 1
+
+ sd-parameters
+
+Todolist:
+
+* 53c700
+* aacraid
+* advansys
+* aha152x
+* aic79xx
+* aic7xxx
+* arcmsr_spec
+* bfa
+* bnx2fc
+* BusLogic
+* cxgb3i
+* dc395x
+* dpti
+* FlashPoint
+* g_NCR5380
+* hpsa
+* hptiop
+* libsas
+* lpfc
+* megaraid
+* ncr53c8xx
+* NinjaSCSI
+* ppa
+* qlogicfas
+* scsi-changer
+* scsi_fc_transport
+* scsi-generic
+* smartpqi
+* st
+* sym53c500_cs
+* sym53c8xx_2
+* tcm_qla2xxx
+* ufs
+* wd719x
+
+* scsi_transport_srp/figures
diff --git a/Documentation/translations/zh_CN/scsi/link_power_management_policy.rst b/Documentation/translations/zh_CN/scsi/link_power_management_policy.rst
new file mode 100644
index 000000000000..67382a6a9b5f
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/link_power_management_policy.rst
@@ -0,0 +1,32 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/link_power_management_policy.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+================
+链路电源管理策略
+================
+
+该参数允许用户设置链路(接口)的电源管理模式。
+共计三类可选项:
+
+===================== =====================================================
+选项 作用
+===================== =====================================================
+min_power 指示控制器在可能的情况下尽量使链路处于最低功耗。
+ 这可能会牺牲一定的性能,因为从低功耗状态恢复时会增加延迟。
+
+max_performance 通常,这意味着不进行电源管理。指示
+ 控制器优先考虑性能而非电源管理。
+
+medium_power 指示控制器在可能的情况下进入较低功耗状态,
+ 而非最低功耗状态,从而改善min_power模式下的延迟。
+===================== =====================================================
\ No newline at end of file
diff --git a/Documentation/translations/zh_CN/scsi/scsi-parameters.rst b/Documentation/translations/zh_CN/scsi/scsi-parameters.rst
new file mode 100644
index 000000000000..7fb4dfee4ac3
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/scsi-parameters.rst
@@ -0,0 +1,118 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/scsi-parameters.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+============
+SCSI内核参数
+============
+
+请查阅Documentation/admin-guide/kernel-parameters.rst以获取
+指定模块参数相关的通用信息。
+
+当前文档可能不完全是最新和全面的。命令 ``modinfo -p ${modulename}``
+显示了可加载模块的参数列表。可加载模块被加载到内核中后,也会在
+/sys/module/${modulename}/parameters/ 目录下显示其参数。其
+中某些参数可以通过命令
+``echo -n ${value} > /sys/module/${modulename}/parameters/${parm}``
+在运行时修改。
+
+::
+
+ advansys= [HW,SCSI]
+ 请查阅 drivers/scsi/advansys.c 文件头部。
+
+ aha152x= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/aha152x.rst。
+
+ aha1542= [HW,SCSI]
+ 格式:<portbase>[,<buson>,<busoff>[,<dmaspeed>]]
+
+ aic7xxx= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/aic7xxx.rst。
+
+ aic79xx= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/aic79xx.rst。
+
+ atascsi= [HW,SCSI]
+ 请查阅 drivers/scsi/atari_scsi.c。
+
+ BusLogic= [HW,SCSI]
+ 请查阅 drivers/scsi/BusLogic.c 文件中
+ BusLogic_ParseDriverOptions()函数前的注释。
+
+ gvp11= [HW,SCSI]
+
+ ips= [HW,SCSI] Adaptec / IBM ServeRAID 控制器
+ 请查阅 drivers/scsi/ips.c 文件头部。
+
+ mac5380= [HW,SCSI]
+ 请查阅 drivers/scsi/mac_scsi.c。
+
+ scsi_mod.max_luns=
+ [SCSI] 最大可探测LUN数。
+ 取值范围为 1 到 2^32-1。
+
+ scsi_mod.max_report_luns=
+ [SCSI] 接收到的最大LUN数。
+ 取值范围为 1 到 16384。
+
+ NCR_D700= [HW,SCSI]
+ 请查阅 drivers/scsi/NCR_D700.c 文件头部。
+
+ ncr5380= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
+
+ ncr53c400= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
+
+ ncr53c400a= [HW,SCSI]
+ 请查阅 Documentation/translations/zh_CN/scsi/g_NCR5380.rst。
+
+ ncr53c8xx= [HW,SCSI]
+
+ osst= [HW,SCSI] SCSI磁带驱动
+ 格式:<buffer_size>,<write_threshold>
+ 另请查阅 Documentation/translations/zh_CN/scsi/st.rst。
+
+ scsi_debug_*= [SCSI]
+ 请查阅 drivers/scsi/scsi_debug.c。
+
+ scsi_mod.default_dev_flags=
+ [SCSI] SCSI默认设备标志
+ 格式:<integer>
+
+ scsi_mod.dev_flags=
+ [SCSI] 厂商和型号的黑/白名单条目
+ 格式:<vendor>:<model>:<flags>
+ (flags 为整数值)
+
+ scsi_mod.scsi_logging_level=
+ [SCSI] 日志级别的位掩码
+ 位的定义请查阅 drivers/scsi/scsi_logging.h。
+ 此参数也可以通过sysctl对dev.scsi.logging_level
+ 进行设置(/proc/sys/dev/scsi/logging_level)。
+ 此外,S390-tools软件包提供了一个便捷的
+ ‘scsi_logging_level’ 脚本,可以从以下地址下载:
+ https://github.com/ibm-s390-linux/s390-tools/blob/master/scripts/scsi_logging_level
+
+ scsi_mod.scan= [SCSI] sync(默认)在发现SCSI总线过程中
+ 同步扫描。async在内核线程中异步扫描,允许系统继续
+ 启动流程。none忽略扫描,预期由用户空间完成扫描。
+
+ sim710= [SCSI,HW]
+ 请查阅 drivers/scsi/sim710.c 文件头部。
+
+ st= [HW,SCSI] SCSI磁带参数(缓冲区大小等)
+ 请查阅 Documentation/translations/zh_CN/scsi/st.rst。
+
+ wd33c93= [HW,SCSI]
+ 请查阅 drivers/scsi/wd33c93.c 文件头部。
diff --git a/Documentation/translations/zh_CN/scsi/scsi.rst b/Documentation/translations/zh_CN/scsi/scsi.rst
new file mode 100644
index 000000000000..874ad34ae8aa
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/scsi.rst
@@ -0,0 +1,48 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/scsi.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+==============
+SCSI子系统文档
+==============
+
+Linux文档项目(LDP)维护了一份描述Linux内核(lk) 2.4中SCSI
+子系统的文档。请参考:
+https://www.tldp.org/HOWTO/SCSI-2.4-HOWTO 。LDP提供单页和
+多页的HTML版本,以及PostScript与PDF格式的文档。
+
+在SCSI子系统中使用模块的注意事项
+================================
+Linux内核中的SCSI支持可以根据终端用户的需求以不同的方式模块
+化。为了理解你的选择,我们首先需要定义一些术语。
+
+scsi-core(也被称为“中间层”)包含SCSI支持的核心。没有他你将
+无法使用任何其他SCSI驱动程序。SCSI核心支持可以是一个模块(
+scsi_mod.o),也可以编译进内核。如果SCSI核心是一个模块,那么
+他必须是第一个被加载的SCSI模块,如果你将卸载该模块,那么他必
+须是最后一个被卸载的模块。实际上,modprobe和rmmod命令将确保
+SCSI子系统中模块加载与卸载的正确顺序。
+
+一旦SCSI核心存在于内核中(无论是编译进内核还是作为模块加载),
+独立的上层驱动和底层驱动可以按照任意顺序加载。磁盘驱动程序
+(sd_mod.o)、光盘驱动程序(sr_mod.o)、磁带驱动程序 [1]_
+(st.o)以及SCSI通用驱动程序(sg.o)代表了上层驱动,用于控制
+相应的各种设备。例如,你可以加载磁带驱动程序来使用磁带驱动器,
+然后在不需要该驱动程序时卸载他(并释放相关内存)。
+
+底层驱动程序用于支持您所运行硬件平台支持的不同主机卡。这些不同
+的主机卡通常被称为主机总线适配器(HBAs)。例如,aic7xxx.o驱动
+程序被用于控制Adaptec所属的所有最新的SCSI控制器。几乎所有的底
+层驱动都可以被编译为模块或直接编译进内核。
+
+.. [1] 磁带驱动程序有一个变种用于控制OnStream磁带设备。其模块
+ 名称为osst.o 。
\ No newline at end of file
diff --git a/Documentation/translations/zh_CN/scsi/scsi_eh.rst b/Documentation/translations/zh_CN/scsi/scsi_eh.rst
new file mode 100644
index 000000000000..60649a2497b2
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/scsi_eh.rst
@@ -0,0 +1,482 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/scsi_eh.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+===================
+SCSI 中间层错误处理
+===================
+
+本文档描述了SCSI中间层(mid layer)的错误处理基础架构。
+关于SCSI中间层的更多信息,请参阅:
+Documentation/scsi/scsi_mid_low_api.rst。
+
+.. 目录
+
+ [1] SCSI 命令如何通过中间层传递并进入错误处理(EH)
+ [1-1] scsi_cmnd(SCSI命令)结构体
+ [1-2] scmd(SCSI 命令)是如何完成的?
+ [1-2-1] 通过scsi_done完成scmd
+ [1-2-2] 通过超时机制完成scmd
+ [1-3] 错误处理模块如何接管流程
+ [2] SCSI错误处理机制工作原理
+ [2-1] 基于细粒度回调的错误处理
+ [2-1-1] 概览
+ [2-1-2] scmd在错误处理流程中的传递路径
+ [2-1-3] 控制流分析
+ [2-2] 通过transportt->eh_strategy_handler()实现的错误处理
+ [2-2-1] transportt->eh_strategy_handler()调用前的中间层状态
+ [2-2-2] transportt->eh_strategy_handler()调用后的中间层状态
+ [2-2-3] 注意事项
+
+
+1. SCSI命令在中间层及错误处理中的传递流程
+=========================================
+
+1.1 scsi_cmnd结构体
+-------------------
+
+每个SCSI命令都由struct scsi_cmnd(简称scmd)结构体
+表示。scmd包含两个list_head类型的链表节点:scmd->list
+与scmd->eh_entry。其中scmd->list是用于空闲链表或设备
+专属的scmd分配链表,与错误处理讨论关联不大。而
+scmd->eh_entry则是专用于命令完成和错误处理链表,除非
+特别说明,本文讨论中所有scmd的链表操作均通过
+scmd->eh_entry实现。
+
+
+1.2 scmd是如何完成的?
+----------------------
+
+底层设备驱动(LLDD)在获取SCSI命令(scmd)后,存在两种
+完成路径:底层驱动可通过调用hostt->queuecommand()时从
+中间层传递的scsi_done回调函数主动完成命令,或者当命令未
+及时完成时由块层(block layer)触发超时处理机制。
+
+
+1.2.1 通过scsi_done回调完成SCSI命令
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+对于所有非错误处理(EH)命令,scsi_done()是其完成回调
+函数。它只调用blk_mq_complete_request()来删除块层的
+定时器并触发块设备软中断(BLOCK_SOFTIRQ)。
+
+BLOCK_SOFTIRQ会间接调用scsi_complete(),进而调用
+scsi_decide_disposition()来决定如何处理该命令。
+scsi_decide_disposition()会查看scmd->result值和感
+应码数据来决定如何处理命令。
+
+ - SUCCESS
+
+ 调用scsi_finish_command()来处理该命令。该函数会
+ 执行一些维护操作,然后调用scsi_io_completion()来
+ 完成I/O操作。scsi_io_completion()会通过调用
+ blk_end_request及其相关函数来通知块层该请求已完成,
+ 如果发生错误,还会判断如何处理剩余的数据。
+
+ - NEEDS_RETRY
+
+ - ADD_TO_MLQUEUE
+
+ scmd被重新加入到块设备队列中。
+
+ - otherwise
+
+ 调用scsi_eh_scmd_add(scmd)来处理该命令。
+ 关于此函数的详细信息,请参见 [1-3]。
+
+
+1.2.2 scmd超时完成机制
+^^^^^^^^^^^^^^^^^^^^^^
+
+SCSI命令超时处理机制由scsi_timeout()函数实现。
+当发生超时事件时,该函数
+
+ 1. 首先调用可选的hostt->eh_timed_out()回调函数。
+ 返回值可能是以下3种情况之一:
+
+ - ``SCSI_EH_RESET_TIMER``
+ 表示需要延长命令执行时间并重启计时器。
+
+ - ``SCSI_EH_NOT_HANDLED``
+ 表示eh_timed_out()未处理该命令。
+ 此时将执行第2步的处理流程。
+
+ - ``SCSI_EH_DONE``
+ 表示eh_timed_out()已完成该命令。
+
+ 2. 若未通过回调函数解决,系统将调用
+ scsi_abort_command()发起异步中止操作,该操作最多
+ 可执行scmd->allowed + 1次。但存在三种例外情况会跳
+ 过异步中止而直接进入第3步处理:当检测到
+ SCSI_EH_ABORT_SCHEDULED标志位已置位(表明该命令先
+ 前已被中止过一次且当前重试仍失败)、当重试次数已达上
+ 限、或当错误处理时限已到期时。在这些情况下,系统将跳
+ 过异步中止流程而直接执行第3步处理方案。
+
+ 3. 最终未解决的命令会通过scsi_eh_scmd_add(scmd)移交给
+ 错误处理子系统,具体流程详见[1-4]章节说明。
+
+1.3 异步命令中止机制
+--------------------
+
+当命令超时触发后,系统会通过scsi_abort_command()调度异
+步中止操作。若中止操作执行成功,则根据重试次数决定后续处
+理:若未达最大重试限制,命令将重新下发执行;若重试次数已
+耗尽,则命令最终以DID_TIME_OUT状态终止。当中止操作失败
+时,系统会调用scsi_eh_scmd_add()将该命令移交错误处理子
+系统,具体处理流程详见[1-4]。
+
+1.4 错误处理(EH)接管机制
+------------------------
+
+SCSI命令通过scsi_eh_scmd_add()函数进入错误处理流程,该函
+数执行以下操作:
+
+ 1. 将scmd->eh_entry链接到shost->eh_cmd_q
+
+ 2. 在shost->shost_state中设置SHOST_RECOVERY状态位
+
+ 3. 递增shost->host_failed失败计数器
+
+ 4. 当检测到shost->host_busy == shost->host_failed
+ 时(即所有进行中命令均已失败)立即唤醒SCSI错误处理
+ 线程。
+
+如上所述,当任一scmd被加入到shost->eh_cmd_q队列时,系统
+会立即置位shost_state中的SHOST_RECOVERY状态标志位,该操
+作将阻止块层向对应主机控制器下发任何新的SCSI命令。在此状
+态下,主机控制器上所有正在处理的scmd最终会进入以下三种状
+态之一:正常完成、失败后被移入到eh_cmd_q队列、或因超时被
+添加到shost->eh_cmd_q队列。
+
+如果所有的SCSI命令都已经完成或失败,系统中正在执行的命令
+数量与失败命令数量相等(
+即shost->host_busy == shost->host_failed),此时将唤
+醒SCSI错误处理线程。SCSI错误处理线程一旦被唤醒,就可以确
+保所有未完成命令均已标记为失败状态,并且已经被链接到
+shost->eh_cmd_q队列中。
+
+需要特别说明的是,这并不意味着底层处理流程完全静止。当底层
+驱动以错误状态完成某个scmd时,底层驱动及其下层组件会立刻遗
+忘该命令的所有关联状态。但对于超时命令,除非
+hostt->eh_timed_out()回调函数已经明确通知底层驱动丢弃该
+命令(当前所有底层驱动均未实现此功能),否则从底层驱动视角
+看该命令仍处于活跃状态,理论上仍可能在某时刻完成。当然,由
+于超时计时器早已触发,所有此类延迟完成都将被系统直接忽略。
+
+我们将在后续章节详细讨论关于SCSI错误处理如何执行中止操作(
+即强制底层驱动丢弃已超时SCSI命令)。
+
+
+2. SCSI错误处理机制详解
+=======================
+
+SCSI底层驱动可以通过以下两种方式之一来实现SCSI错误处理。
+
+ - 细粒度的错误处理回调机制
+ 底层驱动可选择实现细粒度的错误处理回调函数,由SCSI中间层
+ 主导错误恢复流程并自动调用对应的回调函数。此实现模式的详
+ 细设计规范在[2-1]节中展开讨论。
+
+ - eh_strategy_handler()回调函数
+ 该回调函数作为统一的错误处理入口,需要完整实现所有的恢复
+ 操作。具体而言,它必须涵盖SCSI中间层在常规恢复过程中执行
+ 的全部处理流程,相关实现将在[2-2]节中详细描述。
+
+当错误恢复流程完成后,SCSI错误处理系统通过调用
+scsi_restart_operations()函数恢复正常运行,该函数按顺序执行
+以下操作:
+
+ 1. 验证是否需要执行驱动器安全门锁定机制
+
+ 2. 清除shost_state中的SHOST_RECOVERY状态标志位
+
+ 3. 唤醒所有在shost->host_wait上等待的任务。如果有人调用了
+ scsi_block_when_processing_errors()则会发生这种情况。
+ (疑问:由于错误处理期间块层队列已被阻塞,为何仍需显式
+ 唤醒?)
+
+ 4. 强制激活该主机控制器下所有设备的I/O队列
+
+
+2.1 基于细粒度回调的错误处理机制
+--------------------------------
+
+2.1.1 概述
+^^^^^^^^^^^
+
+如果不存在eh_strategy_handler(),SCSI中间层将负责驱动的
+错误处理。错误处理(EH)的目标有两个:一是让底层驱动程序、
+主机和设备不再维护已超时的SCSI命令(scmd);二是使他们准备
+好接收新命令。当一个SCSI命令(scmd)被底层遗忘且底层已准备
+好再次处理或拒绝该命令时,即可认为该scmd已恢复。
+
+为实现这些目标,错误处理(EH)会逐步执行严重性递增的恢复
+操作。部分操作通过下发SCSI命令完成,而其他操作则通过调用
+以下细粒度的错误处理回调函数实现。这些回调函数可以省略,
+若被省略则默认始终视为执行失败。
+
+::
+
+ int (* eh_abort_handler)(struct scsi_cmnd *);
+ int (* eh_device_reset_handler)(struct scsi_cmnd *);
+ int (* eh_bus_reset_handler)(struct scsi_cmnd *);
+ int (* eh_host_reset_handler)(struct scsi_cmnd *);
+
+只有在低级别的错误恢复操作无法恢复部分失败的SCSI命令
+(scmd)时,才会采取更高级别的恢复操作。如果最高级别的错误
+处理失败,就意味着整个错误恢复(EH)过程失败,所有未能恢复
+的设备被强制下线。
+
+在恢复过程中,需遵循以下规则:
+
+ - 错误恢复操作针对待处理列表eh_work_q中的失败的scmds执
+ 行。如果某个恢复操作成功恢复了一个scmd,那么该scmd会
+ 从eh_work_q链表中移除。
+
+ 需要注意的是,对某个scmd执行的单个恢复操作可能会恢复
+ 多个scmd。例如,对某个设备执行复位操作可能会恢复该设
+ 备上所有失败的scmd。
+
+ - 仅当低级别的恢复操作完成且eh_work_q仍然非空时,才会
+ 触发更高级别的操作
+
+ - SCSI错误恢复机制会重用失败的scmd来发送恢复命令。对于
+ 超时的scmd,SCSI错误处理机制会确保底层驱动在重用scmd
+ 前已不再维护该命令。
+
+当一个SCSI命令(scmd)被成功恢复后,错误处理逻辑会通过
+scsi_eh_finish_cmd()将其从待处理队列(eh_work_q)移
+至错误处理的本地完成队列(eh_done_q)。当所有scmd均恢
+复完成(即eh_work_q为空时),错误处理逻辑会调用
+scsi_eh_flush_done_q()对这些已恢复的scmd进行处理,即
+重新尝试或错误总终止(向上层通知失败)。
+
+SCSI命令仅在满足以下全部条件时才会被重试:对应的SCSI设
+备仍处于在线状态,未设置REQ_FAILFAST标志或递增后的
+scmd->retries值仍小于scmd->allowed。
+
+2.1.2 SCSI命令在错误处理过程中的流转路径
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ 1. 错误完成/超时
+
+ :处理: 调用scsi_eh_scmd_add()处理scmd
+
+ - 将scmd添加到shost->eh_cmd_q
+ - 设置SHOST_RECOVERY标记位
+ - shost->host_failed++
+
+ :锁要求: shost->host_lock
+
+ 2. 启动错误处理(EH)
+
+ :操作: 将所有scmd移动到EH本地eh_work_q队列,并
+ 清空 shost->eh_cmd_q。
+
+ :锁要求: shost->host_lock(非严格必需,仅为保持一致性)
+
+ 3. scmd恢复
+
+ :操作: 调用scsi_eh_finish_cmd()完成scmd的EH
+
+ - 将scmd从本地eh_work_q队列移至本地eh_done_q队列
+
+ :锁要求: 无
+
+ :并发控制: 每个独立的eh_work_q至多一个线程,确保无锁
+ 队列的访问
+
+ 4. EH完成
+
+ :操作: 调用scsi_eh_flush_done_q()重试scmd或通知上层处理
+ 失败。此函数可以被并发调用,但每个独立的eh_work_q队
+ 列至多一个线程,以确保无锁队列的访问。
+
+ - 从eh_done_q队列中移除scmd,清除scmd->eh_entry
+ - 如果需要重试,调用scsi_queue_insert()重新入队scmd
+ - 否则,调用scsi_finish_command()完成scmd
+ - 将shost->host_failed置为零
+
+ :锁要求: 队列或完成函数会执行适当的加锁操作
+
+
+2.1.3 控制流
+^^^^^^^^^^^^
+
+ 通过细粒度回调机制执行的SCSI错误处理(EH)是从
+ scsi_unjam_host()函数开始的
+
+``scsi_unjam_host``
+
+ 1. 持有shost->host_lock锁,将shost->eh_cmd_q中的命令移动
+ 到本地的eh_work_q队里中,并释放host_lock锁。注意,这一步
+ 会清空shost->eh_cmd_q。
+
+ 2. 调用scsi_eh_get_sense函数。
+
+ ``scsi_eh_get_sense``
+
+ 该操作针对没有有效感知数据的错误完成命令。大部分SCSI传输协议
+ 或底层驱动在命令失败时会自动获取感知数据(自动感知)。出于性
+ 能原因,建议使用自动感知,推荐使用自动感知机制,因为它不仅有
+ 助于提升性能,还能避免从发生CHECK CONDITION到执行本操作之间,
+ 感知信息出现不同步的问题。
+
+ 注意,如果不支持自动感知,那么在使用scsi_done()以错误状态完成
+ scmd 时,scmd->sense_buffer将包含无效感知数据。在这种情况下,
+ scsi_decide_disposition()总是返回FAILED从而触发SCSI错误处理
+ (EH)。当该scmd执行到这里时,会重新获取感知数据,并再次调用
+ scsi_decide_disposition()进行处理。
+
+ 1. 调用scsi_request_sense()发送REQUEST_SENSE命令。如果失败,
+ 则不采取任何操作。请注意,不采取任何操作会导致对该scmd执行
+ 更高级别的恢复操作。
+
+ 2. 调用scsi_decide_disposition()处理scmd
+
+ - SUCCESS
+ scmd->retries被设置为scmd->allowed以防止
+ scsi_eh_flush_done_q()重试该scmd,并调用
+ scsi_eh_finish_cmd()。
+
+ - NEEDS_RETRY
+ 调用scsi_eh_finish_cmd()
+
+ - 其他情况
+ 无操作。
+
+ 4. 如果!list_empty(&eh_work_q),则调用scsi_eh_ready_devs()。
+
+ ``scsi_eh_ready_devs``
+
+ 该函数采取四种逐步增强的措施,使失败的设备准备好处理新的命令。
+
+ 1. 调用scsi_eh_stu()
+
+ ``scsi_eh_stu``
+
+ 对于每个具有有效感知数据且scsi_check_sense()判断为失败的
+ scmd发送START STOP UNIT(STU)命令且将start置1。注意,由
+ 于我们明确选择错误完成的scmd,可以确定底层驱动已不再维护该
+ scmd,我们可以重用它进行STU。
+
+ 如果STU操作成功且sdev处于离线或就绪状态,所有在sdev上失败的
+ scmd都会通过scsi_eh_finish_cmd()完成。
+
+ *注意* 如果hostt->eh_abort_handler()未实现或返回失败,可能
+ 此时仍有超时的scmd,此时STU不会导致底层驱动不再维护scmd。但
+ 是,如果STU执行成功,该函数会通过scsi_eh_finish_cmd()来完成
+ sdev上的所有scmd,这会导致底层驱动处于不一致的状态。看来STU
+ 操作应仅在sdev不包含超时scmd时进行。
+
+ 2. 如果!list_empty(&eh_work_q),调用scsi_eh_bus_device_reset()。
+
+ ``scsi_eh_bus_device_reset``
+
+ 此操作与scsi_eh_stu()非常相似,区别在于使用
+ hostt->eh_device_reset_handler()替代STU命令。此外,由于我们
+ 没有发送SCSI命令且重置会清空该sdev上所有的scmd,所以无需筛选错
+ 误完成的scmd。
+
+ 3. 如果!list_empty(&eh_work_q),调用scsi_eh_bus_reset()。
+
+ ``scsi_eh_bus_reset``
+
+ 对于每个包含失败scmd的SCSI通道调用
+ hostt->eh_bus_reset_handler()。如果总线重置成功,那么该通道上
+ 所有准备就绪或离线状态sdev上的失败scmd都会被处理处理完成。
+
+ 4. 如果!list_empty(&eh_work_q),调用scsi_eh_host_reset()。
+
+ ``scsi_eh_host_reset``
+
+ 调用hostt->eh_host_reset_handler()是最终的手段。如果SCSI主机
+ 重置成功,主机上所有就绪或离线sdev上的失败scmd都会通过错误处理
+ 完成。
+
+ 5. 如果!list_empty(&eh_work_q),调用scsi_eh_offline_sdevs()。
+
+ ``scsi_eh_offline_sdevs``
+
+ 离线所有包含未恢复scmd的所有sdev,并通过
+ scsi_eh_finish_cmd()完成这些scmd。
+
+ 5. 调用scsi_eh_flush_done_q()。
+
+ ``scsi_eh_flush_done_q``
+
+ 此时所有的scmd都已经恢复(或放弃),并通过
+ scsi_eh_finish_cmd()函数加入eh_done_q队列。该函数通过
+ 重试或显示通知上层scmd的失败来刷新eh_done_q。
+
+
+2.2 基于transportt->eh_strategy_handler()的错误处理机制
+-------------------------------------------------------------
+
+在该机制中,transportt->eh_strategy_handler()替代
+scsi_unjam_host()的被调用,并负责整个错误恢复过程。该处理
+函数完成后应该确保底层驱动不再维护任何失败的scmd并且将设备
+设置为就绪(准备接收新命令)或离线状态。此外,该函数还应该
+执行SCSI错误处理的维护任务,以维护SCSI中间层的数据完整性。
+换句话说,eh_strategy_handler()必须实现[2-1-2]中除第1步
+外的所有步骤。
+
+
+2.2.1 transportt->eh_strategy_handler()调用前的SCSI中间层状态
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ 进入该处理函数时,以下条件成立。
+
+ - 每个失败的scmd的eh_flags字段已正确设置。
+
+ - 每个失败的scmd通过scmd->eh_entry链接到scmd->eh_cmd_q队列。
+
+ - 已设置SHOST_RECOVERY标志。
+
+ - `shost->host_failed == shost->host_busy`。
+
+2.2.2 transportt->eh_strategy_handler()调用后的SCSI中间层状态
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ 从该处理函数退出时,以下条件成立。
+
+ - shost->host_failed为零。
+
+ - shost->eh_cmd_q被清空。
+
+ - 每个scmd->eh_entry被清空。
+
+ - 对每个scmd必须调用scsi_queue_insert()或scsi_finish_command()。
+ 注意,该处理程序可以使用scmd->retries(剩余重试次数)和
+ scmd->allowed(允许重试次数)限制重试次数。
+
+
+2.2.3 注意事项
+^^^^^^^^^^^^^^
+
+ - 需明确已超时的scmd在底层仍处于活跃状态,因此在操作这些
+ scmd前,必须确保底层已彻底不再维护。
+
+ - 访问或修改shost数据结构时,必须持有shost->host_lock锁
+ 以维持数据一致性。
+
+ - 错误处理完成后,每个故障设备必须彻底清除所有活跃SCSI命
+ 令(scmd)的关联状态。
+
+ - 错误处理完成后,每个故障设备必须被设置为就绪(准备接收
+ 新命令)或离线状态。
+
+
+Tejun Heo
+htejun@gmail.com
+
+11th September 2005
diff --git a/Documentation/translations/zh_CN/scsi/scsi_mid_low_api.rst b/Documentation/translations/zh_CN/scsi/scsi_mid_low_api.rst
new file mode 100644
index 000000000000..cedd90b3fec1
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/scsi_mid_low_api.rst
@@ -0,0 +1,1174 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/scsi_mid_low_api.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+=========================
+SCSI中间层 — 底层驱动接口
+=========================
+
+简介
+====
+本文档概述了Linux SCSI中间层与SCSI底层驱动之间的接口。底层
+驱动(LLD)通常被称为主机总线适配器(HBA)驱动或主机驱动
+(HD)。在该上下文中,“主机”指的是计算机IO总线(例如:PCI总
+线或ISA总线)与SCSI传输层中单个SCSI启动器端口之间的桥梁。
+“启动器”端口(SCSI术语,参考SAM-3:http://www.t10.org)向
+“目标”SCSI端口(例如:磁盘)发送SCSI命令。在一个运行的系统
+中存在多种底层驱动(LLDs),但每种硬件类型仅对应一种底层驱动
+(LLD)。大多数底层驱动可以控制一个或多个SCSI HBA。部分HBA
+内部集成多个主机控制器。
+
+在某些情况下,SCSI传输层本身是已存在于Linux中的外部总线子系
+统(例如:USB和ieee1394)。在此类场景下,SCSI子系统的底层驱
+动将作为与其他驱动子系统的软件桥接层。典型示例包括
+usb-storage驱动(位于drivers/usb/storage目录)以
+及ieee1394/sbp2驱动(位于 drivers/ieee1394 目录)。
+
+例如,aic7xxx底层驱动负责控制基于Adaptec公司7xxx芯片系列的
+SCSI并行接口(SPI)控制器。aic7xxx底层驱动可以内建到内核中
+或作为模块加载。一个Linux系统中只能运行一个aic7xxx底层驱动
+程序,但他可能控制多个主机总线适配器(HBA)。这些HBA可能位于
+PCI扩展卡或内置于主板中(或两者兼有)。某些基于aic7xxx的HBA
+采用双控制器设计,因此会呈现为两个SCSI主机适配器。与大多数现
+代HBA相同,每个aic7xxx控制器都拥有其独立的PCI设备地址。[SCSI
+主机与PCI设备之间一一对应虽然常见,但并非强制要求(例如ISA适
+配器就不适用此规则)。]
+
+SCSI中间层将SCSI底层驱动(LLD)与其他层(例如SCSI上层驱动以
+及块层)隔离开来。
+
+本文档的版本大致与Linux内核2.6.8相匹配。
+
+文档
+====
+内核源码树中设有专用的SCSI文档目录,通常位于
+Documentation/scsi目录下。大多数文档采用
+reStructuredText格式。本文档名为
+scsi_mid_low_api.rst,可在该目录中找到。该文档的最新版本可
+以访问 https://docs.kernel.org/scsi/scsi_mid_low_api.html
+查阅。许多底层驱动(LLD)的文档也位于Documentation/scsi目录
+下(例如aic7xxx.rst)。SCSI中间层的简要说明见scsi.rst文件,
+该文档包含指向Linux Kernel 2.4系列SCSI子系统的文档链接。此
+外还收录了两份SCSI上层驱动文档:st.rst(SCSI磁带驱动)与
+scsi-generic.rst(用通用SCSI(sg)驱动)。
+
+部分底层驱动的文档(或相关URL)可能嵌在C源代码文件或与其
+源码同位于同一目录下。例如,USB大容量存储驱动的文档链接可以在
+目录/usr/src/linux/drivers/usb/storage下找到。
+
+驱动程序结构
+============
+传统上,SCSI子系统的底层驱动(LLD)至少包含drivers/scsi
+目录下的两个文件。例如,一个名为“xyz”的驱动会包含一个头文件
+xyz.h和一个源文件xyz.c。[实际上所有代码完全可以合并为单个
+文件,头文件并非必需的。] 部分需要跨操作系统移植的底层驱动会
+采用更复杂的文件结构。例如,aic7xxx驱动,就为通用代码与操作
+系统专用代码(如FreeBSD和Linux)分别创建了独立的文件。此类
+驱动通常会在drivers/scsi目录下拥有自己单独的子目录。
+
+当需要向Linux内核添加新的底层驱动(LLD)时,必须留意
+drivers/scsi目录下的两个文件:Makefile以及Kconfig。建议参
+考现有底层驱动的代码组织方式。
+
+随着Linux内核2.5开发内核逐步演进为2.6系列的生产版本,该接口
+也引入了一些变化。以驱动初始化代码为例,现有两种模型可用。其
+中旧模型与Linux内核2.4的实现相似,他基于在加载HBA驱动时检测
+到的主机,被称为“被动(passive)”初始化模型。而新的模型允许
+在底层驱动(LLD)的生命周期内动态拔插HBA,这种方式被称为“热
+插拔(hotplug)”初始化模型。推荐使用新的模型,因为他既能处理
+传统的永久连接SCSI设备,也能处理现代支持热插拔的类SCSI设备
+(例如通过USB或IEEE 1394连接的数码相机)。这两种初始化模型将
+在后续的章节中分别讨论。
+
+SCSI底层驱动(LLD)通过以下3种方式与SCSI子系统进行交互:
+
+ a) 直接调用由SCSI中间层提供的接口函数
+ b) 将一组函数指针传递给中间层提供的注册函数,中间层将在
+ 后续运行的某个时刻调用这些函数。这些函数由LLD实现。
+ c) 直接访问中间层维护的核心数据结构
+
+a)组中所涉及的所有函数,均列于下文“中间层提供的函数”章节中。
+
+b)组中涉及的所有函数均列于下文名为“接口函数”的章节中。这些
+函数指针位于结构体struct scsi_host_template中,该结构体实
+例会被传递给scsi_host_alloc()。对于LLD未实现的接口函数,应
+对struct scsi_host_template中的对应成员赋NULL。如果在文件
+作用域定义一个struct scsi_host_template的实例,没有显式初
+始化的函数指针成员将自动设置为NULL。
+
+c)组中提到的用法在“热插拔”环境中尤其需要谨慎处理。LLD必须
+明确知晓这些与中间层及其他层级共享的数据结构的生命周期。
+
+LLD中定义的所有函数以及在文件作用域内定义的所有数据都应声明
+为static。例如,在一个名为“xxx”的LLD中的sdev_init()函数定
+义如下:
+``static int xxx_sdev_init(struct scsi_device * sdev) { /* code */ }``
+
+热插拔初始化模型
+================
+在该模型中,底层驱动(LLD)控制SCSI主机适配器在子系统中的注
+册与注销时机。主机最早可以在驱动初始化阶段被注册,最晚可以在
+驱动卸载时被移除。通常,驱动会响应来自sysfs probe()的回调,
+表示已检测到一个主机总线适配器(HBA)。在确认该新设备是LLD的
+目标设备后,LLD初始化HBA,并将一个新的SCSI主机适配器注册到
+SCSI中间层。
+
+在LLD初始化过程中,驱动应当向其期望发现HBA的IO总线(例如PCI
+总线)进行注册。该操作通常可以通过sysfs完成。任何驱动参数(
+特别是那些在驱动加载后仍可修改的参数)也可以在此时通过sysfs
+注册。当LLD注册其首个HBA时,SCSI中间层首次感受到该LLD的存在。
+
+在稍后的某个时间点,当LLD检测到新的HBA时,接下来在LLD与SCSI
+中间层之间会发生一系列典型的调用过程。该示例展示了中间层如何
+扫描新引入的HBA,在该过程中发现了3个SCSI设备,其中只有前两个
+设备有响应::
+
+ HBA探测:假设在扫描中发现2个SCSI设备
+ 底层驱动 中间层 底层驱动
+ =======---------------======---------------=======
+ scsi_host_alloc() -->
+ scsi_add_host() ---->
+ scsi_scan_host() -------+
+ |
+ sdev_init()
+ sdev_configure() --> scsi_change_queue_depth()
+ |
+ sdev_init()
+ sdev_configure()
+ |
+ sdev_init() ***
+ sdev_destroy() ***
+
+
+ *** 对于SCSI中间层尝试扫描但未响应的SCSI设备,系统调用
+ sdev_init()和sdev_destroy()函数对。
+
+如果LLD期望调整默认队列设置,可以在其sdev_configure()例程
+中调用scsi_change_queue_depth()。
+
+当移除一个HBA时,可能是由于卸载LLD模块相关的有序关闭(例如通
+过rmmod命令),也可能是由于sysfs的remove()回调而触发的“热拔
+插”事件。无论哪种情况,其执行顺序都是相同的::
+
+ HBA移除:假设连接了2个SCSI设备
+ 底层驱动 中间层 底层驱动
+ =======---------------------======-----------------=======
+ scsi_remove_host() ---------+
+ |
+ sdev_destroy()
+ sdev_destroy()
+ scsi_host_put()
+
+LLD用于跟踪struct Scsi_Host的实例可能会非常有用
+(scsi_host_alloc()返回的指针)。这些实例由中间层“拥有”。
+当引用计数为零时,struct Scsi_Host实例会被
+scsi_host_put()释放。
+
+HBA的热插拔是一个特殊的场景,特别是当HBA下的磁盘正在处理已挂
+载文件系统上的SCSI命令时。为了应对其中的诸多问题,中间层引入
+了引用计数逻辑。具体内容参考下文关于引用计数的章节。
+
+热插拔概念同样适用于SCSI设备。目前,当添加HBA时,
+scsi_scan_host() 函数会扫描该HBA所属SCSI传输通道上的设备。在
+新型SCSI传输协议中,HBA可能在扫描完成后才检测到新的SCSI设备。
+LLD可通过以下步骤通知中间层新SCSI设备的存在::
+
+ SCSI设备热插拔
+ 底层驱动 中间层 底层驱动
+ =======-------------------======-----------------=======
+ scsi_add_device() ------+
+ |
+ sdev_init()
+ sdev_configure() [--> scsi_change_queue_depth()]
+
+类似的,LLD可能会感知到某个SCSI设备已经被移除(拔出)或与他的连
+接已中断。某些现有的SCSI传输协议(例如SPI)可能直到后续SCSI命令
+执行失败时才会发现设备已经被移除,中间层会将该设备设置为离线状态。
+若LLD检测到SCSI设备已经被移除,可通过以下流程触发上层对该设备的
+移除操作::
+
+ SCSI设备热拔插
+ 底层驱动 中间层 底层驱动
+ =======-------------------======-----------------=======
+ scsi_remove_device() -------+
+ |
+ sdev_destroy()
+
+对于LLD而言,跟踪struct scsi_device实例可能会非常有用(该结构
+的指针会作为参数传递给sdev_init()和sdev_configure()回调函数)。
+这些实例的所有权归属于中间层(mid-level)。struct scsi_device
+实例在sdev_destroy()执行后释放。
+
+引用计数
+========
+Scsi_Host结构体已引入引用计数机制。该机制将struct Scsi_Host
+实例的所有权分散到使用他的各SCSI层,而此前这类实例完全由中间
+层独占管理。底层驱动(LLD)通常无需直接操作这些引用计数,仅在
+某些特定场景下可能需要介入。
+
+与struct Scsi_Host相关的引用计数函数主要有以下3种:
+
+ - scsi_host_alloc():
+ 返回指向新实例的指针,该实例的引用计数被设置为1。
+
+ - scsi_host_get():
+ 给定实例的引用计数加1。
+
+ - scsi_host_put():
+ 给定实例的引用计数减1。如果引用计数减少到0,则释放该实例。
+
+scsi_device结构体现已引入引用计数机制。该机制将
+struct scsi_device实例的所有权分散到使用他的各SCSI层,而此
+前这类实例完全由中间层独占管理。相关访问函数声明详见
+include/scsi/scsi_device.h文件末尾部分。若LLD需要保留
+scsi_device实例的指针副本,则应调用scsi_device_get()增加其
+引用计数;不再需要该指针时,可通过scsi_device_put()递减引用
+计数(该操作可能会导致该实例被释放)。
+
+.. Note::
+
+ struct Scsi_Host实际上包含两个并行维护的引用计数器,该引
+ 用计数由这些函数共同操作。
+
+编码规范
+========
+
+首先,Linus Torvalds关于C语言编码风格的观点可以在
+Documentation/process/coding-style.rst文件中找到。
+
+此外,在相关gcc编译器支持的前提下,鼓励使用大多数C99标准的增强
+特性。因此,在适当的情况下鼓励使用C99风格的结构体和数组初始化
+方式。但不要过度使用,目前对可变长度数组(VLA)的支持还待完善。
+一个例外是 ``//`` 风格的注释;在Linux中倾向于使
+用 ``/*...*/`` 注释格式。
+
+对于编写良好、经过充分测试且有完整文档的代码不需要重新格式化
+以符合上述规范。例如,aic7xxx驱动是从FreeBSD和Adaptec代码库
+移植到Linux的。毫无疑问,FreeBSD和Adaptec遵循其原有的编码规
+范。
+
+
+中间层提供的函数
+================
+这些函数由SCSI中间层提供,供底层驱动(LLD)调用。这些函数的名
+称(即入口点)均已导出,因此作为模块加载的LLD可以访问他们。内
+核会确保在任何LLD初始化之前,SCSI中间层已先行加载并完成初始化。
+下文按字母顺序列出这些函数,其名称均以 ``scsi_`` 开头。
+
+摘要:
+
+ - scsi_add_device - 创建新的SCSI逻辑单元(LU)设备实例
+ - scsi_add_host - 执行sysfs注册并设置传输类
+ - scsi_change_queue_depth - 调整SCSI设备队列深度
+ - scsi_bios_ptable - 返回块设备分区表的副本
+ - scsi_block_requests - 阻止向指定主机提交新命令
+ - scsi_host_alloc - 分配引用计数为1的新SCSI主机适配器实例scsi_host
+ - scsi_host_get - 增加SCSI主机适配器实例的引用计数
+ - scsi_host_put - 减少SCSI主机适配器的引用计数(归零时释放)
+ - scsi_remove_device - 卸载并移除SCSI设备
+ - scsi_remove_host - 卸载并移除主机控制器下的所有SCSI设备
+ - scsi_report_bus_reset - 报告检测到的SCSI总线复位事件
+ - scsi_scan_host - 执行SCSI总线扫描
+ - scsi_track_queue_full - 跟踪连续出现的队列满事件
+ - scsi_unblock_requests - 恢复向指定主机提交命令
+
+详细信息::
+
+ /**
+ * scsi_add_device - 创建新的SCSI逻辑单元(LU)设备实例
+ * @shost: 指向SCSI主机适配器实例的指针
+ * @channel: 通道号(通常为0)
+ * @id: 目标ID号
+ * @lun: 逻辑单元号(LUN)
+ *
+ * 返回指向新的struct scsi_device实例的指针,
+ * 如果出现异常(例如在给定地址没有设备响应),则返
+ * 回ERR_PTR(-ENODEV)
+ *
+ * 是否阻塞:是
+ *
+ * 注意事项:本函数通常在添加HBA的SCSI总线扫描过程
+ * 中由系统内部调用(即scsi_scan_host()执行期间)。因此,
+ * 仅应在以下情况调用:HBA在scsi_scan_host()完成扫描后,
+ * 又检测到新的SCSI设备(逻辑单元)。若成功执行,本次调用
+ * 可能会触发LLD的以下回调函数:sdev_init()以及
+ * sdev_configure()
+ *
+ * 函数定义:drivers/scsi/scsi_scan.c
+ **/
+ struct scsi_device * scsi_add_device(struct Scsi_Host *shost,
+ unsigned int channel,
+ unsigned int id, unsigned int lun)
+
+
+ /**
+ * scsi_add_host - 执行sysfs注册并设置传输类
+ * @shost: 指向SCSI主机适配器实例的指针
+ * @dev: 指向scsi类设备结构体(struct device)的指针
+ *
+ * 成功返回0,失败返回负的errno(例如:-ENOMEM)
+ *
+ * 是否阻塞:否
+ *
+ * 注意事项:仅在“热插拔初始化模型”中需要调用,且必须在
+ * scsi_host_alloc()成功执行后调用。该函数不会扫描总线;
+ * 总线扫描可通过调用scsi_scan_host()或其他传输层特定的
+ * 方法完成。在调用该函数之前,LLD必须先设置好传输模板,
+ * 并且只能在调用该函数之后才能访问传输类
+ * (transport class)相关的数据结构。
+ *
+ * 函数定义:drivers/scsi/hosts.c
+ **/
+ int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
+
+
+ /**
+ * scsi_change_queue_depth - 调整SCSI设备队列深度
+ * @sdev: 指向要更改队列深度的SCSI设备的指针
+ * @tags 如果启用了标记队列,则表示允许的标记数,
+ * 或者在非标记模式下,LLD可以排队的命令
+ * 数(如 cmd_per_lun)。
+ *
+ * 无返回
+ *
+ * 是否阻塞:否
+ *
+ * 注意事项:可以在任何时刻调用该函数,只要该SCSI设备受该LLD控
+ * 制。[具体来说,可以在sdev_configure()执行期间或之后,且在
+ * sdev_destroy()执行之前调用。] 该函数可安全地在中断上下文中
+ * 调用。
+ *
+ * 函数定义:drivers/scsi/scsi.c [更多注释请参考源代码]
+ **/
+ int scsi_change_queue_depth(struct scsi_device *sdev, int tags)
+
+
+ /**
+ * scsi_bios_ptable - 返回块设备分区表的副本
+ * @dev: 指向块设备的指针
+ *
+ * 返回指向分区表的指针,失败返回NULL
+ *
+ * 是否阻塞:是
+ *
+ * 注意事项:调用方负责释放返回的内存(通过 kfree() 释放)
+ *
+ * 函数定义:drivers/scsi/scsicam.c
+ **/
+ unsigned char *scsi_bios_ptable(struct block_device *dev)
+
+
+ /**
+ * scsi_block_requests - 阻止向指定主机提交新命令
+ *
+ * @shost: 指向特定主机的指针,用于阻止命令的发送
+ *
+ * 无返回
+ *
+ * 是否阻塞:否
+ *
+ * 注意事项:没有定时器或其他任何机制可以解除阻塞,唯一的方式
+ * 是由LLD调用scsi_unblock_requests()方可恢复。
+ *
+ * 函数定义:drivers/scsi/scsi_lib.c
+ **/
+ void scsi_block_requests(struct Scsi_Host * shost)
+
+
+ /**
+ * scsi_host_alloc - 创建SCSI主机适配器实例并执行基础初始化
+ * @sht: 指向SCSI主机模板的指针
+ * @privsize: 在hostdata数组中分配的额外字节数(该数组是返
+ * 回的Scsi_Host实例的最后一个成员)
+ *
+ * 返回指向新的Scsi_Host实例的指针,失败返回NULL
+ *
+ * 是否阻塞:是
+ *
+ * 注意事项:当此调用返回给LLD时,该主机适配器上的
+ * SCSI总线扫描尚未进行。hostdata数组(默认长度为
+ * 零)是LLD专属的每主机私有区域,供LLD独占使用。
+ * 两个相关的引用计数都被设置为1。完整的注册(位于
+ * sysfs)与总线扫描由scsi_add_host()和
+ * scsi_scan_host()稍后执行。
+ * 函数定义:drivers/scsi/hosts.c
+ **/
+ struct Scsi_Host * scsi_host_alloc(const struct scsi_host_template * sht,
+ int privsize)
+
+
+ /**
+ * scsi_host_get - 增加SCSI主机适配器实例的引用计数
+ * @shost: 指向Scsi_Host实例的指针
+ *
+ * 无返回
+ *
+ * 是否阻塞:目前可能会阻塞,但可能迭代为不阻塞
+ *
+ * 注意事项:会同时增加struct Scsi_Host中两个子对
+ * 象的引用计数
+ *
+ * 函数定义:drivers/scsi/hosts.c
+ **/
+ void scsi_host_get(struct Scsi_Host *shost)
+
+
+ /**
+ * scsi_host_put - 减少SCSI主机适配器实例的引用计数
+ * (归零时释放)
+ * @shost: 指向Scsi_Host实例的指针
+ *
+ * 无返回
+ *
+ * 是否阻塞:当前可能会阻塞,但可能会改为不阻塞
+ *
+ * 注意事项:实际会递减两个子对象中的计数。当后一个引用
+ * 计数归零时系统会自动释放Scsi_Host实例。
+ * LLD 无需关注Scsi_Host实例的具体释放时机,只要在平衡
+ * 引用计数使用后不再访问该实例即可。
+ * 函数定义:drivers/scsi/hosts.c
+ **/
+ void scsi_host_put(struct Scsi_Host *shost)
+
+
+ /**
+ * scsi_remove_device - 卸载并移除SCSI设备
+ * @sdev: 指向SCSI设备实例的指针
+ *
+ * 返回值:成功返回0,若设备未连接,则返回-EINVAL
+ *
+ * 是否阻塞:是
+ *
+ * 如果LLD发现某个SCSI设备(逻辑单元,lu)已经被移除,
+ * 但其主机适配器实例依旧存在,则可以请求移除该SCSI设备。
+ * 如果该调用成功将触发sdev_destroy()回调函数的执行。调
+ * 用完成后,sdev将变成一个无效的指针。
+ *
+ * 函数定义:drivers/scsi/scsi_sysfs.c
+ **/
+ int scsi_remove_device(struct scsi_device *sdev)
+
+
+ /**
+ * scsi_remove_host - 卸载并移除主机控制器下的所有SCSI设备
+ * @shost: 指向SCSI主机适配器实例的指针
+ *
+ * 返回值:成功返回0,失败返回1(例如:LLD正忙??)
+ *
+ * 是否阻塞:是
+ *
+ * 注意事项:仅在使用“热插拔初始化模型”时调用。应在调用
+ * scsi_host_put()前调用。
+ *
+ * 函数定义:drivers/scsi/hosts.c
+ **/
+ int scsi_remove_host(struct Scsi_Host *shost)
+
+
+ /**
+ * scsi_report_bus_reset - 报告检测到的SCSI总线复位事件
+ * @shost: 指向关联的SCSI主机适配器的指针
+ * @channel: 发生SCSI总线复位的通道号
+ *
+ * 返回值:无
+ *
+ * 是否阻塞:否
+ *
+ * 注意事项:仅当复位来自未知来源时才需调用此函数。
+ * 由SCSI中间层发起的复位无需调用,但调用也不会导
+ * 致副作用。此函数的主要作用是确保系统能正确处理
+ * CHECK_CONDITION状态。
+ *
+ * 函数定义:drivers/scsi/scsi_error.c
+ **/
+ void scsi_report_bus_reset(struct Scsi_Host * shost, int channel)
+
+
+ /**
+ * scsi_scan_host - 执行SCSI总线扫描
+ * @shost: 指向SCSI主机适配器实例的指针
+ *
+ * 是否阻塞:是
+ *
+ * 注意事项:应在调用scsi_add_host()后调用
+ *
+ * 函数定义:drivers/scsi/scsi_scan.c
+ **/
+ void scsi_scan_host(struct Scsi_Host *shost)
+
+
+ /**
+ * scsi_track_queue_full - 跟踪指定设备上连续的QUEUE_FULL
+ * 事件,以判断是否需要及何时调整
+ * 该设备的队列深度。
+ * @sdev: 指向SCSI设备实例的指针
+ * @depth: 当前该设备上未完成的SCSI命令数量(不包括返回
+ * QUEUE_FULL的命令)
+ *
+ * 返回值:0 - 当前队列深度无需调整
+ * >0 - 需要将队列深度调整为此返回值指定的新深度
+ * -1 - 需要回退到非标记操作模式,并使用
+ * host->cmd_per_lun作为非标记命令队列的
+ * 深度限制
+ *
+ * 是否阻塞:否
+ *
+ * 注意事项:LLD可以在任意时刻调用该函数。系统将自动执行“正确
+ * 的处理流程”;该函数支持在中断上下文中安全地调用
+ *
+ * 函数定义:drivers/scsi/scsi.c
+ **/
+ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
+
+
+ /**
+ * scsi_unblock_requests - 恢复向指定主机适配器提交命令
+ *
+ * @shost: 指向要解除阻塞的主机适配器的指针
+ *
+ * 返回值:无
+ *
+ * 是否阻塞:否
+ *
+ * 函数定义:drivers/scsi/scsi_lib.c
+ **/
+ void scsi_unblock_requests(struct Scsi_Host * shost)
+
+
+
+接口函数
+========
+接口函数由底层驱动(LLD)定义实现,其函数指针保存在
+struct scsi_host_template实例中,并将该实例传递给
+scsi_host_alloc()。
+部分接口函数为必选实现项。所有
+接口函数都应声明为static,约定俗成的命名规则如下,
+驱动“xyz”应将其sdev_configure()函数声明为::
+
+ static int xyz_sdev_configure(struct scsi_device * sdev);
+
+其余接口函数的命名规范均依此类推。
+
+需将该函数指针赋值给“struct scsi_host_template”实例
+的‘sdev_configure’成员变量中,并将该结构体实例指针传
+递到中间层的scsi_host_alloc()函数。
+
+各个接口函数的详细说明可参考include/scsi/scsi_host.h
+文件,具体描述位于“struct scsi_host_template”结构体
+各个成员的上方。在某些情况下,scsi_host.h头文件中的描
+述比本文提供的更为详尽。
+
+以下按字母顺序列出所有接口函数及其说明。
+
+摘要:
+
+ - bios_param - 获取磁盘的磁头/扇区/柱面参数
+ - eh_timed_out - SCSI命令超时回调
+ - eh_abort_handler - 中止指定的SCSI命令
+ - eh_bus_reset_handler - 触发SCSI总线复位
+ - eh_device_reset_handler - 执行SCSI设备复位
+ - eh_host_reset_handler - 复位主机(主机总线适配器)
+ - info - 提供指定主机适配器的相关信息
+ - ioctl - 驱动可响应ioctl控制命令
+ - proc_info - 支持/proc/scsi/{驱动名}/{主机号}文件节点的读写操作
+ - queuecommand - 将SCSI命令提交到主机控制器,命令执行完成后调用‘done’回调
+ - sdev_init - 在向新设备发送SCSI命令前的初始化
+ - sdev_configure - 设备挂载后的精细化微调
+ - sdev_destroy - 设备即将被移除前的清理
+
+
+详细信息::
+
+ /**
+ * bios_param - 获取磁盘的磁头/扇区/柱面参数
+ * @sdev: 指向SCSI设备实例的指针(定义于
+ * include/scsi/scsi_device.h中)
+ * @bdev: 指向块设备实例的指针(定义于fs.h中)
+ * @capacity: 设备容量(以512字节扇区为单位)
+ * @params: 三元数组用于保存输出结果:
+ * params[0]:磁头数量(最大255)
+ * params[1]:扇区数量(最大63)
+ * params[2]:柱面数量
+ *
+ * 返回值:被忽略
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 进程上下文(sd)
+ *
+ * 注意事项: 若未提供此函数,系统将基于READ CAPACITY
+ * 使用默认几何参数。params数组已预初始化伪值,防止函
+ * 数无输出。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int bios_param(struct scsi_device * sdev, struct block_device *bdev,
+ sector_t capacity, int params[3])
+
+
+ /**
+ * eh_timed_out - SCSI命令超时回调
+ * @scp: 标识超时的命令
+ *
+ * 返回值:
+ *
+ * EH_HANDLED: 我已修复该错误,请继续完成该命令
+ * EH_RESET_TIMER: 我需要更多时间,请重置定时器并重新开始计时
+ * EH_NOT_HANDLED 开始正常的错误恢复流程
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 中断上下文
+ *
+ * 注意事项: 该回调函数为LLD提供一个机会进行本地
+ * 错误恢复处理。此处的恢复仅限于判断该未完成的命
+ * 令是否还有可能完成。此回调中不允许中止或重新启
+ * 动该命令。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int eh_timed_out(struct scsi_cmnd * scp)
+
+
+ /**
+ * eh_abort_handler - 中止指定的SCSI命令
+ * @scp: 标识要中止的命令
+ *
+ * 返回值:如果命令成功中止,则返回SUCCESS,否则返回FAILED
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 内核线程
+ *
+ * 注意事项: 该函数仅在命令超时时才被调用。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int eh_abort_handler(struct scsi_cmnd * scp)
+
+
+ /**
+ * eh_bus_reset_handler - 发起SCSI总线复位
+ * @scp: 包含该设备的SCSI总线应进行重置
+ *
+ * 返回值:重置成功返回SUCCESS;否则返回FAILED
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 内核线程
+ *
+ * 注意事项: 由SCSI错误处理线程(scsi_eh)调用。
+ * 在错误处理期间,当前主机适配器的所有IO请求均
+ * 被阻塞。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int eh_bus_reset_handler(struct scsi_cmnd * scp)
+
+
+ /**
+ * eh_device_reset_handler - 发起SCSI设备复位
+ * @scp: 指定将被重置的SCSI设备
+ *
+ * 返回值:如果命令成功中止返回SUCCESS,否则返回FAILED
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 内核线程
+ *
+ * 注意事项: 由SCSI错误处理线程(scsi_eh)调用。
+ * 在错误处理期间,当前主机适配器的所有IO请求均
+ * 被阻塞。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int eh_device_reset_handler(struct scsi_cmnd * scp)
+
+
+ /**
+ * eh_host_reset_handler - 复位主机(主机总线适配器)
+ * @scp: 管理该设备的SCSI主机适配器应该被重置
+ *
+ * 返回值:如果命令成功中止返回SUCCESS,否则返回FAILED
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 内核线程
+ *
+ * 注意事项: 由SCSI错误处理线程(scsi_eh)调用。
+ * 在错误处理期间,当前主机适配器的所有IO请求均
+ * 被阻塞。当使用默认的eh_strategy策略时,如果
+ * _abort_、_device_reset_、_bus_reset_和该处
+ * 理函数均未定义(或全部返回FAILED),系统强制
+ * 该故障设备处于离线状态
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int eh_host_reset_handler(struct scsi_cmnd * scp)
+
+
+ /**
+ * info - 提供给定主机适配器的详细信息:驱动程序名称
+ * 以及用于区分不同主机适配器的数据结构
+ * @shp: 指向目标主机的struct Scsi_Host实例
+ *
+ * 返回值:返回以NULL结尾的ASCII字符串。[驱动
+ * 负责管理返回的字符串所在内存并确保其在整个
+ * 主机适配器生命周期内有效。]
+ *
+ * 并发安全声明: 无锁
+ *
+ * 调用上下文说明: 进程上下文
+ *
+ * 注意事项: 通常提供诸如I/O地址或中断号
+ * 等PCI或ISA信息。如果未实现该函数,则
+ * 默认使用struct Scsi_Host::name 字段。
+ * 返回的字符串应为单行(即不包含换行符)。
+ * 通过SCSI_IOCTL_PROBE_HOST ioctl可获
+ * 取该函数返回的字符串,如果该函数不可用,
+ * 则ioctl返回struct Scsi_Host::name中
+ * 的字符串。
+
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ const char * info(struct Scsi_Host * shp)
+
+
+ /**
+ * ioctl - 驱动可响应ioctl控制命令
+ * @sdp: ioctl操作针对的SCSI设备
+ * @cmd: ioctl命令号
+ * @arg: 指向用户空间读写数据的指针。由于他指向用
+ * 户空间,必须使用适当的内核函数
+ * (如 copy_from_user())。按照Unix的风
+ * 格,该参数也可以视为unsigned long 类型。
+ *
+ * 返回值:如果出错则返回负的“errno”值。返回0或正值表
+ * 示成功,并将返回值传递给用户空间。
+ *
+ * 并发安全声明:无锁
+ *
+ * 调用上下文说明:进程上下文
+ *
+ * 注意事项:SCSI子系统使用“逐层下传
+ * (trickle down)”的ioctl模型。
+ * 用户层会对上层驱动设备节点
+ * (例如/dev/sdc)发起ioctl()调用,
+ * 如果上层驱动无法识别该命令,则将其
+ * 传递给SCSI中间层,若中间层也无法识
+ * 别,则再传递给控制该设备的LLD。
+ * 根据最新的Unix标准,对于不支持的
+ * ioctl()命令,应返回-ENOTTY。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int ioctl(struct scsi_device *sdp, int cmd, void *arg)
+
+
+ /**
+ * proc_info - 支持/proc/scsi/{驱动名}/{主机号}文件节点的读写操作
+ * @buffer: 输入或出的缓冲区锚点(writeto1_read0==0表示向buffer写
+ * 入,writeto1_read0==1表示由buffer读取)
+ * @start: 当writeto1_read0==0时,用于指定驱动实际填充的起始位置;
+ * 当writeto1_read0==1时被忽略。
+ * @offset: 当writeto1_read0==0时,表示用户关注的数据在缓冲区中的
+ * 偏移。当writeto1_read0==1时忽略。
+ * @length: 缓冲区的最大(或实际使用)长度
+ * @host_no: 目标SCSI Host的编号(struct Scsi_Host::host_no)
+ * @writeto1_read0: 1 -> 表示数据从用户空间写入驱动
+ * (例如,“echo some_string > /proc/scsi/xyz/2”)
+ * 0 -> 表示用户从驱动读取数据
+ * (例如,“cat /proc/scsi/xyz/2”)
+ *
+ * 返回值:当writeto1_read0==1时返回写入长度。否则,
+ * 返回从offset偏移开始输出到buffer的字符数。
+ *
+ * 并发安全声明:无锁
+ *
+ * 调用上下文说明:进程上下文
+ *
+ * 注意事项:该函数由scsi_proc.c驱动,与proc_fs交互。
+ * 当前SCSI子系统可移除对proc_fs的支持,相关配置选。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int proc_info(char * buffer, char ** start, off_t offset,
+ int length, int host_no, int writeto1_read0)
+
+
+ /**
+ * queuecommand - 将SCSI命令提交到主机控制器,命令执行完成后调用scp->scsi_done回调函数
+ * @shost: 指向目标SCSI主机控制器
+ * @scp: 指向待处理的SCSI命令
+ *
+ * 返回值:成功返回0。
+ *
+ * 如果发生错误,则返回:
+ *
+ * SCSI_MLQUEUE_DEVICE_BUSY表示设备队列满,
+ * SCSI_MLQUEUE_HOST_BUSY表示整个主机队列满
+ *
+ * 在这两种情况下,中间层将自动重新提交该I/O请求
+ *
+ * - 若返回SCSI_MLQUEUE_DEVICE_BUSY,则仅暂停该
+ * 特定设备的命令处理,当该设备的某个命令完成返回
+ * 时(或在短暂延迟后如果没有其他未完成命令)将恢
+ * 复其处理。其他设备的命令仍正常继续处理。
+ *
+ * - 若返回SCSI_MLQUEUE_HOST_BUSY,将暂停该主机
+ * 的所有I/O操作,当任意命令从该主机返回时(或在
+ * 短暂延迟后如果没有其他未完成命令)将恢复处理。
+ *
+ * 为了与早期的queuecommand兼容,任何其他返回值
+ * 都被视作SCSI_MLQUEUE_HOST_BUSY。
+ *
+ * 对于其他可立即检测到的错误,可通过以下流程处
+ * 理:设置scp->result为适当错误值,调用scp->scsi_done
+ * 回调函数,然后该函数返回0。若该命令未立即执行(LLD
+ * 正在启动或将要启动该命令),则应将scp->result置0并
+ * 返回0。
+ *
+ * 命令所有权说明:若驱动返回0,则表示驱动获得该命令的
+ * 所有权,
+ * 并必须确保最终执行scp->scsi_done回调函数。注意:驱动
+ * 可以在返回0之前调用scp->scsi_done,但一旦调用该回
+ * 调函数后,就只能返回0。若驱动返回非零值,则禁止在任何时
+ * 刻执行该命令的scsi_done回调函数。
+ *
+ * 并发安全声明:在2.6.36及更早的内核版本中,调用该函数时持有
+ * struct Scsi_Host::host_lock锁(通过“irqsave”获取中断安全的自旋锁),
+ * 并且返回时仍需保持该锁;从Linux 2.6.37开始,queuecommand
+ * 将在无锁状态下被调用。
+ *
+ * 调用上下文说明:在中断(软中断)或进程上下文中
+ *
+ * 注意事项:该函数执行应当非常快速,通常不会等待I/O
+ * 完成。因此scp->scsi_done回调函数通常会在该函数返
+ * 回后的某个时刻被调用(经常直接从中断服务例程中调用)。
+ * 某些情况下(如模拟SCSI INQUIRY响应的伪适配器驱动),
+ * scp->scsi_done回调可能在该函数返回前就被调用。
+ * 若scp->scsi_done回调函数未在指定时限内被调用,SCSI中
+ * 间层将启动错误处理流程。当调用scp->scsi_done回调函数
+ * 时,若“result”字段被设置为CHECK CONDITION,
+ * 则LLD应执行自动感知并填充
+ * struct scsi_cmnd::sense_buffer数组。在中间层将
+ * 命令加入LLD队列之前前,scsi_cmnd::sense_buffer数组
+ * 会被清零。
+ *
+ * 可选实现说明:LLD必须实现
+ **/
+ int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
+
+
+ /**
+ * sdev_init - 在向新设备发送任何SCSI命令前(即开始扫描
+ * 之前)调用该函数
+ * @sdp: 指向即将被扫描的新设备的指针
+ *
+ * 返回值:返回0表示正常。返回其他值表示出错,
+ * 该设备将被忽略。
+ *
+ * 并发安全声明:无锁
+ *
+ * 调用上下文说明:进程上下文
+ *
+ * 注意事项:该函数允许LLD在设备首次扫描前分配所需的资源。
+ * 对应的SCSI设备可能尚未真正存在,但SCSI中间层即将对其进
+ * 行扫描(例如发送INQUIRY命令等)。如果设备存在,将调用
+ * sdev_configure()进行配置;如果设备不存在,则调用
+ * sdev_destroy()销毁。更多细节请参考
+ * include/scsi/scsi_host.h文件。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int sdev_init(struct scsi_device *sdp)
+
+
+ /**
+ * sdev_configure - 在设备首次完成扫描(即已成功响应INQUIRY
+ * 命令)之后,LDD可调用该函数对设备进行进一步配置
+ * @sdp: 已连接的设备
+ *
+ * 返回值:返回0表示成功。任何其他返回值都被视为错误,此时
+ * 设备将被标记为离线。[被标记离线的设备不会调用sdev_destroy(),
+ * 因此需要LLD主动清理资源。]
+ *
+ * 并发安全声明:无锁
+ *
+ * 调用上下文说明:进程上下文
+ *
+ * 注意事项:该接口允许LLD查看设备扫描代码所发出的初始INQUIRY
+ * 命令的响应,并采取对应操作。具体实现细节请参阅
+ * include/scsi/scsi_host.h文件。
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ int sdev_configure(struct scsi_device *sdp)
+
+
+ /**
+ * sdev_destroy - 当指定设备即将被关闭时调用。此时该设备
+ * 上的所有I/O活动均已停止。
+ * @sdp: 即将关闭的设备
+ *
+ * 返回值:无
+ *
+ * 并发安全声明:无锁
+ *
+ * 调用上下文说明:进程上下文
+ *
+ * 注意事项:该设备的中间层数据结构仍然存在
+ * 但即将被销毁。驱动程序此时应当释放为该设
+ * 备分配的所有专属资源。系统将不再向此sdp
+ * 实例发送任何命令。[但该设备可能在未来被
+ * 重新连接,届时将通过新的struct scsi_device
+ * 实例,并触发后续的sdev_init()和
+ * sdev_configure()调用过程。]
+ *
+ * 可选实现说明:由LLD选择性定义
+ **/
+ void sdev_destroy(struct scsi_device *sdp)
+
+
+
+数据结构
+========
+struct scsi_host_template
+-------------------------
+每个LLD对应一个“struct scsi_host_template”
+实例 [#]_。该结构体通常被初始化为驱动头文件中的静
+态全局变量,此方式可确保未显式初始化的成员自动置零
+(0或NULL)。关键成员变量说明如下:
+
+ name
+ - 驱动程序的名称(可以包含空格,请限制在80个字符以内)
+
+ proc_name
+ - 在“/proc/scsi/<proc_name>/<host_no>”
+ 和sysfs的“drivers”目录中使用的名称。因此
+ “proc_name”应仅包含Unix文件名中可接受
+ 的字符。
+
+ ``(*queuecommand)()``
+ - 中间层使用的主要回调函数,用于将SCSI命令
+ 提交到LLD。
+
+ vendor_id
+ - 该字段是一个唯一标识值,用于确认提供
+ Scsi_Host LLD的供应商,最常用于
+ 验证供应商特定的消息请求。该值由标识符类型
+ 和供应商特定值组成,有效格式描述请参阅
+ scsi_netlink.h头文件。
+
+该结构体的完整定义及详细注释请参阅 ``include/scsi/scsi_host.h``。
+
+.. [#] 在极端情况下,单个驱动需要控制多种不同类型的硬件时,驱动可
+ 能包含多个实例,(例如某个LLD驱动同时处理ISA和PCI两种类型
+ 的适配卡,并为每种硬件类型维护独立的
+ struct scsi_host_template实例)。
+
+struct Scsi_Host
+----------------
+每个由LLD控制的主机适配器对应一个struct Scsi_Host实例。
+该结构体与struct scsi_host_template具有多个相同成员。
+当创建struct Scsi_Host实例时(通过hosts.c中的
+scsi_host_alloc()函数),这些通用成员会从LLD的
+struct scsi_host_template实例初始化而来。关键成员说明
+如下:
+
+ host_no
+ - 系统范围内唯一的主机标识号,按升序从0开始分配
+ can_queue
+ - 必须大于0,表示适配器可处理的最大并发命令数,禁
+ 止向适配器发送超过此数值的命令数
+ this_id
+ - 主机适配器的SCSI ID(SCSI启动器标识),若未知则
+ 设置为-1
+ sg_tablesize
+ - 主机适配器支持的最大散列表(scatter-gather)元素
+ 数。设置为SG_ALL或更小的值可避免使用链式SG列表,
+ 且最小值必须为1
+ max_sectors
+ - 单个SCSI命令中允许的最大扇区数(通常为512字节/
+ 扇区)。默认值为0,此时会使用
+ SCSI_DEFAULT_MAX_SECTORS(在scsi_host.h中定义),
+ 当前该值为1024。因此,如果未定义max_sectors,则磁盘的
+ 最大传输大小为512KB。注意:这个大小可能不足以支持
+ 磁盘固件上传。
+ cmd_per_lun
+ - 主机适配器的设备上,每个LUN可排队的最大命令数。
+ 此值可通过LLD调用scsi_change_queue_depth()进行
+ 调整。
+ hostt
+ - 指向LLD struct scsi_host_template实例的指针,
+ 当前struct Scsi_Host实例正是由此模板生成。
+ hostt->proc_name
+ - LLD的名称,sysfs使用的驱动名。
+ transportt
+ - 指向LLD struct scsi_transport_template实例的指
+ 针(如果存在)。当前支持FC与SPI传输协议。
+ hostdata[0]
+ - 为LLD在struct Scsi_Host结构体末尾预留的区域,大小由
+ scsi_host_alloc()的第二个参数(privsize)决定。
+
+scsi_host结构体的完整定义详见include/scsi/scsi_host.h。
+
+struct scsi_device
+------------------
+通常而言,每个SCSI逻辑单元(Logical Unit)对应一个该结构
+的实例。连接到主机适配器的SCSI设备通过三个要素唯一标识:通
+道号(Channel Number)、目标ID(Target ID)和逻辑单元号
+(LUN)。
+该结构体完整定义于include/scsi/scsi_device.h。
+
+struct scsi_cmnd
+----------------
+该结构体实例用于在LLD与SCSI中间层之间传递SCSI命令
+及其响应。SCSI中间层会确保:提交到LLD的命令数不超过
+scsi_change_queue_depth()(或struct Scsi_Host::cmd_per_lun)
+设定的上限,且每个SCSI设备至少分配一个struct scsi_cmnd实例。
+关键成员说明如下:
+
+ cmnd
+ - 包含SCSI命令的数组
+ cmd_len
+ - SCSI命令的长度(字节为单位)
+ sc_data_direction
+ - 数据的传输方向。请参考
+ include/linux/dma-mapping.h中的
+ “enum dma_data_direction”。
+ result
+ - LLD在调用“done”之前设置该值。值为0表示命令成功
+ 完成(并且所有数据(如果有)已成功在主机与SCSI
+ 目标设备之间完成传输)。“result”是一个32位无符
+ 号整数,可以视为2个相关字节。SCSI状态值位于最
+ 低有效位。请参考include/scsi/scsi.h中的
+ status_byte()与host_byte()宏以及其相关常量。
+ sense_buffer
+ - 这是一个数组(最大长度为SCSI_SENSE_BUFFERSIZE
+ 字节),当SCSI状态(“result”的最低有效位)设为
+ CHECK_CONDITION(2)时,该数组由LLD填写。若
+ CHECK_CONDITION被置位,且sense_buffer[0]的高
+ 半字节值为7,则中间层会认为sense_buffer数组
+ 包含有效的SCSI感知数据;否则,中间层会发送
+ REQUEST_SENSE SCSI命令来获取感知数据。由于命令
+ 排队的存在,后一种方式容易出错,因此建议LLD始终
+ 支持“自动感知”。
+ device
+ - 指向与该命令关联的scsi_device对象的指针。
+ resid_len (通过调用scsi_set_resid() / scsi_get_resid()访问)
+ - LLD应将此无符号整数设置为请求的传输长度(即
+ “request_bufflen”)减去实际传输的字节数。“resid_len”
+ 默认设置为0,因此如果LLD无法检测到数据欠载(不能报告溢出),
+ 则可以忽略它。LLD应在调用“done”之前设置
+ “resid_len”。
+ underflow
+ - 如果实际传输的字节数小于该字段值,LLD应将
+ DID_ERROR << 16赋值给“result”。并非所有
+ LLD都实现此项检查,部分LLD仅将错误信息输出
+ 到日志,而未真正报告DID_ERROR。更推荐
+ 的做法是由LLD实现“resid_len”的支持。
+
+建议LLD在从SCSI目标设备进行数据传输时设置“resid_len”字段
+(例如READ操作)。当这些数据传输的感知码是MEDIUM ERROR或
+HARDWARE ERROR(有时也包括RECOVERED ERROR)时设置
+resid_len尤为重要。在这种情况下,如果LLD无法确定接收了多
+少数据,那么最安全的做法是表示没有接收到任何数据。例如:
+为了表明没有接收到任何有效数据,LLD可以使用如下辅助函数::
+
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+
+其中SCpnt是一个指向scsi_cmnd对象的指针。如果表示仅接收到
+三个512字节的数据块,可以这样设置resid_len::
+
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt) - (3 * 512));
+
+scsi_cmnd结构体定义在 include/scsi/scsi_cmnd.h文件中。
+
+
+锁
+===
+每个struct Scsi_Host实例都有一个名为default_lock
+的自旋锁(spin_lock),它在scsi_host_alloc()函数
+中初始化(该函数定义在hosts.c文件中)。在同一个函数
+中,struct Scsi_Host::host_lock指针会被初始化为指
+向default_lock。此后,SCSI中间层执行的加
+锁和解锁操作都会使用host_lock指针。过去,驱动程序可
+以重写host_lock指针,但现在不再允许这样做。
+
+
+自动感知
+========
+自动感知(Autosense或auto-sense)在SAM-2规范中被定
+义为:当SCSI命令完成状态为CHECK CONDITION时,“自动
+将感知数据(sense data)返回给应用程序客户端”。底层
+驱动(LLD)应当执行自动感知。当LLD检测到
+CHECK CONDITION状态时,可通过以下任一方式完成:
+
+ a) 要求SCSI协议(例如SCSI并行接口(SPI))在此
+ 类响应中执行一次额外的数据传输
+
+ b) 或由LLD主动发起REQUEST SENSE命令获取感知数据
+
+无论采用哪种方式,当检测到CHECK CONDITION状态时,中
+间层通过检查结构体scsi_cmnd::sense_buffer[0]的值来
+判断LLD是否已执行自动感知。若该字节的高半字节为7
+(或 0xf),则认为已执行自动感知;若该字节为其他值
+(且此字节在每条命令执行前会被初始化为0),则中间层将
+主动发起REQUEST SENSE命令。
+
+在存在命令队列的场景下,保存失败命令感知数据的“nexus”
+可能会在等待REQUEST SENSE命令期间变得不同步。因此,
+最佳实践是由LLD执行自动感知。
+
+
+自Linux内核2.4以来的变更
+========================
+io_request_lock已被多个细粒度锁替代。与底层驱动
+(LLD)相关的锁是struct Scsi_Host::host_lock,且每
+个SCSI主机都独立拥有一个该锁。
+
+旧的错误处理机制已经被移除。这意味着LLD的接口函数
+abort()与reset()已经被删除。
+struct scsi_host_template::use_new_eh_code标志
+也已经被移除。
+
+在Linux内核2.4中,SCSI子系统的配置描述与其他Linux子系
+统的配置描述集中存放在Documentation/Configure.help
+文件中。在Linux内核2.6中,SCSI子系统拥有独立的配置文
+件drivers/scsi/Kconfig(体积更小),同时包含配置信息
+与帮助信息。
+
+struct SHT已重命名为struct scsi_host_template。
+
+新增“热插拔初始化模型”以及许多用于支持该功能的额外函数。
+
+
+致谢
+====
+以下人员对本文档做出了贡献:
+
+ - Mike Anderson <andmike at us dot ibm dot com>
+ - James Bottomley <James dot Bottomley at hansenpartnership dot com>
+ - Patrick Mansfield <patmans at us dot ibm dot com>
+ - Christoph Hellwig <hch at infradead dot org>
+ - Doug Ledford <dledford at redhat dot com>
+ - Andries Brouwer <Andries dot Brouwer at cwi dot nl>
+ - Randy Dunlap <rdunlap at xenotime dot net>
+ - Alan Stern <stern at rowland dot harvard dot edu>
+
+
+Douglas Gilbert
+dgilbert at interlog dot com
+
+2004年9月21日
\ No newline at end of file
diff --git a/Documentation/translations/zh_CN/scsi/sd-parameters.rst b/Documentation/translations/zh_CN/scsi/sd-parameters.rst
new file mode 100644
index 000000000000..662caec15b4d
--- /dev/null
+++ b/Documentation/translations/zh_CN/scsi/sd-parameters.rst
@@ -0,0 +1,38 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/scsi/sd-parameters.rst
+
+:翻译:
+
+ 郝栋栋 Dongdong Hao <doubled@leap-io.com>
+
+:校译:
+
+
+
+============================
+Linux SCSI磁盘驱动(sd)参数
+============================
+
+缓存类型(读/写)
+------------------
+启用/禁用驱动器读写缓存。
+
+=========================== ===== ===== ======= =======
+ 缓存类型字符串 WCE RCD 写缓存 读缓存
+=========================== ===== ===== ======= =======
+ write through 0 0 关闭 开启
+ none 0 1 关闭 关闭
+ write back 1 0 开启 开启
+ write back, no read (daft) 1 1 开启 关闭
+=========================== ===== ===== ======= =======
+
+将缓存类型设置为“write back”并将该设置保存到驱动器::
+
+ # echo "write back" > cache_type
+
+如果要修改缓存模式但不使更改持久化,可在缓存类型字符串前
+添加“temporary ”。例如::
+
+ # echo "temporary write back" > cache_type
diff --git a/Documentation/translations/zh_CN/subsystem-apis.rst b/Documentation/translations/zh_CN/subsystem-apis.rst
index 8b646c1010be..0f121f9b0f70 100644
--- a/Documentation/translations/zh_CN/subsystem-apis.rst
+++ b/Documentation/translations/zh_CN/subsystem-apis.rst
@@ -71,12 +71,12 @@ TODOList:
:maxdepth: 1
filesystems/index
+ scsi/index
TODOList:
* block/index
* cdrom/index
-* scsi/index
* target/index
**Fixme**: 这里还需要更多的分类组织工作。
--
2.25.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] docs/zh_CN: add translation of scsi subsystem
2025-06-30 2:29 [PATCH] docs/zh_CN: add translation of scsi subsystem haodongdong
@ 2025-06-30 3:03 ` Yanteng Si
[not found] ` <220d7401030e8c57cb19a90642e0e0ae27071c38.9f9c8c60.2744.44cc.bd7a.c6eb47a4a3f8@feishu.cn>
0 siblings, 1 reply; 4+ messages in thread
From: Yanteng Si @ 2025-06-30 3:03 UTC (permalink / raw)
To: haodongdong, alexs; +Cc: dzm91, corbet, linux-doc
在 6/30/25 10:29 AM, haodongdong 写道:
> This patch introduces the Chinese translation
> of the following SCSI subsystem documentation
> files:
> ../scsi/index.rst
> ../scsi/link_power_management_policy.rst
> ../scsi/scsi_eh.rst
> ../scsi/scsi_mid_low_api.rst
> ../scsi/scsi-parameters.rst
> ../scsi/scsi.rst
> ../scsi/sd-parameters.rst
>
> Signed-off-by: haodongdong <doubled@leap-io.com>
> ---
> .../translations/zh_CN/scsi/index.rst | 92 ++
> .../scsi/link_power_management_policy.rst | 32 +
> .../zh_CN/scsi/scsi-parameters.rst | 118 ++
> .../translations/zh_CN/scsi/scsi.rst | 48 +
> .../translations/zh_CN/scsi/scsi_eh.rst | 482 +++++++
> .../zh_CN/scsi/scsi_mid_low_api.rst | 1174 +++++++++++++++++
> .../translations/zh_CN/scsi/sd-parameters.rst | 38 +
> .../translations/zh_CN/subsystem-apis.rst | 2 +-
Would you mind splitting the patches into a patch set,
with one patch per file? I think this would make the
review much more convenient.
Thanks,
Yanteng
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] docs/zh_CN: add translation of scsi subsystem
[not found] ` <220d7401030e8c57cb19a90642e0e0ae27071c38.9f9c8c60.2744.44cc.bd7a.c6eb47a4a3f8@feishu.cn>
@ 2025-07-02 9:20 ` Dongliang Mu
2025-07-03 1:42 ` Yanteng Si
1 sibling, 0 replies; 4+ messages in thread
From: Dongliang Mu @ 2025-07-02 9:20 UTC (permalink / raw)
To: 郝栋栋, Yanteng Si; +Cc: alexs, corbet, linux-doc
On 7/2/25 5:10 PM, 郝栋栋 wrote:
> Hi Yanteng,
> Thank you again for your kind suggestion.
>
> Sorry for the mistake. I will split the original patch into a patch
> set with one patch per file and resend it soon, to make the review
> easier. Since this is my first time submitting patches to the Linux
> kernel, I’m still learning the process and might not fully understand
> all the best practices. I really appreciate your guidance.
Great!
>
> Do I need to do anything to withdraw the previous single patch?
No
> Or can I just submit the new patch set directly as a replacement?
It's fine to directly resubmit your patch set.
> Should I mention in the cover letter that it supersedes the earlier
> version?
No need to mention it.
Dongliang Mu
>
> Best regards,
> Dongdong Hao
> From: "Yanteng Si"<si.yanteng@linux.dev <mailto:si.yanteng@linux.dev>>
> Date: Mon, Jun 30, 2025, 11:04
> Subject: Re: [PATCH] docs/zh_CN: add translation of scsi subsystem
> To: "haodongdong"<doubled@leap-io.com <mailto:doubled@leap-io.com>>,
> <alexs@kernel.org <mailto:alexs@kernel.org>>
> Cc: <dzm91@hust.edu.cn <mailto:dzm91@hust.edu.cn>>, <corbet@lwn.net
> <mailto:corbet@lwn.net>>, <linux-doc@vger.kernel.org
> <mailto:linux-doc@vger.kernel.org>>
> 在 6/30/25 10:29 AM, haodongdong 写道:
> > This patch introduces the Chinese translation
> > of the following SCSI subsystem documentation
> > files:
> > ../scsi/index.rst
> > ../scsi/link_power_management_policy.rst
> > ../scsi/scsi_eh.rst
> > ../scsi/scsi_mid_low_api.rst
> > ../scsi/scsi-parameters.rst
> > ../scsi/scsi.rst
> > ../scsi/sd-parameters.rst
> >
> > Signed-off-by: haodongdong <doubled@leap-io.com>
> > ---
> > .../translations/zh_CN/scsi/index.rst | 92 ++
> > .../scsi/link_power_management_policy.rst | 32 +
> > .../zh_CN/scsi/scsi-parameters.rst | 118 ++
> > .../translations/zh_CN/scsi/scsi.rst | 48 +
> > .../translations/zh_CN/scsi/scsi_eh.rst | 482 +++++++
> > .../zh_CN/scsi/scsi_mid_low_api.rst | 1174
> +++++++++++++++++
> > .../translations/zh_CN/scsi/sd-parameters.rst | 38 +
> > .../translations/zh_CN/subsystem-apis.rst | 2 +-
>
> Would you mind splitting the patches into a patch set,
>
> with one patch per file? I think this would make the
>
> review much more convenient.
>
>
> Thanks,
>
> Yanteng
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] docs/zh_CN: add translation of scsi subsystem
[not found] ` <220d7401030e8c57cb19a90642e0e0ae27071c38.9f9c8c60.2744.44cc.bd7a.c6eb47a4a3f8@feishu.cn>
2025-07-02 9:20 ` Dongliang Mu
@ 2025-07-03 1:42 ` Yanteng Si
1 sibling, 0 replies; 4+ messages in thread
From: Yanteng Si @ 2025-07-03 1:42 UTC (permalink / raw)
To: 郝栋栋; +Cc: alexs, dzm91, corbet, linux-doc
在 7/2/25 5:10 PM, 郝栋栋 写道:
> Hi Yanteng,
> Thank you again for your kind suggestion.
>
> Sorry for the mistake. I will split the original patch into a patch set with one patch per file and resend it soon, to make the review easier. Since this is my first time submitting patches to the Linux kernel, I’m still learning the process and might not fully understand all the best practices. I really appreciate your guidance.
>
> Do I need to do anything to withdraw the previous single patch?
> Or can I just submit the new patch set directly as a replacement?
> Should I mention in the cover letter that it supersedes the earlier version?
Maybe this document can help you.
https://docs.kernel.org/translations/zh_CN/how-to.html
Thanks,
Yanteng
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-07-03 1:42 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-30 2:29 [PATCH] docs/zh_CN: add translation of scsi subsystem haodongdong
2025-06-30 3:03 ` Yanteng Si
[not found] ` <220d7401030e8c57cb19a90642e0e0ae27071c38.9f9c8c60.2744.44cc.bd7a.c6eb47a4a3f8@feishu.cn>
2025-07-02 9:20 ` Dongliang Mu
2025-07-03 1:42 ` Yanteng Si
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.