SCSI 磁带驱动程序¶
此文件包含关于 SCSI 磁带驱动程序的简要信息。该驱动程序目前由 Kai Mäkisara 维护(电子邮件 Kai.Makisara@kolumbus.fi)
上次修改时间:2016 年 2 月 9 日星期二 21:54:16,作者 kai.makisara
基本原理¶
该驱动程序是通用的,即它不包含任何针对特定磁带驱动器的代码。磁带参数可以使用以下三种方法之一指定
1. 每个用户可以直接使用 ioctl 指定他/她想要使用的磁带参数。这在管理上是一种非常简单灵活的方法,适用于单用户工作站。但是,在多用户环境中,下一个用户会发现磁带参数处于上一个用户离开时的状态。
2. 系统管理员 (root) 可以使用 MTSETDRVBUFFER ioctl 为某些磁带参数定义默认值,例如块大小和密度。可以对这些参数进行编程,使其在新磁带加载到驱动器中时生效,或者如果在磁带开头开始写入时生效。如果磁带驱动器能够很好地自动检测磁带格式(如某些 QIC 驱动器),则第二种方法适用。结果是任何磁带都可以读取,可以使用现有格式继续写入,并且如果从头开始重写磁带(或首次写入新磁带),则使用默认格式。如果驱动器不能很好地执行自动检测,并且设备的单个“合理”模式,则第一种方法适用。一个例子是仅在可变块模式下使用的 DAT 驱动器(我不知道这是否合理 :-)。
用户可以覆盖系统管理员定义的参数。这些更改会持续存在,直到默认值再次生效。
3. 默认情况下,最多可以定义四种模式,并使用次要数字(位 5 和 6)选择。可以通过更改 st.h 中的 ST_NBR_MODE_BITS 来更改模式数量。模式 0 对应于上面讨论的默认值。其他模式处于休眠状态,直到系统管理员 (root) 定义它们。启动新模式的规范时,模式 0 的配置用于为新模式的定义提供起点。
使用模式允许系统管理员让用户可以选择某些用户无法直接访问的缓冲参数(缓冲和异步写入)。这些模式还允许在多磁带操作中选择格式(当加载新磁带时,显式覆盖的参数会被重置)。
如果使用多个模式,则所有模式应包含相同参数集的定义。
许多 Unix 包含内部表,将不同的模式与支持的设备相关联。Linux SCSI 磁带驱动程序不包含此类表(并且将来也不会这样做)。相反,可以制作一个实用程序,用于获取设备发送的查询数据,扫描其数据库,并使用 ioctl 设置模式。另一种方法是创建一个使用 mt 设置针对系统定制的默认值的小脚本。
该驱动程序支持固定和可变块大小(在缓冲区限制范围内)。自动倒带(次要等于设备号)和非倒带设备(次要为 128 + 设备号)都已实现。
在可变块模式下,write() 中的字节数决定了磁带上的物理块大小。读取时,如果 read() 字节数至少为块大小,则驱动器将读取下一个磁带块并将数据返回给用户。否则,将返回错误 ENOMEM。
在固定块模式下,驱动器和驱动程序之间的数据传输是块大小的倍数。write() 字节数必须是块大小的倍数。读取时不需要这样做,但为了可移植性,可能建议这样做。
提供对更改磁带分区和使用一个或两个分区对磁带进行分区的支持。默认情况下,每个驱动程序都禁用对分区磁带的支持,可以使用 ioctl MTSETDRVBUFFER 启用。
默认情况下,驱动程序在写入后关闭设备并且上次操作是写入时写入一个文件标记。可以选择写入两个文件标记。在这两种情况下,数据的结尾都通过为两个连续读取返回零字节来表示。
在 SCSI 命令块中写入没有设置立即位的文件标记充当同步点,即,驱动器缓冲区中的所有剩余数据在命令返回之前都写入到磁带。这确保了在该点捕获写入错误,但这需要时间。在某些应用程序中,必须快速写入几个连续的文件。MTWEOFI 操作可用于在不刷新驱动器缓冲区的情况下写入文件标记。在 close() 写入文件标记始终会刷新驱动器缓冲区。但是,如果之前的操作是 MTWEOFI,则 close() 不写入文件标记。如果程序想要在文件之间关闭/打开磁带设备并且想要跳过等待,可以使用此方法。
如果完成倒带、脱机、bsf 或 seek,并且之前的磁带操作是写入,则在移动磁带之前会写入文件标记。
编译选项在文件 linux/drivers/scsi/st_options.h 中定义。
4. 如果使用打开选项 O_NONBLOCK,即使驱动器未准备好,打开也会成功。如果不使用 O_NONBLOCK,驱动程序会等待驱动器准备就绪。如果 ST_BLOCK_SECONDS 秒内未发生这种情况,则打开失败,errno 值为 EIO。使用 O_NONBLOCK,即使驱动器中有写保护磁带,也可以打开设备进行写入(尝试写入任何内容的命令如果尝试则返回错误)。
次要数字¶
如果每个驱动器使用 4 种模式,则磁带驱动程序当前支持最多 2^17 个驱动器。
次要数字由以下位字段组成
dev_upper non-rew mode dev-lower
20 - 8 7 6 5 4 0
非倒带位始终是位 7(最下面的字节中的最高位)。定义模式的位低于非倒带位。其余位定义磁带设备号。此编号与次要数字仅 8 位宽时使用的编号向后兼容。
Sysfs 支持¶
该驱动程序创建目录 /sys/class/scsi_tape 并使用对应于现有磁带设备的目录填充它。每个模式都有自动倒带和非倒带条目。名称是 stxy 和 nstxy,其中 x 是磁带编号,y 是对应于模式的字符(none、l、m、a)。例如,第一个磁带设备的目录是(假设有四种模式):st0 nst0 st0l nst0l st0m nst0m st0a nst0a。
每个目录包含以下条目:default_blksize default_compression default_density defined dev device driver。文件“defined”包含 1(如果模式已定义),否则包含 0。文件“default_*”包含用户设置的默认值。值 -1 表示未设置默认值。文件“dev”包含对应于此设备的设备号。链接“device”和“driver”指向 SCSI 设备和驱动程序条目。
每个目录还包含条目“options”,它显示当前启用的驱动程序和模式选项。文件中的值是一个位掩码,其中位定义与 MTSETDRVBUFFER 中设置选项时使用的位定义相同。
每个目录都包含条目“position_lost_in_reset”。如果此值为 1,则在设备重置后阻止对设备的读取和写入。大多数设备在重置后会倒带磁带,并且写入/读取不会访问用户期望的磁带位置。
从 SCSI 设备目录到对应于模式 0 自动倒带设备的类目录(例如,st0)创建一个名为“tape”的链接。
磁带设备的 Sysfs 和统计信息¶
st 驱动程序维护 sysfs 文件系统中的磁带驱动器统计信息。可以使用以下方法来找到可用的统计信息(假设 sysfs 安装在 /sys 上)
在目录 /sys/class/scsi_tape 上使用 opendir(3)
使用 readdir(3) 读取目录内容
使用 regcomp(3)/regexec(3) 将目录条目与扩展的正则表达式“^st[0-9]+$”匹配
从 /sys/class/scsi_tape/<match>/stats 目录访问统计信息(其中 <match> 是 /sys/class/scsi_tape 中与扩展正则表达式匹配的目录条目)
使用此方法的原因是,指向同一磁带驱动器的所有字符设备都使用相同的统计信息。这意味着 st0 将具有与 nst0 相同的统计信息。
该目录包含以下统计信息文件
- in_flight
当前发送到此设备的 I/O 数量。
- io_ns
等待所有 I/O 完成所花费的时间(以纳秒为单位)(包括读取和写入)。这包括磁带移动命令,例如在文件或集合标记之间寻找,以及隐式磁带移动,例如在使用关闭时倒带磁带设备时。
- other_cnt
除了读取或写入命令之外,发送到磁带驱动器的 I/O 数量。完成这些命令所花费的时间使用以下计算 io_ms-read_ms-write_ms。
- read_byte_cnt
从磁带驱动器读取的字节数。
- read_cnt
发送到磁带驱动器的读取请求数量。
- read_ns
等待读取请求完成所花费的时间(以纳秒为单位)。
- write_byte_cnt
写入到磁带驱动器的字节数。
- write_cnt
发送到磁带驱动器的写入请求数量。
- write_ns
等待写入请求完成所花费的时间(以纳秒为单位)。
- resid_cnt
在读取或写入过程中,我们发现剩余数量非零的次数。这应该意味着程序正在发出大于磁带上块大小的读取。对于写入,并非所有数据都已写入到磁带。
注意
在 I/O 启动时增加 in_flight 值,I/O 本身在完成之前不会添加到统计信息中。
read_cnt、write_cnt 和 other_cnt 的总和可能与设备级别的 iodone_cnt 的值不同。磁带统计信息仅计算通过 st 模块发出的 I/O。
当读取统计信息时,当 I/O 正在进行时,它们在时间上可能不一致。单独的值是原子地读取和写入的,但是当通过 sysfs 将它们读回时,它们可能在启动 I/O 或完成 I/O 时正在被更新。
在更新任何统计信息之前增加 in_flight 中显示的值,并在完成 I/O 时更新统计信息后减少该值。当没有 st 驱动程序发出的未完成 I/O 时,in_flight 的值为 0。磁带统计信息不考虑通过 sg 设备执行的任何 I/O。
BSD 和 Sys V 语义¶
用户可以通过定义符号 ST_SYSV 的值来选择磁带驱动程序的这两种行为。当正在读取的文件关闭时,语义不同。BSD 语义将磁带留在当前位置,而 SYS V 语义将磁带移动到下一个文件标记之后,除非刚刚越过该文件标记。
默认设置为 BSD 语义。
缓冲¶
该驱动程序尝试直接从用户空间执行传输。如果不可能,则使用在运行时分配的驱动程序缓冲区。如果整个传输不可能进行直接 i/o,则使用驱动程序缓冲区(即,不使用单个页面的跳转缓冲区)。由于多种原因,直接 i/o 可能不可能,例如
一个或多个页面位于 HBA 无法访问的地址。
传输中的页面数超过了 HBA 允许的散点/收集段数。
一个或多个页面无法锁定到内存中(在任何合理的情况下都不应发生)。
驱动程序缓冲区的大小始终至少为一个磁带块。在固定块模式下,最小缓冲区大小由 ST_FIXED_BUFFER_BLOCKS(以 1024 字节为单位)定义。对于小块大小,这允许缓冲多个块并使用一个 SCSI 读取或写入来传输所有块。如果 ST_BUFFER_WRITES 为非零并且未使用直接 i/o,则允许跨固定块模式下的写入调用缓冲数据。缓冲区分配使用大小为 2^n *(页面大小)的内存块。因此,实际缓冲区大小可能大于最小允许缓冲区大小。
请注意,如果使用直接 i/o,则不会缓冲小写入。从 2.4 迁移时,这可能会导致意外。在那里,小写入(例如,没有 -b 选项的 tar)可能具有良好的吞吐量,但在 2.6 中不再是这样。可以关闭直接 i/o 来解决此问题,但更好的解决方案是使用更大的 write() 字节数(例如,tar -b 64)。
异步写入。启动将缓冲区内容写入到磁带,并且写入调用立即返回。在下一个磁带操作中检查状态。异步写入不是使用直接 i/o 完成的,也不是在固定块模式下完成的。
如果早期警告标记后没有足够的空间来刷新驱动程序缓冲区,则缓冲写入和异步写入在某些罕见情况下可能会导致多卷操作出现问题。
固定块模式的预读 (ST_READ_AHEAD)。即使用户不想在此读取命令中获取所有数据,也会尝试填充缓冲区。对于那些不喜欢文件标记截断读取请求或不喜欢退回的驱动器,应禁用此功能。
如果无法分配连续缓冲区,则使用散点/收集缓冲区(由物理内存中不连续的块组成的缓冲区)。为了支持所有 SCSI 适配器(包括那些不支持散点/收集的适配器),缓冲区分配使用以下三种块
初始段,用于所有 SCSI 适配器,包括那些不支持散点/收集的适配器。如果系统可以提供此大小的块(并且它不大于 ST_BUFFER_BLOCKS 指定的缓冲区大小),则此缓冲区的大小将为 (PAGE_SIZE << ST_FIRST_ORDER) 字节。如果此大小不可用,则驱动程序将大小减半并重试,直到大小为一个页面。st_options.h 中的默认设置使驱动程序尝试将所有缓冲区分配为一个块。
分配散点/收集段以填充指定的缓冲区大小,以便使用尽可能多的段,但段数不超过 ST_FIRST_SG。
ST_MAX_SG(或模块参数 max_sg_segs)与阶段 1 和 2 中使用的段数之间的剩余段用于在运行时扩展缓冲区(如果需要)。如果允许用于 SCSI 适配器的散点/收集段数小于指定的最大散点/收集段数,则不会超过该数量。如果允许用于 SCSI 适配器的最大段数小于阶段 1 和 2 中使用的段数,则扩展缓冲区将始终失败。
写入时的 EOM 行为¶
当遇到介质早期警告的末尾时,将完成当前写入并返回字节数。下一个写入返回 -1,并且 errno 设置为 ENOSPC。要启用写入尾部,允许下一个写入继续进行,并且如果成功,则返回字节数。此后,交替返回 -1 和字节数,直到遇到介质的物理末尾(或其他一些错误)。
模块参数¶
当驱动程序作为模块加载时,可以配置缓冲区大小、写入阈值和分配的最大缓冲区数。关键词是
buffer_kbs=xxx |
固定块模式的缓冲区大小设置为 xxx KB |
write_threshold_kbs=xxx |
写入阈值(以 KB 为单位)设置为 xxx |
max_sg_segs=xxx |
最大散点/收集段数 |
try_direct_io=x |
如果此值为非零,则尝试在用户缓冲区和磁带驱动器之间进行直接传输 |
请注意,如果更改了缓冲区大小但未设置写入阈值,则写入阈值将设置为新的缓冲区大小 - 2 KB。
启动时配置¶
如果驱动程序已编译到内核中,则也可以使用 LILO 命令行设置相同的参数。首选语法是使用与作为模块加载时使用的关键字相同的关键字,但前面加上“st.”。例如,要设置最大散点/收集段数,应使用参数“st.max_sg_segs=xx”(xx 是散点/收集段数)。
为了兼容性,支持早期 2.5 和 2.4 内核版本的旧语法。可以使用与将驱动程序作为模块加载时相同的关键字。如果设置了多个参数,则关键字-值对用逗号分隔(不允许有空格)。可以使用冒号代替等号。定义前面加上字符串 st=。这是一个例子
st=buffer_kbs:64,write_threshold_kbs:60
还支持旧内核版本使用的以下语法
st=aa[,bb[,dd]]
其中
aa 是固定块模式的缓冲区大小(以 1024 字节为单位)
bb 是写入阈值(以 1024 字节为单位)
dd 是最大散点/收集段数
IOCTL¶
磁带的位置和驱动器参数使用 mtio.h 中定义的 ioctl 设置。磁带控制程序“mt”使用这些 ioctl。尝试找到一个 mt,它支持所有 Linux SCSI 磁带 ioctl,并且如果将修改磁带内容,则打开设备进行写入(从 Linux ftp 站点查找程序包 mt-st*;GNU mt 不打开进行写入,例如,擦除)。
支持的 ioctl 是
以下使用结构 mtop
- MTFSF
向前跳过计数文件标记。磁带位于文件标记之后。
- MTFSFM
与上述相同,但磁带位于文件标记之前。
- MTBSF
向后跳过计数文件标记。磁带位于文件标记之前。
- MTBSFM
与上述相同,但磁带位于文件标记之后。
- MTFSR
向前跳过计数记录。
- MTBSR
向后跳过计数记录。
- MTFSS
向前跳过计数集合标记。
- MTBSS
向后跳过计数集合标记。
- MTWEOF
写入计数文件标记。
- MTWEOFI
写入设置了立即位的文件标记计数(即,不等待数据写入磁带)
- MTWSM
写入计数集合标记。
- MTREW
倒带磁带。
- MTOFFL
将设备设置为脱机(通常是倒带加上弹出)。
- MTNOP
除了刷新缓冲区之外,什么也不做。
- MTRETEN
重新拉紧磁带。
- MTEOM
跳到记录数据的末尾。
- MTERASE
擦除磁带。如果参数为零,则使用短擦除命令。长擦除命令与参数的所有其他值一起使用。
- MTSEEK
寻找磁带块计数。对 SCSI-1 驱动器使用 Tandberg 兼容的 seek (QFA),对 SCSI-2 驱动器使用 SCSI-2 seek。seek 之后的文件的文件号和块号无效。
- MTSETBLK
设置驱动器块大小。设置为零将驱动器设置为可变块模式(如果适用)。
- MTSETDENSITY
将驱动器密度代码设置为 arg。有关可用代码,请参阅驱动器文档。
- MTLOCK 和 MTUNLOCK
显式锁定/解锁磁带驱动器门。
- MTLOAD 和 MTUNLOAD
显式加载和卸载磁带。如果命令参数 x 介于 MT_ST_HPLOADER_OFFSET + 1 和 MT_ST_HPLOADER_OFFSET + 6 之间,则编号 x 用于随命令发送到驱动器,并选择 HP C1553A 切换器要使用的磁带插槽。
- MTCOMPRESSION
使用 SCSI 模式页 15 设置压缩或解压缩驱动器模式。请注意,某些驱动器使用其他方法来控制压缩。某些驱动器(如 Exabytes)使用密度代码进行压缩控制。某些驱动器使用另一个模式页,但此页尚未在驱动程序中实现。某些没有压缩功能的驱动器将接受任何压缩模式而不会出错。
- MTSETPART
在下一个磁带操作时将磁带移动到参数给定的分区。磁带定位的块是在新的活动分区中先前磁带定位的块,除非下一个磁带操作是 MTSEEK。在这种情况下,磁带将直接移动到 MTSEEK 指定的块。除非设置 MT_ST_CAN_PARTITIONS,否则 MTSETPART 无效。
- MTMKPART
使用一个分区(参数为零)或两个分区(参数为非零)格式化磁带。如果参数为正数,则它指定分区 1 的大小(以 MB 为单位)。对于 DDS 驱动器和几个早期驱动器,这是磁带的物理上第一个分区。如果参数为负数,则其绝对值指定分区 0 的大小(以 MB 为单位)。这是许多后来的驱动器(如 LTO-5 及以上的 LTO 驱动器)的物理上第一个分区。该驱动器必须支持由启动器指定大小的分区。除非设置 MT_ST_CAN_PARTITIONS,否则无效。
- MTSETDRVBUFFER
用于多种目的。该命令从带有掩码 MT_SET_OPTIONS 的计数获得,低位用作参数。此命令仅允许超级用户 (root) 使用。子命令是
- 0
驱动器缓冲区选项设置为参数。零表示没有缓冲。
- MT_ST_BOOLEANS
设置缓冲选项。这些位是以下选项的新状态(已启用/已禁用)(括号中指定选项是全局的还是可以针对每种模式指定不同的选项)
- MT_ST_BUFFER_WRITES
写入缓冲(模式)
- MT_ST_ASYNC_WRITES
异步写入(模式)
- MT_ST_READ_AHEAD
预读(模式)
- MT_ST_TWO_FM
写入两个文件标记(全局)
- MT_ST_FAST_EOM
使用 SCSI 间距到 EOD(全局)
- MT_ST_AUTO_LOCK
自动锁定驱动器门(全局)
- MT_ST_DEF_WRITES
默认值仅用于写入(模式)
- MT_ST_CAN_BSR
可以使用跨多个记录的退回操作来重新定位磁带(全局)
- MT_ST_NO_BLKLIMS
驱动程序不从驱动器询问块限制(只能将块大小更改为可变)(全局)
- MT_ST_CAN_PARTITIONS
启用对分区磁带的支持(全局)
- MT_ST_SCSI2LOGICAL
对于 SCSI-2 驱动器,在 MTSEEK 和 MTIOCPOS 中使用逻辑块号,而不是设备相关的地址。建议设置此标志,除非存在使用设备相关的磁带(来自旧时代)(全局)
- MT_ST_SYSV
设置 SYSV 语义(模式)
- MT_ST_NOWAIT
为某些命令(例如,倒带)启用立即模式(即,不等待命令完成)
- MT_ST_NOWAIT_EOF
启用立即文件标记模式(即,在写入文件标记时,不等待它完成)。请参阅关于 MTWEOFI 的基本原理注释,了解写入立即文件标记的可能危险。
- MT_ST_SILI
在可变块模式下读取时,启用在 SCSI 命令中设置 SILI 位,以提高读取短于字节数的块时的性能;仅当您确定驱动器支持 SILI 并且 HBA 正确返回传输残留时才设置此值
- MT_ST_DEBUGGING
调试(全局;必须将调试编译到驱动程序中)
- MT_ST_SETBOOLEANS、MT_ST_CLEARBOOLEANS
设置或清除选项位。
- MT_ST_WRITE_THRESHOLD
将此设备的写入阈值设置为最低位指定的 KB 数。
- MT_ST_DEF_BLKSIZE
定义自动设置的默认块大小。值 0xffffff 表示不再使用默认值。
- MT_ST_DEF_DENSITY、MT_ST_DEF_DRVBUFFER
用于设置或清除密度(8 位)和驱动器缓冲区状态(3 位)。如果该值为 MT_ST_CLEAR_DEFAULT (0xfffff),则不再使用默认值。否则,该值的最低位包含参数的新值。
- MT_ST_DEF_COMPRESSION
如果最低字节的值为 0xff,则不使用压缩默认值。否则,最低位包含新的默认值。如果位 8-15 设置为非零数字,并且此数字不是 0xff,则该数字用作压缩算法。可以使用值 MT_ST_CLEAR_DEFAULT 清除压缩默认值。
- MT_ST_SET_TIMEOUT
为此设备设置正常超时(以秒为单位)。默认值为 900 秒(15 分钟)。超时应足够长,以便设备在读取/写入时完成重试。
- MT_ST_SET_LONG_TIMEOUT
设置用于已知需要长时间操作的长超时。默认值为 14000 秒(3.9 小时)。对于擦除,此值还要乘以 8。
- MT_ST_SET_CLN
使用参数的最低 24 位设置清理请求解释参数。如果从扩展检测数据中找到清理请求位模式,驱动程序可以设置通用状态位 GMT_CLN。当驱动器需要清理时,许多驱动器在扩展检测数据中设置一个或多个位。这些位取决于设备。驱动程序会获得检测数据字节的编号(参数的最低 8 位;必须 >= 18(保留值 1 - 17)且 <= 最大请求的检测数据大小)、用于选择相关位的掩码(位 9-16)和位模式(位 17-23)。如果位模式为零,则掩码下的一个或多个位指示清理请求。如果模式为非零,则模式必须与屏蔽的检测数据字节匹配。
(如果看到附加的检测代码和限定符 00h 17h,则无论 MT_ST_SET_CLN 的设置如何,都会设置清理位。)
以下 ioctl 使用结构 mtpos
- MTIOCPOS
从驱动器读取当前位置。对 SCSI-1 驱动器使用 Tandberg 兼容的 QFA,对 SCSI-2 驱动器使用 SCSI-2 命令。
以下 ioctl 使用结构 mtget 返回状态
- MTIOCGET
返回一些状态信息。返回文件号和文件中的块号。当无法确定块时(例如,在 MTBSF 之后),块为 -1。驱动器类型为 MTISSCSI1 或 MTISSCSI2。自上次状态调用以来恢复的错误数存储在字段 mt_erreg 的低字中。当前块大小和密度代码存储在字段 mt_dsreg 中(子字段的偏移量为 MT_ST_BLKSIZE_SHIFT 和 MT_ST_DENSITY_SHIFT)。GMT_xxx 状态位反映驱动器状态。如果没有磁带在驱动器中,则设置 GMT_DR_OPEN。GMT_EOD 表示记录数据的末尾或磁带的末尾。GMT_EOT 表示磁带的末尾。
其他编译选项¶
如果定义了 ST_RECOVERED_WRITE_FATAL,则恢复的写入错误被认为是致命的。
磁带设备的最大数量由 define ST_MAX_TAPES 确定。如果在驱动程序初始化时检测到更多磁带,则会相应地调整最大值。
可以通过定义 ST_NOWAIT 来启用从磁带定位 SCSI 命令立即返回。如果定义了此值,则用户应注意在上一个磁带操作完成之前未启动下一个磁带操作。驱动器和 SCSI 适配器应正常处理这种情况,但已知某些驱动器/适配器组合会在这种情况下挂起 SCSI 总线。
默认情况下,MTEOM 命令实现为跨 32767 个文件标记的间距。使用此方法,状态中的文件号是正确的。用户可以通过设置 ST_FAST_EOM 1(或使用 MT_ST_OPTIONS ioctl)来请求使用直接间距到 EOD。在这种情况下,文件号将无效。
当使用预读或缓冲写入时,关闭文件后,文件中的位置可能不正确(正确的位置可能需要退回多个记录)。如果在编译时定义了 ST_IN_FILE_POS,或者驱动器的 MT_ST_CAN_BSR 位设置为 ioctl,则可以获得文件中正确的位置。(如果用户没有请求那么远的数据,则驱动程序始终退回预读越过的文件标记。)
调试提示¶
调试代码现在默认编译,但使用内核模块参数 debug_flag(默认为 0)关闭调试。仍然可以使用 ioctl 打开和关闭调试。要在模块加载时启用调试,请将 debug_flag=1 添加到模块加载选项,调试输出并不多。还可以通过向 sysfs 文件 /sys/bus/scsi/drivers/st/debug_flag 写入“0”(禁用)或“1”(启用)来启用和禁用调试。
如果磁带似乎挂起,我将非常感兴趣地听到驱动程序在何处等待。使用命令“ps -l”,您可以查看使用磁带的进程的状态。如果状态为 D,则进程正在等待某些内容。字段 WCHAN 告诉驱动程序在何处等待。如果您在正确的位置(对于我使用的 procps,在 /boot 中)有当前的 System.map,或者已经更新了 /etc/psdatabase(对于 kmem ps),则 ps 会在 WCHAN 字段中写入函数名称。如果没有,您必须从 System.map 中查找该函数。
还要注意,与其他大多数驱动程序相比,超时时间非常长。这意味着 Linux 驱动程序可能显示为挂起,尽管真正的原因是磁带固件已感到困惑。