版权所有 © 2001, 2002, 2003, 2004 Douglas Gilbert
2003-08-24
修订历史 | ||
---|---|---|
修订 2.1 | 2004-08-24 | 修订者: dpg |
scsihosts 更改 -> 运行 mkinitrd, lk 2.4.21,22 | ||
修订 2.0 | 2003-05-04 | 修订者: dpg |
lk2.4.20, linuxdoc->tldp, sATA 和 SAS, 原始设备上的最后一个扇区, blockdev | ||
修订 1.9 | 2002-11-20 | 修订者: dpg |
转换为 xml, lk2.4.19, 拼写 | ||
修订 1.8 | 2002-05-05 | 修订者: dpg |
scsihosts 逗号分隔符, grub+lilo | ||
修订 1.7 | 2002-04-27 | 修订者: dpg |
mkinitrd, scsi_debug, 2.4.18, 更多 ATAPI | ||
修订 1.6 | 2002-01-26 | 修订者: dpg |
ATAPI cdrom 选择 | ||
修订 1.5 | 2001-12-21 | 修订者: dpg |
16 字节 SCSI 命令, SCSI_IOCTL_GET_PCI | ||
修订 1.4 | 2001-08-26 | 修订者: dpg |
拼写, dd_rescue, mkinitrd 示例, lk 2.4 更改, 1394。 | ||
修订 1.3 | 2001-08-26 | 修订者: dpg |
ATAPI CDROM 部分, 修改标题, U320, iSCSI。 | ||
修订 1.2 | 2001-03-25 | 修订者: dpg |
关于 scu, dt, "Alt" 序列, 更多说明的信息。 | ||
修订 1.1 | 2001-01-22 | 修订者: dpg |
添加 osst 描述, _EXTRA_DEVS 限制。 |
允许复制、分发和/或修改本文档,但必须遵守 GNU 自由文档许可证第 1.1 版或自由软件基金会发布的任何后续版本的条款;不得包含不变部分、封面文本和封底文本。
有关许可证的在线副本,请参阅 www.fsf.org/copyleft/fdl.html。
本文档描述了 Linux 内核进入 2.4 生产系列时的 SCSI 子系统。
SCSI 子系统的外部视图是主要主题。包含材料是为了帮助 Linux SCSI 子系统的系统管理。此外,还简要描述了 ioctl() 和接口,它们可能与编写使用此子系统的应用程序的人员有关。但是,未涉及内部数据结构和设计问题 [请参阅参考 W2]。为了使演示文稿简洁明了,编译选项和系统调用(包括 ioctl())已放置在 附录 E 中。虽然原始设备并不完全是 SCSI 子系统的一部分,但在 第 11 章中也对其进行了描述。
对于那些对 SCSI 子系统不感兴趣,只想让他们的 ATAPI cd 刻录机正常工作的人,请参阅 第 9.2.4 节。浏览 第 2 章 也可能很有用。
本文档是 Drew Eckhardt 五年前编写的 SCSI-HOWTO [请参阅参考 W7] 的后续文档。该文档描述了 Linux 内核 1.2 和 1.3 系列中的 SCSI 子系统。它仍然可以在 Linux 文档项目 [LDP,请参阅参考 W8] 的“未维护”部分中找到。这两份文档具有大致相似的结构,尽管 Drew 的文档包含大量关于适配器驱动程序的信息。
本文档可以以电子形式在 www.tldp.org/HOWTO/SCSI-2.4-HOWTO 找到。本文档的主站点以及可能最新的版本可以在 www.torque.net/scsi/SCSI-2.4-HOWTO 找到(这是多页 html 版本)。在该位置,本文档以 txt、pdf、ps、单页(长)html 以及多页 html 呈现。例如,pdf 版本位于 www.torque.net/scsi/SCSI-2.4-HOWTO.pdf)。
本文档最后修改于 2004 年 8 月 24 日。
SCSI 子系统具有 3 级架构,“上”层最接近用户/内核接口,而“下”层最接近硬件。上层驱动程序通常以简洁的两个字母的缩写形式表示(例如,“sd”表示 SCSI 磁盘驱动程序)。对应的模块驱动程序的名称(由于历史原因,有时与内置驱动程序的名称不同)在下图中用括号显示。
SCSI 子系统的 3 级驱动程序架构。
上层支持用户-内核接口。对于 sd 和 sr,这是一个块设备接口,而对于 st 和 sg,这是一个字符设备接口。使用 SCSI 子系统的任何操作(例如,从磁盘读取扇区)都涉及 3 个级别中的每个级别的一个驱动程序(例如,sd、SCSI 中间层和 aic7xxx 驱动程序)。
从图中可以看出,SCSI 中间层对于所有操作都是通用的。SCSI 中间层定义内部接口并为上层和下层驱动程序提供常用服务。中间层提供的 Ioctl 可用于属于 4 个上层驱动程序中任何一个的文件描述符。
对块设备最常见的操作是“挂载”文件系统。对于 sd 设备,通常会挂载一个分区(例如,mount -t ext2 /dev/sda6 /home)。对于 sr 设备,通常会挂载整个设备(例如,mount -t iso9660 /dev/sr0 /mnt/cdrom)。 dd 命令可用于从块设备读取或写入。在这种情况下,块大小参数 ("bs") 需要设置为设备的块大小(例如,大多数磁盘为 512 字节)或该设备块大小的整数倍(例如,8192 字节)。块子系统最近添加了一个功能,允许设备(或分区)多次挂载在不同的挂载点上。
Sd 是通用磁盘系列的一员,hd 设备也是 IDE 子系统的一员。除了挂载 sd 设备之外,还可以使用 fdisk 命令来查看或修改磁盘的分区表。虽然 hdparm 命令主要用于 ATA 磁盘(也称为 IDE 或 EIDE 磁盘),但某些选项也可用于 SCSI 磁盘。
Sr 是 CD-ROM 子系统的一员。除了挂载文件系统(例如,iso9660)之外,还可以读取音频 CD。后者的动作不涉及挂载文件系统,而是通常通过调用一些 ioctl 来完成。通用 Linux 命令(例如 dd)不能用于音频 CD。
St 是用于读取和写入磁带的字符设备。通常,mt 命令用于执行数据传输和其他控制功能。
Sg 是一个 SCSI 命令传递设备,它使用字符设备接口。通用 Linux 命令不应在 sg 设备上使用。 SANE(用于扫描仪)、cdrecord 和 cdrdao(用于 CD 刻录机)以及 cdparanoia(用于以数字方式读取音频 CD)等应用程序使用 sg。
本节介绍 Linux 和 SCSI 世界中存在的各种命名方案以及它们如何交互。
Linux 对 SCSI 设备采用四级分层寻址方案
SCSI 适配器编号 [host]
通道号 [bus]
ID 号 [target]
lun [lun]
“Lun”是逻辑单元号的常用 SCSI 缩写。括号中的术语是设备伪文件系统 (devfs) 使用的命名约定。在下面的描述中,首选使用“Bus”而不是“channel”。
SCSI 适配器编号通常是计算机内部 IO 总线(例如 PCI、PCMCIA、ISA 等)上的适配器卡的任意编号。此类适配器有时被称为 HBA(主机总线适配器)。 SCSI 适配器编号由内核按升序(从 0 开始)发出。
每个 HBA 可以控制一个或多个 SCSI 总线。各种类型的 SCSI 总线在 附录 A 中列出。
每个SCSI总线上可以连接多个SCSI设备。在SCSI术语中,HBA被称为“发起者”(initiator),并占用一个SCSI ID号(通常为7)。发起者[1]与目标设备通信,这些目标设备通常被称为SCSI设备(例如磁盘)。在SCSI并行总线上,ID的数量与总线宽度有关。8位总线(有时称为“窄总线”)可以有8个SCSI ID,其中1个被HBA占用,剩下7个用于SCSI设备。宽SCSI总线是16位宽,最多可以连接15个SCSI设备(目标设备)。SCSI 3草案标准允许在SCSI总线上存在大量的ID。
每个SCSI设备可以包含多个逻辑单元号(LUN)。这些LUN通常被支持多个媒体的复杂磁带和CD-ROM设备使用。
因此,Linux的SCSI寻址方式是一个四级层次结构
<scsi(_adapter_number), channel, id, lun> |
<host, bus, target, lun> |
设备名称可以被认为是内核驱动程序的入口,该驱动程序控制设备,而不是设备本身。因此,可以有多个设备名称,其中一些可能提供略有不同的特性,但都映射到同一个实际设备。
各种SCSI设备的设备名称位于/dev目录下。传统上,在Linux中,SCSI设备通过其主设备号和次设备号来识别,而不是通过它们的SCSI总线地址(例如,SCSI目标ID和LUN)。设备伪文件系统(devfs)不再使用主设备号和次设备号方案,对于SCSI子系统,它使用基于SCSI总线地址的设备名称[稍后在第3.3节中讨论,并参考:W5]。另外,还有一个名为scsidev的实用程序,它在Linux SCSI子系统的范围内解决这个问题,因此不像devfs那样具有系统范围的影响。Scsidev将在稍后的第3.4节和参考:W6中讨论。
为SCSI磁盘保留了八个块主设备号:8、65、66、67、68、69、70和71。每个主设备号可以容纳256个次设备号,在SCSI磁盘的情况下,这些次设备号细分为如下
[b,8,0] /dev/sda [b,8,1] /dev/sda1 .... [b,8,15] /dev/sda15 [b,8,16] /dev/sdb [b,8,17] /dev/sdb1 .... [b,8,255] /dev/sdp15 |
没有尾随数字的磁盘设备名称指的是整个磁盘(例如/dev/sda),而带有尾随数字的设备名称指的是该磁盘中的15个允许的分区之一[2]。
其余7个SCSI磁盘块主设备号遵循类似的模式
[b,65,0] /dev/sdq [b,65,1] /dev/sdq1 .... [b,65,159] /dev/sdz15 [b,65,160] /dev/sdaa [b,65,161] /dev/sdaa1 .... [b,65,255] /dev/sdaf15 [b,66,0] /dev/sdag [b,66,1] /dev/sdag1 .... [b,66,255] /dev/sdav15 .... [b,71,255] /dev/sddx15 |
所以有128个可能的磁盘(即/dev/sda到/dev/sddx),每个磁盘最多可以有15个分区。相比之下,IDE子系统允许20个磁盘(10个控制器,每个控制器有1个主盘和1个从盘),每个磁盘最多可以有63个分区。
SCSI CD-ROM设备分配的块主设备号为11。传统上sr一直是设备名称,但是scd可能更容易识别,并且受到最近几个发行版的青睐。允许有256个SCSI CD-ROM设备
[b,11,0] /dev/scd0 [or /dev/sr0] [b,11,255] /dev/scd255 [or /dev/sr255] |
SCSI磁带设备分配的字符主设备号为9。支持多达32个磁带设备,每个设备都可以以四种模式之一(0、1、2和3)访问,带或不带回绕。设备分配如下
[c,9,0] /dev/st0 [tape 0, mode 0, rewind] [c,9,1] /dev/st1 [tape 1, mode 0, rewind] .... [c,9,31] /dev/st31 [tape 31, mode 0, rewind] [c,9,32] /dev/st0l [tape 0, mode 1, rewind] .... [c,9,63] /dev/st31l [tape 31, mode 1, rewind] [c,9,64] /dev/st0m [tape 0, mode 2, rewind] .... [c,9,96] /dev/st0a [tape 0, mode 3, rewind] .... [c,9,127] /dev/st31a [tape 31, mode 3, rewind] [c,9,128] /dev/nst0 [tape 0, mode 0, no rewind] .... [c,9,160] /dev/nst0l [tape 0, mode 1, no rewind] .... [c,9,192] /dev/nst0m [tape 0, mode 2, no rewind] .... [c,9,224] /dev/nst0a [tape 0, mode 3, no rewind] .... [c,9,255] /dev/nst31a [tape 31, mode 3, no rewind] |
SCSI通用(sg)设备分配的字符主设备号为21。有256个可能的SCSI通用(sg)设备
[c,21,0] /dev/sg0 [c,21,1] /dev/sg1 .... [c,21,255] /dev/sg255 |
请注意,SCSI通用设备名称使用尾随字母(例如/dev/sgc)已被弃用。
每个SCSI磁盘(但不是每个分区)、每个SCSI CD-ROM和每个SCSI磁带都映射到一个sg设备。不属于这三类(例如扫描仪)的SCSI设备也显示为sg设备。
伪设备[参见第10.1节]可能导致通常不被认为是SCSI的设备显示为SCSI设备名称。例如,ATAPI CD-ROM可能被ide-scsi伪驱动程序拾取并映射到/dev/scd0 .
Thelinux/Documentation/devices.txt内核源代码中提供的文件是Linux设备名称及其对应的主设备号和次设备号分配的权威参考。
设备伪文件系统可以挂载为/dev在这种情况下,它取代了传统的Linux设备子目录。或者,它可以挂载在其他地方(例如/devfs),并补充现有的设备结构。
如果没有devfs,设备名称通常保存在根分区的dev目录下。因此,设备名称(及其相关的权限)具有文件系统持久性。设备名称的存在并不一定意味着存在这样的设备(甚至它的驱动程序)。为了避免用户必须创建设备名称条目(使用mknod 命令),大多数Linux发行版都定义了数千个设备名称/dev目录下。当应用程序尝试open()设备名称时,errno值为ENODEV表示当前没有可用的相应设备(或驱动程序)。
Devfs采用不同的方法,其中设备名称的存在直接与相应设备(及其驱动程序)的存在相关。
假设devfs挂载在/dev那么SCSI设备的主要设备名称可能如下所示
/dev/scsi/host0/bus0/target1/lun0/disc [whole disk] /dev/scsi/host0/bus0/target1/lun0/part6 [partition 6] /dev/scsi/host0/bus0/target1/lun0/generic [sg device for disk] /dev/scsi/host1/bus0/target2/lun0/cd [CD reader or writer] /dev/scsi/host1/bus0/target2/lun0/generic [sg device for cd] /dev/scsi/host2/bus0/target0/lun0/mt [tape mode 0 rewind] /dev/scsi/host2/bus0/target0/lun0/mtan [tape mode 3 no rewind] /dev/scsi/host2/bus0/target0/lun0/generic [sg device for tape] |
[请注意“disc”的拼写,因为devfs作者更喜欢英语拼写而不是美式拼写。] 可以看出,devfs的命名方案与第3.1节中讨论的SCSI寻址密切相关。值得注意的是,IDE子系统使用类似的devfs设备命名方案,其中“scsi”替换为“ide”。有关Devfs的更多信息,请参见第12章。
名为scsidev的实用程序将设备名称添加到/dev/scsi目录,该目录反映了每个设备的SCSI地址。名称的前两个字母是上层SCSI驱动程序名称(即sd,sr,st或sg)。“h”后面的数字是主机号,而“-”后面的数字用于主机识别。“对于PCI适配器,这似乎总是0,而对于ISA适配器,这是它们的IO地址。[也许可以使该字段更具信息性或删除。] “c”,“i”和“l”后面的数字分别是通道(总线),目标ID和lun值。原始磁盘显示时没有尾随分区号,而其中包含的分区显示时带有“p”后面的分区号。
scsidev通常作为启动序列的一部分运行。在SCSI配置更改后运行它也可能很有用(例如,添加或删除较低级别的驱动程序模块,或使用add / remove-single-device命令)。我的系统包含2个磁盘,一个CD读写器和一个扫描仪,运行scsidev后,以下名称已添加到/dev/scsi目录下
$ ls -l /dev/scsi/ # abridged total 0 brw------- 8, 0 Sep 2 11:56 sdh0-0c0i0l0 brw------- 8, 1 Sep 2 11:56 sdh0-0c0i0l0p1 ... brw------- 8, 8 Sep 2 11:56 sdh0-0c0i0l0p8 brw------- 8, 16 Sep 2 11:56 sdh0-0c0i1l0 brw------- 8, 17 Sep 2 11:56 sdh0-0c0i1l0p1 ... brw------- 8, 24 Sep 2 11:56 sdh0-0c0i1l0p8 crw------- 21, 0 Sep 2 11:56 sgh0-0c0i0l0 crw------- 21, 1 Sep 2 11:56 sgh0-0c0i1l0 crw------- 21, 2 Sep 2 11:56 sgh1-0c0i2l0 crw------- 21, 3 Sep 2 11:56 sgh1-0c0i5l0 crw------- 21, 4 Sep 2 11:56 sgh1-0c0i6l0 br-------- 11, 0 Sep 2 11:56 srh1-0c0i2l0 br-------- 11, 1 Sep 2 11:56 srh1-0c0i6l0 |
scsidev软件包还包括引入类似名称的功能/dev/scsi/scanner通过操纵/etc/scsi.alias配置文件。该软件包还包括有用的rescan-scsi-bus.sh实用程序。有关scsidev的更多信息,请参见W6。在我的系统上,devfs和scsidev可以和谐共存。
Linux内核配置通常可以在内核源代码中的文件/usr/src/linux/.config中找到。不建议直接编辑此文件,而是使用以下配置选项之一
make config - 启动基于字符的问题和答案会话
make menuconfig - 启动面向终端的配置工具(使用ncurses)
make xconfig - 启动基于X的配置工具
可以通过相关的帮助按钮显示这些选项的描述,这些描述可以在纯ASCII文件中找到/usr/src/linux/Documentation/Configure.help
最终,这些配置工具会编辑.config文件。一个选项将指示某些驱动程序内置到内核中(“= y”),或者将构建为模块(“= m”),或者未被选择。未选择的状态可以通过以“#”开头的行(例如“#CONFIG_SCSI is not set”)或通过从.config文件中缺少相关行来表示。
以下是SCSI子系统(实际上选择了SCSI中间层驱动程序)的主要选择选项的3种状态。只有其中一种应出现在实际.config文件中
CONFIG_SCSI=y CONFIG_SCSI=m # CONFIG_SCSI is not set |
一些其他常见的SCSI配置选项是
CONFIG_BLK_DEV_SD [disk (sd) driver] CONFIG_SD_EXTRA_DEVS [extra slots for disks added later] CONFIG_BLK_DEV_SR [SCSI cdrom (sr) driver] CONFIG_BLK_DEV_SR_VENDOR [allow vendor specific cdrom commands] CONFIG_SR_EXTRA_DEVS [extra slots for cdroms added later] CONFIG_CHR_DEV_ST [tape (st) driver] CONFIG_CHR_DEV_OSST [OnSteam tape (osst) driver] CONFIG_CHR_DEV_SG [SCSI generic (sg) driver] CONFIG_DEBUG_QUEUES [for debugging multiple queues] CONFIG_SCSI_MULTI_LUN [allow probes above lun 0] CONFIG_SCSI_CONSTANTS [symbolic decode of SCSI errors] CONFIG_SCSI_LOGGING [allow logging to be runtime selected] CONFIG_SCSI_<ll_driver> [numerous lower level adapter drivers] CONFIG_SCSI_DEBUG [lower level driver for debugging] CONFIG_SCSI_PPA [older parallel port zip drives] CONFIG_SCSI_IMM [newer parallel port zip drives] CONFIG_BLK_DEV_IDESCSI [ide-scsi pseudo adapter] CONFIG_I2O_SCSI [scsi command set over i2o bus] CONFIG_SCSI_PCMCIA [for SCSI HBAs on PCMCIA bus] CONFIG_USB_STORAGE [usb "mass storage" type] CONFIG_MAGIC_SYSRQ [Alt+SysRq+S for emergency sync] [Alt+SyrRq+U for emergency remount ro] |
如果根文件系统位于SCSI磁盘上,则将SCSI中间层,sd驱动程序以及磁盘连接到的主机适配器驱动程序构建到内核中是有意义的。在大多数情况下,通常可以安全地将sr,st和sg驱动程序构建为模块,以便根据需要加载它们。如果像扫描仪这样的设备位于单独的适配器上,则其驱动程序很可能被构建为模块。在这种情况下,需要先加载该适配器驱动程序,然后才能识别扫描仪。
Linux发行版具有许多内置为模块的SCSI子系统驱动程序,因为将所有驱动程序都构建在其中将导致内核非常大,从而超出引导加载程序的功能。这导致了一个“鸡和蛋”的问题,即需要SCSI驱动程序来加载根文件系统,反之亦然。initrd设备使用的两阶段加载解决了这个问题(有关更多详细信息,请参见第6章)。
在PC上,主板的BIOS以及大多数SCSI主机适配器提供的SCSI BIOS负责将引导加载程序的映像从SCSI磁盘加载到内存中并执行它。这可能需要更改主板BIOS中的一些设置。当涉及多个SCSI适配器时,可能需要更改SCSI BIOS设置,以指示哪个适配器包含具有引导映像的磁盘。引导映像也可以来自ATA(IDE)磁盘,可引导的CD-ROM或软盘。
lilo和grub都是常用的Linux引导加载程序。它们的配置文件位于/etc/lilo.conf和/etc/grub.conf [3]中。一个区别是,在更改lilo的配置后,必须执行lilo命令才能使更改生效(grub没有等效的要求)。有关用法信息,请参见其“man”页面。有关lilo和Linux启动顺序的优秀论文可以在 ftp://icaftp.epfl.ch/pub/people/almesber/booting/bootinglinux-0.ps.gz中找到。有关grub的更多信息,请参见 www.gnu.org/software/grub。
一些与SCSI子系统相关的启动参数
single [enter single user mode] <n> [enter run level <n> {0..6}] root=/dev/sda6 [*] root=/dev/scsi/host0/bus0/target0/lun0/part6 [*] root=/dev/sd/c0b0t0u0p6 [*] devfs=mount [overrides CONFIG_DEVFS_MOUNT=n] devfs=nomount [overrides CONFIG_DEVFS_MOUNT=y] init=<command> [executes <command> rather than init] quiet [reduce output to console during boot] debug [increase output to console during boot] nmi_watchdog=0 [turn off NMI watchdog on a SMP machine] max_scsi_luns=1 [limits SCSI bus scans to lun==0] scsi_allow_ghost_devices=<n> |
“root=”参数也可以是十六进制数。例如,如果根分区位于/dev/sda3那么“root=803”就是合适的。最后两位数字是在前面章节讨论过的次设备号。
“init”参数的默认值是/sbin/init(参见 man (8) init)。如果像/etc/fstab这样的文件有不正确的条目,直接进入 shell 可能会很有用,使用“init=/bin/bash”。然而,如果共享库文件或其路径不合适,这也可能失败。这样就只剩下“init=/sbin/sash”了,它是一个静态链接的 shell,内置了许多有用的命令(用于修复系统)(参见 man (8) sash)。
当 Linux 报告类似以下的消息后启动失败时:
VFS: Cannot open root device 08:02 |
Lilo 的配置文件/etc/lilo.conf可以通过两种方式使用“root=”选项。通常的方式是一行代码,例如:“root=/dev/sda2”。在这种情况下,/dev/sda2会基于执行 lilo 命令时系统的状态转换为主设备号和次设备号。这可能是一个麻烦,尤其是在硬件要重新排列的情况下。另一种方式是以下形式的一行代码:“append="root=/dev/sda2"”。在这种情况下,/dev/sda2会在下次启动时传递给内核。这与在内核启动时提示符处给出“root=/dev/sda2”字符串相同。它在启动时由内核解释(一旦 HBA 及其连接的设备被识别),因此更灵活。
有很多与 SCSI 相关的模块。中间层和上层模块如下所示:
scsi_mod.o
sd_mod.o
sr_mod.o
st.o [osst.o]
sg.o
请注意,前 3 个模块的名称都附加了“_mod”到其正常的驱动程序名称。较低级别的驱动程序倾向于使用 HBA 制造商的名称(或缩写)(例如 advansys),还可以选择主要控制器芯片的芯片编号(例如,sym53c8xx 用于基于 NCR 53c8?? 系列芯片的 symbios 控制器)。
所有 SCSI 模块都依赖于中间层。这意味着如果 SCSI 中间层没有构建到内核中,并且如果scsi_mod.o尚未加载,那么像 modprobe st 这样的命令将导致scsi_mod.o模块被加载。可能还有其他依赖项,例如,modprobe sr_mod 也会导致 cdrom 模块被加载(如果它还没有被加载)。此外,如果 SCSI 中间层是一个模块,那么所有其他 SCSI 子系统驱动程序都必须是模块(这是由内核构建配置工具强制执行的)。
可以使用 modprobe <module_name> 命令加载模块,该命令将尝试加载任何指定的 <module_name> 所依赖的模块。此外,<module_name> 不需要尾随的“.o”扩展名,如果未给出,则假定该扩展名存在。 insmod <module_name> 命令也将尝试加载 <module_name>,但不会首先加载它所依赖的模块。有关模块如何导致加载其他模块(并附加适当的参数)的规则通常放置在文件中/etc/modules.conf. [请注意,在早期的 Linux 内核中,该文件通常称为/etc/conf.modules。] 有关此文件格式的更多信息,请尝试 man modules.conf。
可以使用以下命令查询任何模块的可允许命令行参数:modinfo -p <module_name>。
当初始化上层驱动程序时,如果没有活动主机,那么中间层将尝试加载一个名为“scsi_hostadapter”的模块。然后可以使用“alias”将“scsi_hostadapter”与较低级别(适配器)驱动程序的实际名称相关联。例如,文件中的一行代码,如“alias scsi_hostadapter aic7xxx”,/etc/modules.conf将导致加载 aic7xxx 模块(如果没有较低级别的驱动程序已处于活动状态)。[4]
模块参数“scsi_hostadapter”和 initrd 文件系统之间存在特殊关系。有关更多信息,请参见 man initrd 和 man mkinitrd。[5]
proc 伪文件系统提供了一些关于 SCSI 子系统的有用信息。选择“proc_fs”的内核配置选项是 CONFIG_PROC_FS,在几乎所有情况下都应该选择它。 SCSI 特定信息位于目录/proc/scsi下。可能最常访问的条目是 cat /proc/scsi/scsi,它列出了连接的 SCSI 设备。 有关更多详细信息,请参见第 8.3 节。
较低级别的驱动程序被分配了以下形式的 proc_fs 条目:
/proc/scsi/<driver_name>/<scsi_adapter_number> |
cdrom 驱动程序在/proc/sys/dev/cdrom目录下提供有关连接的 cdrom 设备的信息。这将包括 SCSI 设备(即由 sr 驱动程序控制的设备)和 IDE 设备(即由 ide-cd 驱动程序控制的设备)。请参见第 9.2.3 节。
sg 驱动程序在/proc/scsi/sg目录下提供有关其状态以及连接的主机和设备的信息。请参见第 9.4.3 节。
有关 proc 伪文件系统的更多一般信息,可以在内核源文件中找到/usr/src/linux/Documentation/filesystems/proc.txt.
SCSI 中间层对于 SCSI 子系统的所有用法都是通用的。可能它最重要的作用是定义所有其他 SCSI 驱动程序使用的内部接口和服务。本文档未讨论这些内部机制[参见参考文献:W2]。
主要的内核配置参数“CONFIG_SCSI”决定了中间层是构建在内核中(当“=y”时)还是作为模块(当“=m”时)。如果“CONFIG_SCSI=m”,那么所有其他 SCSI 子系统驱动程序也必须是模块。
当中间层构建为模块时,可能永远不需要显式加载它,因为使用“modprobe”加载任何其他 SCSI 子系统模块都会导致首先加载中间层(如果它尚未加载)。
如果该驱动程序没有要控制的设备,则一些上层和下层驱动程序不会(完全)加载。 有时报告声音很大,例如对于 imm 驱动程序,该驱动程序控制连接到并行端口的 zip 驱动器
$ modprobe imm imm.o: init_module: No such device |
构建到内核中的 SCSI 驱动程序会按照预定的顺序进行检查,以查看它们可以控制的 HBA 是否存在。用户无法控制此顺序,在大多数情况下,此顺序是任意的,但在某些较旧的 ISA 适配器的情况下,需要停止错误识别 [6] 。
scsi_logging=<n> where <n> is 0 to turn logging off where <n> is non-zero to turn logging on max_scsi_luns=<n> where <n> is a number between 1 and 8 (< lk 2.4.7), >= lk 2.4.7 the upper limit can be much larger scsi_allow_ghost_devices=<n> where (<n> - 1) is the maximum lu number to ghost if the the corresponding device is offline. When <n>==0 (default) then don't ghost any devices (in lk 2.4.26 and later) scsihosts=host0:hosts1::host3 |
最近引入的 devfs 定义了一个“scsihosts”引导时参数,以使用户可以控制它。有关描述,请参见 devfs 文档[参考文献:W5]。传递给“scsihosts”引导选项的列表中的主机名是较低级别驱动程序的名称(例如“scsihosts=advansys:imm::ide-scsi”)。[7] [8] 不需要存在 Devfs 即可使用“scsihosts”。如果给定了“scsihosts”参数,则会在启动消息期间回显该参数。例如
scsi: host order: advansys:imm::ide-scsi |
有关内核参数的完整列表,以及一些解释,可以在文件中找到/usr/src/linux/Documentation/kernel-parameters.txt.
如果系统中存在 SCSI 磁盘,那么通常最好将中间层驱动程序构建到内核中。但是,如果仅定期使用 SCSI 子系统(例如,在 ATAPI CD 刻录机上刻录 CD-R),那么将中间层构建为模块就可以了。模块加载时选项与驱动程序的内置选项相同
scsi_logging_level=<n> where <n> is the logging level mask (0 for logging off) max_scsi_luns=<n> scsihosts=host0::host2 scsi_allow_ghost_devices=<n> |
要显示当前由 SCSI 子系统连接(并识别)的 SCSI 设备,请使用 cat /proc/scsi/scsi。
输出如下所示
Attached devices: Host: scsi0 Channel: 00 Id: 02 Lun: 00 Vendor: PIONEER Model: DVD-ROM DVD-303 Rev: 1.10 Type: CD-ROM ANSI SCSI revision: 02 Host: scsi1 Channel: 00 Id: 00 Lun: 00 Vendor: IBM Model: DNES-309170W Rev: SA30 Type: Direct-Access ANSI SCSI revision: 03 |
在“Attached devices:”行之后,每个已识别的设备都有 3 行。 这些行中的第一行是第 3.1 节中讨论的 SCSI 地址信息。 以下 2 行数据是从设备连接时对其执行的 INQUIRY 命令获得的。有关这些设备的排序与 sg 驱动程序的排序之间的关系,请参见第 9.4 节(在大多数情况下是相同的)。
可以使用 echo "scsi remove-single-device <h> <b> <t> <l>" > /proc/scsi/scsi 删除现有设备,其中变量是主机、总线(通道)、目标(scsi id)和 lun。 可以通过发送随后的 cat /proc/scsi/scsi 命令来确定此命令的成功与否。 如果设备繁忙(例如,如果设备上的文件系统已挂载),则删除将失败。
可以使用 echo "scsi add-single-device <h> <b> <t> <l>" > /proc/scsi/scsi 添加新设备,其中变量是主机、总线(通道)、目标(scsi id)和 lun。 可以通过发送随后的 cat /proc/scsi/scsi 命令来确定此命令的成功与否。 [9]
SCSI 子系统不支持 SCSI 设备的热插拔(关联的 SCSI 并行总线上可能还存在电气问题)。 建议使用 add+remove-single-device 的人确保如果将要重新插入,则该 SCSI 总线上的其他设备处于非活动状态。
要输出内部 SCSI 命令块的列表,请使用 echo "scsi dump <n>" > /proc/scsi/scsi,其中 <n> 的数值无关紧要。 这可能只对在 SCSI 子系统中追查错误的人员感兴趣。
要启动(或停止)将信息发送到控制台/日志,请使用 echo "scsi log <token> <n>" > /proc/scsi/scsi ,其中 <token> 是以下之一:{all, none, error, timeout, scan, mlqueue, mlcomplete, llqueue, llcomplete, hlqueue, hlcomplete, ioctl},<n> 是一个介于 0 和 7 之间的数字。 令牌“all”和“none”不接受 <n> 参数。 前缀含义
hl upper level drivers [exception: sg uses "timeout"] ml mid level ll lower level drivers [adapter drivers often have there own flags] |
![]() | 警告:“scsi log all”(以及其他几个变体)如果日志文件(通常为/var/log/messages)位于 SCSI 磁盘上,则会导致日志记录无限循环。 关闭内核日志记录守护程序或将其输出定向到非 SCSI 设备。 |
高层驱动程序维护内核侧的操作系统接口,以支持它们所代表的设备逻辑类别(例如磁盘)。 它们还负责管理某些内核和 SCSI 子系统资源,例如内核内存和 SCSI 命令结构。 用户空间中的应用程序通过打开一个特殊文件(块或字符)来访问这些驱动程序,这些文件通常位于/dev目录树中。
可以通过 sd 驱动程序访问两种类型的 SCSI 设备:
"直接访问" 设备,通常是磁盘。[SCSI 外围设备代码为 0]
"光存储设备",通常称为 MOD 磁盘。[SCSI 外围设备代码为 7]
sd 驱动程序能够在内核启动时或之后作为模块加载时识别 128 个磁盘。 但是,一旦加载,它将只能识别固定数量的附加磁盘。 可以容纳的附加磁盘数量由内核配置参数 CONFIG_SD_EXTRA_DEVS 设置,其默认值为 40。
CDROM 和 DVD 驱动器(以及 WORM 设备)可以通过 sr 高层设备驱动程序访问。 虽然 "sr" 是设备驱动程序名称,但 "sr_mod" 是其模块名称。 设备文件名是/dev/sr<n>或/dev/scd<n>.
以下图表说明了 sr 所属的 CDROM 子系统
CD-ROM 子系统的架构。
该图忽略了协议栈之间的一些差异。 CDROM 设备名称不是由统一 CDROM 层维护,而是由每个单独的协议栈维护。 在 SCSI 子系统中,设备名称由 sr 驱动程序维护,而 IDE 子系统使用其中心 "ide" 驱动程序(即不是由 ide-cd 驱动程序)维护设备名称。 USB 和 IEEE1394 cd 设备名称由它们各自的协议栈维护。 这可能部分解释了为什么/dev/cdrom通常是指向相应子系统设备名称的符号链接。
可以通过 sr 驱动程序访问两种类型的 SCSI 设备:
CD-ROM 设备(包括 DVD 播放器)[SCSI 外围设备代码为 5]
"一次写入多次读取" 设备,称为 WORM。[SCSI 外围设备代码为 4]
sr 驱动程序能够在内核启动时或之后作为模块加载时识别 256 个 CDROM/DVD 驱动器。 但是,一旦加载,它将只能识别固定数量的附加驱动器。 可以容纳的附加驱动器数量由内核配置参数 CONFIG_SR_EXTRA_DEVS 设置,其默认值为 2。
人们通常使用 dd 命令读取包含 iso9660 文件系统的数据 CDROM。 如果没有给出 count 参数,则 dd 命令将读取 SCSI Read Capacity 命令指示的 2048 字节扇区数。 不幸的是,这可能包括图像末尾未写入(或“用完”)的扇区,这可能会导致 I/O 错误。 使用 isosize 命令(请参阅其手册页)查找 iso9660 图像的真实长度,并在提供给 dd 命令的 "count=" 参数中使用该长度。
执行测试以查明 CDROM 驱动器是否支持 XA 模式(模式 2)会在某些驱动器上触发固件错误。 因此,默认情况下会关闭 XA 模式支持的检查。 提供以下模块参数
xa_test=<0|1> |
以下所有文件都可以被所有人读取,并且在读取时会产生 ASCII 输出
/proc/sys/dev/cdrom/autoclose /proc/sys/dev/cdrom/autoeject /proc/sys/dev/cdrom/check_media /proc/sys/dev/cdrom/debug /proc/sys/dev/cdrom/info /proc/sys/dev/cdrom/lock |
例如,可以使用命令 echo "1" > /proc/sys/dev/cdrom/autoeject 来启用超级用户的自动弹出功能。 这将导致在卸载时从驱动器中弹出 CDROM。
许多 Linux 用户的系统中没有 SCSI 设备(或适配器)。 他们有点困惑为什么 CD 刻录软件(例如 cdrecord 和 cdrdao)和 CD 音乐读取程序(例如 cdparanoia)使用 Linux SCSI 子系统。 答案是这些程序需要对这些设备进行更低级别的访问。 ATAPI(ATA 数据包接口)本质上是通过 ATA [10] 传输发送的 SCSI 命令集。[本节中的讨论也适用于 ATAPI 磁带机和 ATAPI 软盘驱动器。]
目前,cdrecord 和 cdparanoia 都连接到 SCSI 通用驱动程序 (sg),并且在 ATAPI cd 设备的情况下,使用 ide-scsi 伪设备驱动程序来访问硬件。 这种情况将来可能会发生变化,因为在 2.4 系列内核中,数据包接口 ioctl 已添加到统一 cdrom 层(请参阅上面 第 9.2 节中的图表)。 [11]
Linux 中 IDE 子系统的默认操作是声明所有 ATA 设备都用于其内置驱动程序。 在 ATAPI CD 刻录机的情况下,它将被内置的 ide-cd 驱动程序声明。 发生这种情况后,SCSI 子系统将无法控制 ATAPI 设备。 ide-scsi(伪低层 SCSI)驱动程序只能在 SCSI 子系统中注册尚未被 IDE 子系统声明的 ATAPI 设备。
请注意上一段中的内置限定词。 如果 ide-cd 和 ide-scsi 驱动程序都是模块,则第一个加载的驱动程序将声明 ATAPI CD 设备(例如,CD/DVD 读取器和刻录机)。 此外,您可以通过 rmmod 一个驱动程序并 modprobe 另一个驱动程序来切换控制驱动程序模块。
可能指示 IDE 核心驱动程序您希望位于/dev/hdd的 CD 刻录机可被 cdrecord 访问的最灵活的方法是使用内核引导选项:"hdd=ide-scsi"。 这将导致 ide-cd 驱动程序绕过/dev/hdd(无论 ide-cd 驱动程序是内置的还是模块)。 只要 ide-scsi 驱动程序是内置的或模块,它就会在/dev/hdd“捕获” CD 刻录机(如果需要,IDE 核心驱动程序会加载 ide-scsi 模块)。
可以指示 ide-cd 驱动程序使用以下语法忽略某些 ATA 设备
modprobe ide-cd ignore='hdc hdd' |
中放置类似这样的行来实现此效果:"options ide-cd ignore=hdd"。 在 lk 2.4 系列中添加的一个新选项的形式为 "hdd=scsi"。 此选项似乎与上面讨论的 "hdd=ide-scsi" 选项具有类似的功能。 此外,只有在 SCSI 中间层和 ide-scsi 驱动程序都内置于内核中时,才能使用 "hdd=scsi"(否则 ide_setup 函数会报告 "BAD OPTION")。
要查明 ATAPI CD 设备是否由 SCSI 子系统 "拥有",可以检查 cat /proc/scsi/scsi 的输出。 另一种技术是观察 cat /proc/sys/dev/cdrom/info 的 "drive name:" 行是否有 "sr" 条目。 以下输出来自我的系统
$ cat /proc/sys/dev/cdrom/info CD-ROM information, Id: cdrom.c 3.12 2000/10/18 drive name: sr1 sr0 drive speed: 16 0 drive # of slots: 1 1 Can close tray: 1 1 Can open tray: 1 1 Can lock tray: 1 1 Can change speed: 1 1 Can select disk: 0 0 Can read multisession: 1 1 Can read MCN: 1 1 Reports media changed: 1 1 Can play audio: 1 1 Can write CD-R: 1 0 Can write CD-RW: 1 0 Can read DVD: 0 1 Can write DVD-R: 0 0 Can write DVD-RAM: 0 0 |
一旦 SCSI 子系统注册了 /dev/hdd 处的 ATAPI CD 刻录机,就应该通过 "scd" 设备名称安装 CDROM,并且 CD 播放器也应该使用 "scd" 设备。 奇怪的是,hdparm 命令仍然应该使用/dev/hdd设备文件(或本节中描述的 "echo ... > /proc/ide/hdd/settings" 方法)。 [12]
磁带机驱动程序接口记录在文件中/usr/src/linux/drivers/scsi/README.st以及 st(4) 手册页(键入 man st)。 文件README.st还记录了驱动程序的各种参数和选项,以及驱动程序中使用的基本机制。
通常通过 mt 命令访问磁带机驱动程序(请参阅 man mt)。 mtx 是用于控制磁带自动加载器的相关程序(请参阅 mtx.sourceforge.net)。
除非它们出现在驱动程序的 "reject_list" 上,否则 st 驱动程序会检测到外围设备类型为 "Sequential-access"(代码编号 1)的那些 SCSI 设备。[目前,OnStream 磁带机(在后面的章节中描述)是此 reject_list 中唯一的条目。]
st 驱动程序能够识别 32 个磁带机。 每个磁带机都有 8 个设备文件名:4 种模式(编号为 0 到 3)的每种模式都有一个倒带和非倒带变体。 请参阅第 3.2 节中有关设备名称的磁带设备文件名示例。 加载 st 驱动程序后,可以添加任意数量的磁带机(最多 32 个的总体限制)。
ATAPI 磁带机可以在 ide-scsi 伪适配器驱动程序的帮助下由该驱动程序控制。 第 9.2.4 节中的讨论也适用于 ATAPI 磁带机(和 ATAPI 软盘)。
st=xxx[,yyy] where xxx is one of the following: buffer_kbs:<n> write_threshold_kbs:<n> max_buffers:<n> max_sg_segs:<n> (The old boot parameters st=aa[,bb[,cc[,dd]]] supported but deprecated) |
默认驱动程序缓冲区大小 (buffer_kbs) 为 32 (即 32 KB)。默认异步写入阈值 (write_threshold_kbs) 为 30 (即 30 KB)。初始化时分配的默认缓冲区数量 (max_buffers) 为 4。要使用的散布/收集段的默认数量 (max_sg_segs) 为 32。
有一个辅助磁带驱动程序,用于 OnStream 制造的磁带驱动器。它是一个附加的上层驱动程序,可以与 st 驱动程序共存。其驱动程序名称为 "osst" (也是其模块名称)。
OnStream SC-x0 SCSI 磁带驱动器不能由标准的 st 驱动程序驱动,而需要此特殊的 osst 驱动程序并使用/dev/osst<x>字符设备节点 (主设备号 206)。 [其中 <x> 遵循与 第 3.2 节 中概述的 st 设备相同的命名方案。] 通过 usb-storage 和 ide-scsi,您也可以驱动 USB-x0 和 DI-x0 驱动器。请注意,还有第二代 OnStream 磁带驱动器 (ADR-x0),它支持用于磁带的标准 SCSI-2 命令 (QIC-157),并且可以由标准驱动程序 st 驱动。有关更多信息,您可以查看内核源文件/usr/src/linux/drivers/scsi/README.osst。有关 OnStream 驱动程序的更多信息,请访问 linux1.onstream.nl/test/。
所有类型的 SCSI 设备都可以通过 sg 驱动程序访问。这意味着 CDROM 驱动器等设备可以通过 sr 和 sg 驱动程序访问。其他 SCSI 设备(例如扫描仪)只能通过 sg 驱动程序访问。 sg 驱动程序能够识别 256 个 SCSI 设备。加载 sg 驱动程序后,可以添加任意数量的设备(最多达到 256 的总体限制)。
有关 SCSI 通用 (sg) 驱动程序文档,请参阅参考文献 W4(sg_utils 包也位于其中)。 有关 SCSI 标准,请参阅参考文献 W1,有关 SCSI 编程和传递机制主题的书籍,请参阅参考文献 B3。
lk 2.4 中的 sg 驱动程序是“版本 3”,它添加了一个额外的接口结构和一些新的 ioctl()。 最有趣的新 ioctl() 是 SG_IO,它发送 SCSI 命令并等待其响应。 有关 sg 驱动程序的完整描述,请参阅 Linux 文档项目站点: www.tldp.org/HOWTO/SCSI-Generic-HOWTO/。 可以在 www.torque.net/sg/p/sg_v3_ho.html 找到此文档的(可能较新的)版本。
缩写 "sg" 在内核中用于指代 SCSI 通用驱动程序和许多现代 IO 设备提供的散布/收集功能(通常与 DMA 相关)。 上下文通常可以清楚地表明正在引用哪个。 例如,请注意扭曲的 sg ioctl(),名为 SG_GET_SG_TABLESIZE,其中第二个 "SG" 指的是散布收集。
sg 的公共接口位于文件中/usr/src/linux/include/scsi/sg.h。 根据发行版,这可能包含与/usr/include/scsi/sg.h相同的信息,后者由 GNU 库维护人员控制。 如果这 2 个文件不相同,请使用前一个头文件。 那些基于 sg 编写应用程序的人应该参阅其文档以了解更多相关信息。
sg 驱动程序会注册所有 SCSI 设备(当前最多 256 个),因为它们会被看到。 每个新注册的 SCSI 设备都会分配下一个可用的次设备号。 至少在最初,这将与设备在中间层的 cat /proc/scsi/scsi 中显示的顺序相同。 可以使用 cat /proc/scsi/sg/devices 或 cat /proc/scsi/sg/device_strs 查看 sg 设备设备映射。 当删除低级驱动程序(例如 rmmod aha1542)或使用 remove-single-device 删除设备时,cat /proc/scsi/scsi 和 sg 排序之间会出现差异。 sg 驱动程序将保留剩余的 SCSI 设备映射到次设备号不变。 这可能会在 sg 映射中留下一个“孔”。 下面是一个例子
$ cat /proc/scsi/scsi Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: IBM Model: DNES-309170W Rev: SA30 Type: Direct-Access ANSI SCSI revision: 03 Host: scsi1 Channel: 00 Id: 02 Lun: 00 Vendor: PIONEER Model: DVD-ROM DVD-303 Rev: 1.10 Type: CD-ROM ANSI SCSI revision: 02 Host: scsi1 Channel: 00 Id: 06 Lun: 00 Vendor: YAMAHA Model: CRW4416S Rev: 1.0g Type: CD-ROM ANSI SCSI revision: 02 $ cat /proc/scsi/sg/device_strs IBM DNES-309170W SA30 PIONEER DVD-ROM DVD-303 1.10 YAMAHA CRW4416S 1.0g $ echo "scsi remove-single-device 1 0 2 0" > /proc/scsi/scsi $ cat /proc/scsi/scsi Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: IBM Model: DNES-309170W Rev: SA30 Type: Direct-Access ANSI SCSI revision: 03 Host: scsi1 Channel: 00 Id: 06 Lun: 00 Vendor: YAMAHA Model: CRW4416S Rev: 1.0g Type: CD-ROM ANSI SCSI revision: 02 $ cat /proc/scsi/sg/device_strs IBM DNES-309170W SA30 <no active device> YAMAHA CRW4416S 1.0g |
新的 sg_io_hdr 接口包括一个名为 "resid" 的数据传输剩余计数字段。 只有一些较低级别的适配器支持此功能,那些不支持此功能的适配器始终在此字段中产生零。 在撰写本文时,advansys、aha152x 和 sym53c8xx 驱动程序支持此功能。
sg 驱动程序为每个打开的文件描述符维护一个保留缓冲区。 目的是保证应用程序的数据传输大小不超过保留缓冲区的大小,而不会因为缺少内核内存而失败。 这对于像 cdrecord 这样的应用程序很重要,因为它们无法轻易地从 ENOMEM 错误中恢复(CDR)。
在没有启动参数 'sg_def_reserved_size' 或 sg 模块参数 'def_reserved_size' 的情况下,每次打开 sg 文件描述符时,保留缓冲区大小都会从 SG_DEF_RESERVED_SIZE 继承,该值在include/linux/sg.h.
中定义。 可以通过此内核启动选项覆盖 SG_DEF_RESERVED_SIZE 定义值
sg_def_reserved_size=<n> |
所有人都可以读取以下所有文件,并在读取时生成 ASCII 输出。 root 用户也可以写入文件 'def_reserved_size'。 ASCII 输出的格式经过格式化,以便人类和机器可读(因此是一种折衷)。 使用 Unix 命令 cat device_hdrs devices 查看表的输出。
/proc/scsi/sg/debug [internal state of sg driver] /proc/scsi/sg/def_reserved_size [like boot/module load parameter] /proc/scsi/sg/devices [table of numeric device data] /proc/scsi/sg/device_hdr [column headers for sg/devices] /proc/scsi/sg/device_strs [table of strings from INQUIRY] /proc/scsi/sg/hosts [table of numeric host data] /proc/scsi/sg/host_hdr [column headers for sg/hosts] /proc/scsi/sg/host_strs [table of string ids for hosts] /proc/scsi/sg/version [sg version number and date] |
SCSI 低级驱动程序太多,无法在此文档中详细说明。 作为对任何表面概述的替代方案,本文档向读者提供了一些查找更多信息的地方的建议。
Linux 内核中 SCSI 子系统的源代码目录是一个很好的起点/usr/src/linux/drivers/scsi。 几个驱动程序在 "readme" 文件中有信息README.<driver_name>。 其他驱动程序在其 ".c" 文件的顶部有大量信息。 此信息通常包括版本号、更改日志以及内核启动时间和模块加载时间选项。 通常,可以在各种 Linux 发行版的安装指南中找到后一种信息。 有时,驱动程序维护人员会有一个包含最新错误修复信息的网站。 官方维护人员列在/usr/src/linux/MAINTAINERS文件中。 如果那里没有任何内容,请查看 SCSI 子系统目录中的相关 ".c" 文件。 一些旧的驱动程序没有活跃的维护人员。 在这种情况下,发布到 linux-scsi 新闻组可能会有所帮助 [参见 N1 ]。
要了解内核源代码树提供的驱动程序的概述,请使用内核配置程序之一(例如 cd /usr/src/linux; make menuconfig)。 与每个选择关联的帮助信息可以在一个(大)平面文件中一起找到,位于/usr/src/linux/Documentation/Configure.help。 可以从其他地方获得驱动程序。 为 lk 2.2 系列(或之前)制作的 SCSI 驱动程序不太可能在 lk 2.4 系列中成功构建或运行。 [从编程的角度来看,没有很多需要更改的内容。] 驱动程序甚至可能仅以二进制形式提供,在这种情况下,请确保您信任提供商并严格按照他们的说明进行操作。
低级驱动程序可以支持 2 种错误处理策略中的任何一种。 较旧的一种被认为是过时的,而较新的一种通常称为 "new_eh"。 "new_eh" 的优势在于它为每个主机使用一个单独的内核线程(名为 "scsi_eh_<n>",其中 <n> 是主机号)来促进错误恢复。 两种错误处理策略在 lk 2.2 系列中也可用,其中极少有适配器驱动程序使用 "new_eh"。 在 lk 2.4 系列中,更多驱动程序正在使用它,并且即将到来的 lk 2.5 开发系列的计划是删除对较旧的过时错误策略的中间层支持。
Drew Eckhardt 的 SCSI-HOWTO 文档 [参见参考文献 W7 ] 比本文档更详细地介绍了低级(适配器)驱动程序。 由于该 SCSI-HOWTO 已有 5 年的历史,因此许多事情发生了变化,并且添加了更多驱动程序。
有一个名为 scsi_debug 的低级驱动程序,它使用计算机的内存模拟一个或多个“直接访问”设备(即磁盘)。 从 lk 2.4.17 开始,它充当“ram 磁盘”。 虽然 Linux 中有很多 ram 磁盘实现可用(例如 ramfs),但 scsi_debug 可能有助于隔离问题安装中存在问题的 scsi 驱动程序。 见scsi_debug.c了解更多信息。
SCSI 可以被视为一个命令集和一组传输该命令集的硬件总线。 这些硬件总线可以进一步分为专门用于 SCSI 的总线(例如,超宽),与其他协议共享的总线(例如,USB,IEEE 1394)以及未由各种 SCSI 标准定义的总线。 在最后一个类别中,有几个有趣的例子,包括 ATAPI CD 刻录机和 PC 并行总线 ZIP 驱动器。 这种设备在外部总线上使用 SCSI 命令集(或非常接近它的东西)。
本节简要概述了各种伪低级驱动程序,它们本质上与其他 Linux 子系统通信,以便将 SCSI 命令集发送到由这些其他子系统控制的设备。 这提出了一些所有权问题,这些问题经常使使用者感到困惑,并导致对维护人员提出许多问题。
IDE-SCSI。 从配置的角度来看,ide-scsi 将获取并尝试控制每个没有附加 "native" 驱动程序 (例如 ide-cd, ide-tape 等) 的 ATA (也称为 IDE) 设备。 例如,如果 ide-cd 和 ide-scsi 都编译到内核中,而在系统中有一个 ATAPI cdrom,则 ide-cd 将获得控制权。 如果只编译了 ide-scsi,它将获得该设备。 有一些内核启动时间参数可以控制哪个驱动程序获得哪个设备。
IDE子系统的偏好设置可以通过以下内核启动参数来覆盖(对于此子系统而言,第一个参数最重要):
hdx=ide-scsi
hdx=ide-cdrom
hdx=ide-floppy
当驱动程序运行时,该设备将可以通过 SCSI 设备 (/dev/sda, /dev/sr0等)访问,而不是通过对应的/dev/hdx设备。尽管如此,该/dev/hdx设备仍然可用,但仅用于配置。
所有通用的 IDE 配置参数(DMA 开启/关闭,32 位 I/O,取消屏蔽 IRQ 等)都可以通过使用/dev/hdx设备来设置,例如启用 DMA。
hdparm -d1 /dev/hdx |
bios_cyl
bios_head
bios_sect
transform
log
位 0:启用(1)/禁用(0) 并非来自 sg 驱动程序的命令的转换。
位 1:启用/禁用使用 sg 驱动程序发出的命令的转换。
echo "log:1" > /proc/ide/hdx/settings |
echo "using_dma:0" > /proc/ide/hdx/settings |
PPA + IMM. Iomega ZIP 驱动器有多种类型,包括并行端口、SCSI 和 ATAPI。并行端口版本(旧的和新的)分别由 ppa 和 imm 驱动。
并行端口 ZIP 驱动器实际上是 SCSI 设备,它使用名为 VPI0(旧样式)和 VPI2(新样式)的接口通过并行端口隧道传输 SCSI 命令。ppa 驱动程序是 VPI0 主机实现,imm 驱动程序是 VPI2 主机实现。
它的工作方式是,HBA 是 ZIP 驱动器内部的一个芯片,因此主机适配器和外围设备在同一个实际外壳中。
PPSCSI. 用于通过并行端口电缆使用 SCSI 的设备的新架构(尚未集成)是 ppscsi。 ppscsi 模块提供样板代码,并且可以轻松地为不同的接口编写实现。
每个 ppscsi 协议模块都会向 ppscsi 模块注册自身,并传入一个入口点列表,这些入口点对于所有协议驱动程序都是通用的。
PPSCSI 驱动程序的结构。
计划是 ppscsi 架构将吸收 ppa 和 imm 驱动程序以及协议模块;到目前为止,只编写了 vpi0。 请参阅 www.torque.net/parport/ppscsi.html。
USB. USB 将一组设备分类为“大容量存储”(例如磁盘),并使用 SCSI 命令集与它们交互。 模块名称是“usb-storage”。 请参阅 www.one-eyed-alien.net/~mdharm/linux-usb。
还有 usb/microtek 驱动程序,用于控制 Microtek 的 X6 USB 扫描仪。 配置后,SANE 应用程序使用 sg 驱动程序通过 USB 发送 SCSI 命令来控制此扫描仪。
I2O. 请参阅内核源文件/usr/src/linux/drivers/i2o/io2_scsi.c.
IEEE 1394. 现在可以使用支持 SBP-2 协议的 IEEE 1394 设备 (lk 2.4.7)。 有关更多信息,请参阅此节中的 IEEE 1394 段落。
iSCSI. IETF 草案正在形成 iSCSI。 这通过 TCP 网络连接发送 SCSI 命令集。 iSCSI 似乎正在迅速普及,并且 Linux 有几个正在形成的实现。 其中一个实现位于 sourceforge.net/projects/intel-iscsi/。 使用您喜欢的搜索引擎查找其他项目。
原始设备可以绑定到现有的块设备(例如磁盘),并用于对该现有块设备执行“原始”IO。 这种“原始”IO 绕过了通常与块设备关联的缓存。 因此,原始设备提供了通往物理设备的更“直接”的途径,并允许应用程序更好地控制对该物理设备进行 IO 的时序。 这使得原始设备适用于复杂的应用程序,例如通常进行自己的缓存的数据库管理系统。
原始设备是字符设备(主设备号为 162)。 第一个次设备号(即 0)保留作为控制接口,通常位于/dev/rawctl。 可以使用名为 raw 的实用程序(参见 man raw)将原始设备绑定到现有块设备。 这些“现有块设备”可以是磁盘或 cdrom/dvd,它们的基础接口可以是 Linux 支持的任何东西(例如 IDE/ATA 或 SCSI)。
以下命令序列列出了原始设备,然后绑定了 SCSI 磁盘分区,然后绑定了整个磁盘:
$ ls -lR /dev/raw* crw-r--r-- 1 root root 162, 0 Dec 6 06:54 /dev/rawctl /dev/raw: total 0 crw-r--r-- 1 root root 162, 1 Dec 6 06:54 raw1 crw-r--r-- 1 root root 162, 2 Dec 6 06:54 raw2 crw-r--r-- 1 root root 162, 3 Dec 6 06:54 raw3 crw-r--r-- 1 root root 162, 4 Dec 6 06:54 raw4 $ $ raw -qa $ $ raw /dev/raw/raw1 /dev/sda3 /dev/raw/raw1: bound to major 8, minor 3 $ raw /dev/raw/raw2 /dev/sda /dev/raw/raw2: bound to major 8, minor 0 $ raw -qa /dev/raw/raw1: bound to major 8, minor 3 /dev/raw/raw2: bound to major 8, minor 0 |
用于字符设备的常用系统调用阵列可用于原始设备。 read(2) 和 write(2) 的传输大小必须是物理设备块大小的整数倍。 对于磁盘,这将是其扇区大小,通常为 512 字节。 提供给 read() 和 write() 系统调用的数据缓冲区必须与块大小对齐。 lseek(2) 调用还需要将其文件读取/写入偏移量与块边界对齐。 pread(3) 调用(参见 man pread)结合了 read() 和 lseek(),并且对原始设备可能很有用(pwrite() 也是如此)。 在 32 位架构上,如果 "off_t" 类型为 32 位长,则应注意大于 2 GB(或可能为 4 GB)的偏移量。 一种解决方案是使用 _llseek() 调用(参见 man llseek)。
诸如最新版本的 dd 和 lmdd(来自 lmbench 程序套件)之类的 Unix 实用程序可用于将数据移动到“原始”设备和从“原始”设备移动数据,因为它们满足上述块对齐要求。 sg_utils 包中的 sg_dd 命令的最新版本可以访问原始设备和 sg 设备。
另请注意,如果物理设备的扇区数为奇数(如 blockdev --getsize /dev/raw/raw* 所示),则无法使用原始 IO 访问最后一个扇区。
![]() | 如果通过绑定的原始设备以及通过其正常块接口访问块设备,则两种访问机制之间没有缓存一致性。 例如,如果/dev/sda1既已挂载又通过绑定的原始设备进行访问,则可能存在数据不一致的情况。 |
devfs 的主要文档可以在以下位置找到:参考 W5。 SCSI 子系统的 devfs 命名约定在 第 3.3 节中概述。 Devfs 通过内核构建选项 CONFIG_DEVFS_FS 选择,以及是否在启动时挂载它(如/dev)由内核构建选项 CONFIG_DEVFS_MOUNT 控制。 后一个选项可以被内核启动时选项“devfs=mount”或“devfs=nomount”覆盖,以合适者为准。
带有其默认权限的 devfs SCSI 节点名称是
disc rw------- whole disk including mbr part1 rw------- first partition {...p1} ... part15 rw------- 15th partition {...p15} cd rw-rw-rw- cd or dvd devices mt rw-rw-rw- tape mode 0 with rewind {...m0} mtl rw-rw-rw- tape mode 1 with rewind {...m1} mtm rw-rw-rw- tape mode 2 with rewind {...m2} mta rw-rw-rw- tape mode 3 with rewind {...m3} mtn rw-rw-rw- tape mode 0 with no rewind {...m0n} mtln rw-rw-rw- tape mode 1 with no rewind {...m1n} mtmn rw-rw-rw- tape mode 2 with no rewind {...m2n} mtan rw-rw-rw- tape mode 3 with no rewind {...m3n} generic rw-r----- |
只有在相应的设备(或设备的子实体(例如分区))和驱动程序存在时,这些节点名称才会存在。 例如,如果没有 sg 驱动程序,则没有“通用”设备名称。 上面括号中出现的字符串将根据需要在下面概述的缩写“c0b0t0u0”符号中附加。
作为块或字符特殊文件的 devfs 文件名将在此描述中称为主要设备名称。 devfs 守护程序(称为 devfsd)引入了许多指向这些主要设备名称的符号链接。 这是为了向后兼容性和方便性而完成的。 这些符号链接将被称为辅助设备名称。
辅助设备名称由 devfsd 配置文件控制,该文件通常位于/etc/devfsd.conf。 以下是使用默认 devfsd.conf 文件时的辅助设备名称列表:
Secondary name slink to this primary device name -------------------------------------------------------------- /dev/sda /dev/scsi/host0/bus0/target2/lun0/disc /dev/sda1 /dev/scsi/host0/bus0/target2/lun0/part1 /dev/sd/c0b0t2u0 /dev/scsi/host0/bus0/target2/lun0/disc /dev/sd/c0b0t2u0p1 /dev/scsi/host0/bus0/target2/lun0/part1 /dev/sr0 /dev/scsi/host0/bus0/target4/lun0/cd /dev/sr/c0b0t4u0 /dev/scsi/host0/bus0/target4/lun0/cd /dev/st0 /dev/scsi/host1/bus0/target0/lun0/mt /dev/nst0a /dev/scsi/host1/bus0/target0/lun0/mtan /dev/st/c1b0t0u0m0 /dev/scsi/host1/bus0/target0/lun0/mt /dev/st/c1b0t0u0m3n /dev/scsi/host1/bus0/target0/lun0/mtan /dev/sg0 /dev/scsi/host0/bus0/target2/lun0/generic /dev/sg1 /dev/scsi/host0/bus0/target4/lun0/generic /dev/sg2 /dev/scsi/host1/bus0/target0/lun0/generic /dev/sg/c0b0t2u0 /dev/scsi/host0/bus0/target2/lun0/generic /dev/sg/c0b0t4u0 /dev/scsi/host0/bus0/target4/lun0/generic /dev/sg/c1b0t0u0 /dev/scsi/host1/bus0/target0/lun0/generic |
请注意,更常见的/dev/scd0不支持 SCSI cdrom 的变体。 还有/dev/discs, /dev/cdroms和/dev/tapes包含指向属于该类别的所有设备(即不仅是 SCSI 设备)的符号链接的目录。
Secondary name slink to this primary device ------------------------------------------------------------ /dev/discs/disc0 /dev/ide/host0/bus0/target0/lun0 * /dev/discs/disc1 /dev/scsi/host0/bus0/target2/lun0 * /dev/cdroms/cdrom0 /dev/ide/host0/bus1/target1/lun0/cd /dev/cdroms/cdrom1 /dev/scsi/host0/bus0/target4/lun0/cd /dev/tapes/tape0 /dev/scsi/host1/bus0/target0/lun0 * |
标有“*”的条目是包含主要设备的目录。 请注意,IDE/ATA 设备在 SCSI 设备之前列出。 这些辅助设备名称模仿与主要设备名称相同的持久性规则。 因此,当删除 SCSI 设备 (?) 或其较低级别的驱动程序或其较高级别的驱动程序时,与它关联的主要和辅助设备名称也会被删除。
当 devfs 挂载为/dev时,旧的“/dev/sda6”类型仍然可以在某些上下文中使用。 如果需要在内核启动时提示输入,这可能很方便。 例如,如果用户想要更改“devfs”计算机上的根分区,则可以使用以下任何示例作为内核启动时选项:
root=/dev/sda6 root=/dev/scsi/host0/bus0/target0/lun0/part6 root=/dev/sd/c0b0t0u0p6 |
有许多设备扫描程序希望看到预 devfs 设备名称存在,并且需要一些时间才能使它们意识到 devfs。 此外,某些程序依赖于打开/dev/sg0(例如)来加载 sg 驱动程序(假设它是一个模块并且尚未加载)。 这可以通过/etc/devfsd.conf文件中的条目进行安排,以及以下内容
LOOKUP sg.* MODLOAD |
probeall /dev/sg scsi-hosts sg alias /dev/sg* /dev/sg |
可以使用此条目更改 sg 设备的权限,在/etc/devfsd.conf文件中
REGISTER scsi/host.*/bus.*/target.*/lun.*/generic PERMISSIONS 0.0 rw-rw-rw- |
应用程序可以通过文件/dev/.devfsd.
是否存在来确定 devfs 是否处于活动状态。 基于持久文件系统(例如 ext2)的 /dev 目录的一个功能是能够将权限与设备文件名关联,并将其从一次启动保持到下一次启动。 如上所述,devfs 的默认操作是在每次启动计算机时重新分配设备文件名权限。/etc/devfsd.conf中的 PERMISSIONS 操作可用于断言权限,但这可能被认为有点笨拙。 devfs 文档 (W5) 描述了一种获得两全其美的方法。 此技术依赖于 lk 2.4 中最近添加的功能,以在多个点挂载相同的文件系统。
可以在 www.pctechguide.com/04disk2.htm 找到本附录中涉及的各种总线类型(SCSI 和其他)的非常好的概述。
SCSI. 最初的 SCSI 1 标准(ANSI 规范 X3.131-1986)引入了 8 位并行总线,该总线能够以 1.5兆字节/秒的速度进行异步传输,并以高达 5 MB/秒的速度进行同步传输。 SCSI 命令以异步速率发送。 SCSI 数据以异步速率(最坏情况)或协商的同步速率(最佳情况为 5 MB/秒)传输。
FAST SCSI. SCSI 2 标准将最大同步速度提高到 10 MB/秒。 SCSI 2 定义了几个并行总线:单端(如 SCSI 1 使用)和新的差分总线。 差分总线具有更好的抗噪声能力,其最大总线长度为 25 米(相比之下,单端的总线长度为 6 米)。 SCSI 2 还增加了命令的标记排队。
WIDE SCSI(宽 SCSI). SCSI 2 标准也增加了总线的宽度,允许 16 位和 32 位的“宽”变体。32 位宽度的使用非常少,所以“宽”通常指的是 16 位宽的数据通路。可以连接到并行 SCSI 总线的 SCSI 设备的最大数量与总线宽度直接相关,因此“宽”总线允许连接最多 16 个 SCSI 设备。[这些设备中至少有一个必须是 SCSI “发起者”,通常是主机适配器。]
ULTRA SCSI(超 SCSI). 传统上,同步总线在时钟的上升沿或下降沿计时(通常是方波)。最近的趋势是在两个边沿都计时,从而使可用带宽加倍。这就是 ULTRA SCSI 如何将 SCSI 2 的“快速”速度加倍到 20 MB/秒的方式。
ULTRA WIDE SCSI(超宽 SCSI). 将相同的“超”技术应用于 (16 位) 宽 SCSI 并行总线,可以产生 40 MB/秒的带宽。
ULTRA 2 WIDE SCSI(超 2 宽 SCSI). 这种变体引入了一种新的“低电压”差分信号 (LVD),当使用 (16 位) 宽总线时,可以使同步时钟速度加倍,产生 80 MB/秒的速度。 在这种情况下,SCSI 总线的最大长度为 12 米。 为了与 ULTRA WIDE 向后兼容,这种变体可以回退到“单端”操作。 这导致适配器制造商使用缩写 LVD/SE。 这种方法的一个缺点是,在 U2W 总线上存在一个 UW 设备会导致所有其他 U2W 设备以较慢的(即 UW)速率通信。 一些适配器通过在同一逻辑 SCSI 总线上具有单独的 LVD 和 SE 物理总线来克服这个问题。
ULTRA 160 SCSI(超 160 SCSI). ULTRA 160 再次将并行 SCSI 总线带宽加倍。 它使用 16 位宽的数据通路、LVD 信号(参见前面的条目)和双跃迁时钟,将最大同步带宽提高到 160 MB/秒。 其他功能包括循环冗余校验码 (CRC) 以提高数据完整性(与奇偶校验位相比),以及如果错误率过高则调整传输速率的域验证。
ULTRA 320 SCSI(超 320 SCSI). ULTRA 320 适配器很快就会上市(具有该接口的磁盘已经在市场上销售)。 这也是一个 16 位宽的 LVD 总线,可以回退到较慢的速度以与旧设备兼容。 它通过将时钟速度加倍来扩展 Ultra 160 的功能。 包含分组 SCSI,它以全总线速度(而不是 5 MB/秒)发送命令和状态。 其他改进包括“快速仲裁和选择”、“读取和写入数据流”以及命令块和数据的 CRC 保护(Ultra 160 仅对数据进行 CRC 保护)。 请注意,需要使用 64 位 PCI(或更好的:PCI-X)的适配器卡,以防止 PCI 总线成为这些速度的瓶颈。 更多信息可以在 www.scsita.org 上找到。 最近,一家 Ultra 320 HBA 供应商声称每秒高达 105,000 次 IO 操作,这意味着每个命令的 SCSI 总线开销小于 10 微秒。 有一个 ULTRA 640 标准草案,但可能会被 Serial Attached SCSI 超越。
Serial Attached SCSI (SAS)(串行连接 SCSI). Serial Attached SCSI (SAS) 使用与 Serial ATA (sATA) 相同的传输技术并对其进行扩展。[sATA 在下面描述。] SAS 可以使用外部扩展器从单个 HBA 控制多达 16000 个设备。 数据传输是全双工的,并且可以聚合 1.5 Gbps 或 3.0 Gbps 的 "phys" 以增加带宽。 电缆长度可以达到 6 米。 SAS 磁盘是双端口的。 sATA 磁盘可以连接到 SAS 扩展器(但 SAS 磁盘不能连接到 sATA HBA)。 SAS 最近在 CeBit 上进行了演示,但直到 2004 年才会上市。
FC-AL. 这代表 Fibre Channel - Arbitrated Loop(光纤通道仲裁环路),可能涉及跨越 10 公里的双 2 千兆位/秒单模光纤链路,吞吐量高达 400 兆字节/秒。 通常与存储区域网络 (SAN) 相关联。 最多可以将 126 个设备连接到一个环路,该环路又可以在公共环路模式中扩展到 1600 万个设备。 传输介质不一定是光纤电缆:铜缆(同轴电缆的形式)也可以在较低速度和较短距离中使用。
SRP/InfiniBand. SRP (SCSI RDMA Protocol) [ SRP_draft] 是 InfiniBand 的 SCSI 传输协议 [ Infiniband_trade_association],一种运行在 10 和 30 Gbps 的高性能互连技术。 SRP 驱动程序源代码可在 infiniband.sourceforge.net/Storage/SRP 找到。
IEEE 1394. 该标准也被称为 "Fire Wire" [由 Apple 注册商标] 和 "iLink" [由 Sony 注册商标]。 它是一种串行总线,可以以高达 400 兆位/秒 (IEEE 1394a) 的速度运行。 一个较新的标准 IEEE 1394b 将其提升到 800 兆位/秒(扩展到 1.6 和 3.2 千兆位/秒),电缆运行长度可达 100 米。 它具有与 USB 类似但更通用的架构。 IEEE 1394 标准允许通过 1394 总线传输 SCSI 命令集。 现在有一个 "sbp2" 驱动程序可用于 Linux IEEE 1394 堆栈。 此 sbp2 驱动程序也是一个 SCSI 子系统底层驱动程序(因此它在功能上类似于 ide-scsi 驱动程序)。 因此,可以使用 SBP-2 协议的 IEEE 1394 设备(例如,磁盘、cd-rw/dvd 驱动器、MO 驱动器和扫描仪)可以通过 SCSI 子系统访问。 有关更多信息,请参见 Linux1394.sourceforge.net。 sbp2 驱动程序现在在 lk 2.4.7 中。
iSCSI. 这是新的 IETF 标准,用于通过 TCP 连接(或多个连接)发送 SCSI 命令集。 这允许 SCSI 设备(例如磁盘等目标)成为网络设备,由主机在本地(或可能在很远的距离)访问。
NON SCSI buses(非 SCSI 总线). 以下总线不是由 SCSI 标准定义的,但由于它们可以携带 SCSI 命令集、在某种程度上与 Linux SCSI 子系统相关,或者为 SCSI 产品提供类似的功能而备受关注。
IDE/ATA (ATAPI). IDE 是当今 PC 系统上最常用的磁盘类型。 该缩写代表 Integrated Drive Electronics(集成驱动器电子设备),顾名思义,它将大部分 IO "智能" 放在磁盘控制器卡上,而不是像 SCSI 那样在设备(最常见的是磁盘)和控制器 (HBA) 之间分配。 IDE 在 20 世纪 80 年代从 ST506 和 ESDI 标准发展而来。 EIDE (extended IDE) 是一个相关的缩写。 指代此总线架构的现代标准称为 ATA,可以在 www.t13.org 找到。 ATA Packet Interface (ATAPI) 扩展了面向磁盘的命令集以支持 CDROM 和磁带驱动器。 ATAPI 命令集与 SCSI 命令集非常相似。 最新的 ATA 技术在下一段中概述。
ATA 133. IDE 设备使用的 ATA 标准也一直在通过形容词(例如,快速和超速)和数字(例如,2、33、66、100 和 133)。 最新添加的是 ATA 133,它支持 133 MB/秒的突发速率,每个总线最多支持 2 个设备。[PC 通常有 2 个甚至 4 个 ATA 总线。] ATA 66、100 和 133 需要特殊的电缆。 ATA 电缆相对较短,因此 IDE 设备无法放置在计算机外部。 电缆长度以前限制为 18 英寸,但现在已经出现 1 米长的电缆。 巧合的是,133 MB/秒也是大多数 PC 中常见的普通 PCI 总线的最大吞吐量。 存在更高速度(和更宽)的 PCI 版本,但它们相对罕见。
Serial ATA (sATA)(串行 ATA). Serial ATA 使用 2 个差分线对以 1.5 吉比特/秒的速度与 1 米以内的 sATA 磁盘交换数据。 一对将数据传输到磁盘,另一对从磁盘返回数据。 数据速率高达每秒 150 兆字节是可能的(数据传输是半双工的)。 sATA 是一种点对点连接,而不是总线,因此 ATA 的主从跳线消失了。 sATA 布线不太笨重,并且其插头和插座的外形尺寸小于并行 ATA(和 SCSI 并行接口)。 sATA 设备已开始出现在市场上。 sATA-2 是一个标准草案,它将串行数据速率加倍到每秒 3 吉比特。
USB. 通用串行总线 (USB) 的带宽介于 1.5 和 12 兆位/秒之间(后一种速度与 USB 1.1 一起使用)。 最多可以连接 127 个设备,方法是使用一系列集线器,每个集线器最多连接 7 个设备(限制为 5 米)。 USB 提供 5 伏特 @ 0.5 安培的电压来为小型设备供电。 USB 是“即插即用”的,支持热插拔,并支持等时数据传输(音频和视频设备需要保证的最小带宽)。
PC Parallel port(PC 并行端口). 原始的 PC 并行端口是单向的(朝向打印机),能够达到大约 10 KB/秒的速度。 1994 年的 IEEE 1284 标准引入了 5 种数据传输模式
Compatibility mode (forward direction)(兼容模式(正向))
Nibble mode (reverse direction)(半字节模式(反向))
Byte mode (reverse direction)(字节模式(反向))
EPP mode (bi-directional)(EPP 模式(双向))
ECP mode (bi-directional)(ECP 模式(双向))
I2O. “I2O(智能输入/输出)规范定义了一种智能 I/O 的标准架构,该架构独立于受控的特定设备和主机操作系统 (OS)” [来自 www.i2osig.org]。 它定义了一个“分离驱动程序”模型,其中 OS 服务模块 (OSM) 位于主机 OS 设备接口和 I2O 通信层之间,而硬件设备模块 (HDM) 位于 I2O 通信层和硬件之间。 HDM 很可能在专用处理器 (IOP) 上运行。
已经完成了大量工作,将 lk 2.2 中使用的单个 SCSI 命令队列更改为每个设备一个命令队列。 为了使 SCSI 子系统更适合 SMP,锁的粒度更精细。 在 lk 2.2 中,整个子系统基本上使用一个锁。
即使它不是 SCSI 子系统的一部分,包含 devfs 也解决了过去存在的许多 SCSI 设备寻址问题。 与 devfs 相关联但在没有它的情况下也很有用的是 "scsihosts" 内核启动时间(和模块加载时间)选项。 此选项允许用户控制多个 SCSI 主机的排序。
此附录难以维护,因为已证明在 lk 2.4(及其开发树)中有用的特性和驱动程序已倾向于向后移植到 lk 2.2 系列的更高版本号中。
目前 (lk 2.4.2) MO 设备的支持已损坏。据报告,块大小为 2048 字节的旧 DOS 文件系统也已损坏。问题似乎出现在物理块大小大于块子系统使用的 1 KB 逻辑块大小的介质上。只有 sd 驱动程序存在此问题(幸运的是,sr 驱动程序没有,在 sr 驱动程序中,2048 字节扇区是常态)。
没有接口更改。在 lk 2.2 中,启动后可以添加的额外磁带设备的最大数量限制为 3。此限制已删除(如前所述,留下最多 32 个磁带设备)。
在 lk 2.4 中,添加了一个名为 "osst" 的变体 st 驱动程序来处理早期型号的 OnStream 磁带驱动器。
主要的更改是添加了一个名为 "sg_io_hdr" 的新接口结构。发现现有的接口结构(称为 "sg_header")不灵活,需要在 read() 和 write() 命令中将原始数据与元数据连接在一起。
sg_io_hdr {new interface structure} SG_IO {new ioctl} direct IO {present but commented out, see ALLOW_DIO} procfs output {new information in /proc/scsi/sg directory} boot/module parameters {new} |
可以从 sg_io_hdr 接口结构中获取最多 64 字节的 sense 数据。此外,还可以获得与数据传输相关的剩余计数(如果较低级别的驱动程序支持,如果不支持,则剩余计数将为 0)。
即使 lk 2.4 产品系列旨在“稳定”,但也进行了大量更改以及错误修复。以下列表不包括对较低级别(适配器)驱动程序的更改。列表中的每个项目都以引入它的内核版本为前缀。[14]
[2.4.4] 添加了 SCSI_IOCTL_GET_PCI ioctl(),
[2.4.7] 如果该设备的 INQUIRY 显示的 SCSI 级别高于 SCSI_2,则不再将 "lun" 位(代表 SCSI 1 和 SCSI 2 标准中 lun 值 0 到 7 的 3 位)屏蔽到 SCSI 命令的第二个字节中,
[2.4.7] max_scsi_luns 内核(和模块 scsi_mod)选项以前可以是 1 到 7。现在上限值可以很大。[扫描算法仍然执行顺序扫描,而不是使用 REPORT_LUNS。]
[2.4.7] scsi_unregister_host() 和 scsi_unregister_module() 现在都返回一个 int(以前它们是 void 函数)。它们返回 0 表示成功,返回 -1 表示失败(通常是忙),
[2.4.7] 上层驱动程序现在在连接时报告正确的 scsi 设备名称。[以 "Detected ..." 开头的日志消息以前有时会报告错误的设备(例如,sdc 而不是 sdb)。]内核启动消息现在会将 SCSI 设备显示为 "Attached ...",
[2.4.7] 'max_sectors' 已添加到 Scsi_Host 结构中,
[2.4.8] 更改了一些中级逻辑,以便在 sense 缓冲区指示逻辑单元正在准备就绪时重试命令 [ASC=4, ASQ=1],
[2.4.9] 一项主要的 st 更新,
[2.4.9] 中级更改为在下级(适配器)驱动程序返回 DID_RESET 时重试命令,
[2.4.10] 保存原始结果(包括 SCSI 状态),以便在中级发出 REQUEST SENSE 时可以之后恢复它,
[2.4.10] 将 BLKGETSIZE64、BLKBSZSET 和 BLKBSZGET ioctl 添加到 sd + sr,
[2.4.10] sg 更新,修复了 generic_unplug_device() 竞争 + 增加了 opens 上的 access_count(并在 releases 上减少),
[2.4.11] 在大多数驱动程序中添加了 MODULE_LICENSE 宏,主要是 MODULE_LICENSE("GPL"),
[2.4.11] 为每个命令增加 scsi_pid(为什么?),
[2.4.11] st 更新以增加 access_count。现在,所有上层驱动程序都会在 opens 上递增 access_count,并在 releases 上递减它,
[2.4.13] scatterlist 结构增长(删除了 alt_address,添加了 page 和 offset),
[2.4.13] 不要为 target <= SCSI_2 探测 lun > 7,
[2.4.14] 与 scatterlist 结构更改相关的微调(错误修复)[它破坏了 st ?],
[2.4.15] 允许 16 字节 SCSI 命令 [MAX_COMMAND_SIZE 从 12 更改为 16]。HBA 驱动程序必须将 Scsi_Host::max_cmd_len 设置为 16,以便中级转发 16 字节 SCSI 命令,
[2.4.15] BLKGETSIZE + BLKGETSIZE64 ioctl() 实现已从 SCSI 子系统移出(并移至块子系统),
[2.4.15] 大型 st 更新,
[2.4.15] lk 2.5.0 分支,因此 lk2.4.15==lk2.5.0 。
[2.4.17] 将 generic_unplug_device() 调用添加到 scsi_wait_req()。这可以停止 SCSI_IOCTL_SEND_COMMAND 中的长时间等待。
[2.4.17] 修复设备扫描错误,在某些情况下,scsi_level(即,SCSI 标准遵守情况)被错放。
[2.4.17] 主要的 sg 驱动程序更新,添加 mmap()-ed IO
[2.4.18] 允许上层驱动程序 "init()" 函数(例如,sd_init() )正常失败。[添加 Scsi_Device::detected 和 scsi_unregister_module() 。]
[2.4.18] 修复 MO 设备上的群集(SCSI 命令)。
[2.4.18] st 驱动程序更新(压缩算法)。
[2.4.18] 更新 Documentation/scsi.txt 和 scsi-generic.txt 。
[2.4.18] 修改 scsi_debug 驱动程序 。
[2.4.19] 添加了 Scsi 预留和重置功能。预留允许多台机器共享同一设备(通过预留/释放机制)。需要 Scsi 重置(通过 sg)来“中断”由无响应机器持有的预留。
[2.4.19] 引入 BLIST_LARGELUN 以处理大于 7 的 LUN,尽管报告为 SCSI 2。
[2.4.19] 更改 sd 和 sr,以便 RECOVERED_ERROR 不被视为硬错误。向日志/控制台发送警告。
[2.4.19] 在使用前清零 sg 的缓冲区。[Sg 版本从 3.1.22 升级到 3.1.24,但这并未在 sg.h 中反映出来(表面上的)。]
[2.4.20] 添加了对 highmem I/O 的支持。由 aic7xxx、3w-xxxx、esp、megaraid、qlogicfc 和 sym53c8xx_2 LLD 使用。
[2.4.20] 将 "blocking_open" 启动时间,模块加载时间参数添加到 st。
[2.4.21] 为新的 HBA 提供一个新的主机编号(高于任何先前使用过的),除非存在 "scsihosts" 匹配。只有在存在 "scsihosts" 匹配时,才会重新使用主机编号序列“漏洞”。
[2.4.21] 停止 SCSI 状态 RECOVERED ERROR 被中级视为错误(补充了 2.4.19 中的更改)。
[2.4.21] 使用 TEST_UNIT_READY 命令(而不是 START_STOP)来确定可移动介质是否已更改(在 sd 驱动程序中)。
[2.4.21] ide-scsi 驱动程序的主要工作。
[2.4.21] 为 Adaptec Ultra 320 控制器添加 aic79xx 驱动程序。
[2.4.22] 将 SEND DIAGNOSTIC 命令的超时时间延长至 2 小时。这适用于前台扩展自检。
[2.4.26] 添加 'scsi_allow_ghost_devices' 内核启动时间和 scsi_mod 模块选项。
[2.4.27] 引入了通过 "libata" 库的 SATA 支持。SATA 磁盘显示带有 SCSI 子系统名称(例如,"/dev/sdb"),并通过命令转换工具响应 SCSI 命令。
许多 SCSI 问题是由布线和(缺乏或不适当的)端接引起的。这通常会导致重复的 SCSI 总线重置、奇偶校验或 CRC 错误,有时还会降低传输速度。在此站点上有一个很好的 SCSI 端接教程: www.scsita.org/aboutscsi/SCSI_Termination_Tutorial.html。该站点上还有其他有用的 SCSI 信息(请参见W9)。
还有一个 SCSI "faq" 站点(请参见W10),其中解决了许多配置和故障排除问题。尽管该站点的主要重点是 Windows(及其 ASPI 接口),但其中许多与 Linux 和其他 Unix 实现中的 SCSI 相关。
当看起来某些东西部分锁定了系统时,ps 命令可用于找出可能导致问题的原因。以下选项可用于识别内核的哪个部分可能导致问题。此信息可以转发给维护人员。
ps -eo cmd,wchan ps -eo fname,tty,pid,stat,pcpu,wchan ps -eo pid,stat,pcpu,nwchan,wchan=WIDE-WCHAN-COLUMN -o args |
如果系统没有响应击键,则在文本模式下,<Alt+ScrollLock> 应输出堆栈跟踪,而 <Ctrl+ScrollLock> 应输出所有进程的列表。如果日志仍在工作,则输出将发送到那里以及出现在控制台上。
如果内核已使用 CONFIG_MAGIC_SYSRQ 构建,则在文本模式下,<Alt+SysRq+H> 将列出可用的命令。在这些命令中,<Alt+SysRq+S> 可用于执行紧急同步,而 <Alt+SysRq+U> 将以只读模式重新挂载文件系统。之后,<Alt+SysRq+B> 以重新启动机器可能是你的下一步行动。
scu. SCSI 命令实用程序 (SCU) 实现了正常维护和诊断 SCSI 外围设备所需的各种 SCSI 命令。它的一些功能包括:格式化、扫描(和重新分配)坏块、下载新固件、执行诊断并获取性能信息。它可在多个 Unix 平台(和 NT)上使用,但目前仅以二进制形式提供。有关更多详细信息,请参见 www.bit-net.com/~rmiller/scu.html。
dd. 非常有用,用于测试磁盘和 cdrom/dvds 的流式传输性能。有关更多详细信息,请参见 man dd。这是一个定时磁盘从块 0 开始读取 1 GB(10**9 字节)需要多长时间的示例
$ time dd if=/dev/sda of=/dev/null bs=512 count=1953126 |
$ time dd if=/dev/raw/raw1 of=/dev/null bs=512 count=1953126 |
dt. 数据测试 (DT) 程序以 dd 的语法为模型,但 dt 可以做比顺序复制更多的事情。它是一个全面的数据测试程序,用于 SCSI 设备,例如磁盘、磁带和 cdrom/dvds。它可在多个 Unix 平台(和 NT)上使用,并且其源代码可用(与其稳定的伙伴“scu”不同,如前所述)。有关更多详细信息,请参见 www.bit-net.com/~rmiller/dt.html。
lmdd. 此命令是 lmbench 程序套件的一部分,是 dd 命令的一个变体。它专为 IO 测量而定制,并在完成后输出计时和吞吐量数字。因此,不再需要 time 命令和计算器。
blockdev. 获取块设备(通常是磁盘)的扇区大小、扇区数和预读状态。也可用于刷新缓冲区和重新读取分区表。请参阅 man blockdev。
sg_dd. 此命令是 sg_utils 包的一部分 (参见 W4),是 dd 命令的另一个变体,其中输入和/或输出文件是 sg 或原始设备。块大小参数 ("bs") 必须与相关物理设备的大小匹配。“skip”和“seek”参数在 32 位体系结构上可以达到 2**31 - 1,从而可以访问 1TB 的磁盘 (2G * 512)。Linux 系统命令 llseek() 用于以 64 位文件读/写偏移量进行查找。lmdd 不处理 > 2GB 的情况,dd 命令则使用多个相对查找来进行处理。sg_dd 具有 "bpt" (每次传输的块数) 参数,用于控制每次 IO 事务中读取或写入的块数。
sg_utils 包中还有其他程序可以扫描 SCSI 总线 (sg_scan 和 sg_map),测量 SCSI 总线吞吐量 (sg_rbuf 和 sg_turs ),显示来自 SCSI inquiry 命令的数据 (sg_inq),以及启动(或停止)介质 (sg_start)。
dd_rescue + scsiinfo. 此 dd 变体旨在抢救损坏的介质,例如 SCSI(或 IDE)磁盘和 CDROM (参见 W6)。用于显示和更改模式页面信息的 scsiinfo 实用程序也位于该站点。
sard. 此实用程序模仿 System V Release 4 的 sar -d,用于生成已挂载设备和分区的 IO 统计信息。它由 Stephen Tweedie 开发,包括 sard 实用程序和一个必需的内核补丁,该补丁扩展了以下内容的输出:/proc/partitions。它可以在 ftp.uk.linux.org/pub/linux/sct/fs/profiling 找到。与 vmstat 等程序(请参阅 "man vmstat")相比,它以相对较低的级别(例如,SCSI 中间级别)收集统计信息。
本附录中的编译选项是系统管理员可能希望更改的选项。当然,默认值的选择使得绝大多数用户无需修改任何内容。在某些情况下,设置内核构建时选项、内核启动时参数或模块加载参数与更改驱动程序编译时选项具有相同的效果。
系统调用充当应用程序和内核及其驱动程序之间的接口。在使用 SCSI 子系统的分层驱动程序体系结构中,上层驱动程序处理大部分系统调用。
SCSI 子系统具有 "bubble down" ioctl 结构。首先,与打开的文件描述符关联的上层驱动程序尝试解码 ioctl。如果它无法识别它,则 ioctl 将传递到中间层。如果中间层无法识别它,则 ioctl 将传递到与文件描述符关联的下层驱动程序。如果下层驱动程序无法识别它,则会生成 EINVAL 错误。
一些 ioctl 被分派到相关的子系统。
内核源代码中的以下头文件与中间层相关:
/usr/src/linux/include/scsi/scsi.h /usr/src/linux/include/scsi/scsi_ioctl.h |
这些文件供应用程序使用(除了 __KERNEL__ 条件编译块中的部分)。它们也可能在 /usr/include/scsi 目录中找到,但最好不要信任这些版本,因为它们与 glibc 库一起维护,并且可能滞后于使用的内核版本。通常在 Linux 系统中/usr/include/linux可以依靠它作为内核源代码 include 区域的符号链接(通常是/usr/src/linux/include/linux)。此符号链接可用于包含正确的scsi_ioctl.h使用以下技巧#include <linux/../scsi/scsi_ioctl.h>
此包含文件/usr/src/linux/drivers/scsi/scsi.h是 SCSI 子系统的关键内部头文件。因此,除了指出它与本节开头提到的包含文件具有相同的文件名(但它位于不同的目录中)之外,这里将不再讨论它。这有时会引起混淆。
中间层drivers/scsi/scsi_scan.c文件维护一个已知 SCSI 设备的数组,这些设备具有特性。[这以前被称为“黑名单”,但认为这过于武断。] 该数组名为 "device_list"。各种值是
BLIST_NOLUN 只探测 lun 0
BLIST_FORCELUN 强制探测所有 8 个 lun
BLIST_BORKEN 将 broken 标志传递到下层驱动程序
BLIST_KEY 发送神奇的 MODE SENSE (pc=0x2e) 以解锁设备
BLIST_SINGLELUN 一次只允许在一个 lun 上进行 IO
BLIST_NOTQ 禁用标记队列
BLIST_SPARSELUN 在未找到 lun 后继续
BLIST_MAX5LUN 只探测到 lun 5
BLIST_ISDISK 使用磁盘(直接访问)类型覆盖 INQUIRY 的类型
BLIST_ISROM 使用 ROM 覆盖 INQUIRY 的类型
请参阅以下文件
/usr/src/linux/include/scsi/scsi.h |
请注意,include/scsi/scsi.h 中定义的 SCSI 状态常量从 SCSI 标准中的值向右移动 1 位
scsi.h constant value SCSI 2 standard value ---------------------------------------------------- CHECK_CONDITION 0x1 0x2 CHECK_GOOD 0x2 0x4 BUSY 0x4 0x8 .... |
ioctl() 的摘要如下
SCSI_IOCTL_SEND_COMMAND This interface is deprecated - users should use the scsi generic (sg) interface instead, as this is a more flexible approach to performing generic SCSI commands on a device. The structure that we are passed should look like: struct sdata { unsigned int inlen; [i] Length of data written to device unsigned int outlen; [i] Length of data read from device unsigned char cmd[x]; [i] SCSI command (6 <= x <= 16) [o] Data read from device starts here [o] On error, sense buffer starts here unsigned char wdata[y]; [i] Data written to device starts here }; Notes: - The SCSI command length is determined by examining the 1st byte of the given command. There is no way to override this. - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha). - The length (x + y) must be at least OMAX_SB_LEN bytes long to accommodate the sense buffer when an error occurs. The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that old code will not be surprised. - If a Unix error occurs (e.g. ENOMEM) then the user will receive a negative return and the Unix error code in 'errno'. If the SCSI command succeeds then 0 is returned. Positive numbers returned are the compacted SCSI error codes (4 bytes in one int) where the lowest byte is the SCSI status. See the drivers/scsi/scsi.h file for more information on this. SCSI_IOCTL_GET_IDLUN This ioctl takes a pointer to a "struct scsi_idlun" object as its third argument. The "struct scsi_idlun" definition is found in <scsi/scsi.h>. It gets populated with scsi host, channel, device id and lun data for the given device. Unfortunately that header file "hides" that structure behind a "#ifdef __KERNEL__" block. To use this, that structure needs to be replicated in the user's program. Something like: typedef struct my_scsi_idlun { int four_in_one; /* 4 separate bytes of info compacted into 1 int */ int host_unique_id; /* distinguishes adapter cards from same supplier */ } My_scsi_idlun; "four_in_one" is made up as follows: (scsi_device_id | (lun << 8) | (channel << 16) | (host << 24)) These 4 components are assumed (or masked) to be 1 byte each. SCSI_IOCTL_GET_BUS_NUMBER In lk 2.2 and earlier this ioctl was needed to get the host number. During lk 2.3 development the SCSI_IOCTL_GET_IDLUN ioctl was changed to include this information. Hence this ioctl is only needed for backward compatibility. SCSI_IOCTL_TAGGED_ENABLE Probably a remnant of the past when the mid level addressed such issues. Now this functionality is controlled by the lower level drivers. Best ignored. SCSI_IOCTL_TAGGED_DISABLE See comment for SCSI_IOCTL_TAGGED_ENABLE. SCSI_IOCTL_PROBE_HOST This ioctl expects its 3rd argument to be a pointer to a union that looks like this: union probe_host { unsigned int length; /* [i] max length of output ASCII string */ char str[length]; /* [o] N.B. may need '\0' appended */ }; The host associated with the device's fd either has a host dependent information string or failing that its name, output into the given structure. Note that the output starts at the beginning of given structure (overwriting the input length). N.B. A trailing '\0' may need to be put on the output string if it has been truncated by the input length. A return value of 1 indicates the host is present, 0 indicates that the host isn't present (how can that happen?) and a negative value indicates an error. SCSI_IOCTL_DOORLOCK SCSI_IOCTL_DOORUNLOCK SCSI_IOCTL_TEST_UNIT_READY Returns 0 if the unit (device) is ready, a positive number if it is not or a negative number when there is an OS error. SCSI_IOCTL_START_UNIT SCSI_IOCTL_STOP_UNIT SCSI_EMULATED_HOST {same as SG_EMULATED_HOST <new>} SCSI_IOCTL_GET_PCI Yields the PCI slot name (pci_dev::slot_name) associated with the lower level (adapter) driver that controls the current device. Up to 8 characters are output to the locations pointed to by 'arg'. If the current device is not controlled by a PCI device then errno is set to ENXIO. [This ioctl() was introduced in lk 2.4.4] |
相关文件请参阅
include/linux/hdreg.h include/linux/genhd.h include/linux/fs.h |
ioctl() 的列表如下
HDIO_GETGEO_BIG HDIO_GETGEO [retrieve disk geometry] BLKGETSIZE [number of sectors in device] BLKROSET [set read only flag] BLKROGET [get read only flag] BLKRASET [set read ahead value] BLKRAGET [get read ahead value] BLKFLSBUF [instructs SCSI subsystem to flush buffers] BLKSSZGET [get device block size] BLKPG [partition table manipulation] BLKELVGET [get elevator parameters] BLKELVSET [set elevator parameters] BLKRRPART [reread the partition table] open() (all flags ignored) close() ioctl() (see list above) |
请参阅以下文件
/usr/src/linux/include/linux/cdrom.h /usr/src/linux/drivers/cdrom/cdrom.c [revision history section] /usr/src/linux/Documentation/cdrom/cdrom-standard.tex |
cdrom-standard.tex 中描述了一些以下 ioctl
CDROMCLOSETRAY CDROM_SET_OPTIONS CDROM_CLEAR_OPTIONS CDROM_SELECT_SPEED CDROM_SELECT_DISC CDROM_MEDIA_CHANGED CDROM_DRIVE_STATUS CDROM_CHANGER_NSLOTS CDROM_LOCKDOOR CDROM_DEBUG CDROM_GET_CAPABILITY DVD_READ_STRUCT DVD_WRITE_STRUCT DVD_AUTH CDROM_SEND_PACKET CDROM_NEXT_WRITABLE CDROM_LAST_WRITTEN |
scd 设备的 open() 上的 O_NONBLOCK 标志非常重要。如果没有它,open() 将等待直到设备中有介质才返回。
open() O_NONBLOCK close() read() write() ioctl() |
以下大多数编译选项可以通过启动/模块参数和/或运行时配置(即 ioctl)来覆盖。
以下参数在 linux/drivers/scsi/st_options.h 中定义
ST_NOWAIT {0} ST_IN_FILE_POS {0} ST_RECOVERED_WRITE_FATAL {0} ST_DEFAULT_BLOCK {0} ST_BUFFER_BLOCKS {32} ST_WRITE_THRESHOLD_BLOCKS {30} ST_MAX_BUFFERS {4} ST_MAX_SG {16} ST_FIRST_SG {8} ST_FIRST_ORDER {5} ST_TWO_FM {0} ST_BUFFER_WRITES {1} ST_ASYNC_WRITES {1} ST_READ_AHEAD {1} ST_AUTO_LOCK {0} ST_FAST_MTEOM {0} ST_SCSI2LOGICAL {0} ST_SYSV {0} |
以下参数在 linux/drivers/scsi/st.c 中定义
ST_TIMEOUT {900*HZ} ST_LONG_TIMEOUT {14000*HZ} |
Linux 磁带接口在/usr/src/linux/include/linux/mtio.h.
中定义。以下 ioctl() 按字母顺序列出,右侧附有简要说明。[有关更多详细信息,请参阅 st 文档(尤其是 man 4 st)。]
MTIOCTOP [execute tape commands and set drive/driver options] MTIOCGET [get the status of the drive] MTIOCPOS [get the current tape location] open() O_RDONLY, O_RDWR close() read() write() ioctl() |
内核源代码中的以下头文件与 sg 驱动程序相关
/usr/src/linux/include/scsi/sg.h |
正如 第 E.1 节 中指出的那样,最好使用以下方式将其包含在应用程序中
#include <linux/../scsi/sg.h> |
以下是一些来自 sg.h 文件的定义,用户可能希望更改。当前的默认值显示在右侧的大括号中
SG_SCATTER_SZ {32768} SG_DEF_RESERVED_SIZE {SG_SCATTER_SZ} SG_DEF_FORCE_LOW_DMA {0} SG_DEF_FORCE_PACK_ID {0} SG_DEF_KEP_ORPHAN {0} SG_MAX_QUEUE {16} SG_DEFAULT_RETRIES {1} # i.e. don't retry SG_BIG_BUFF {SG_DEF_RESERVED_SIZE} SG_DEFAULT_TIMEOUT {60 seconds} SG_DEF_COMMAND_Q {0 *} SG_DEF_UNDERRUN_FLAG {0} * The per file descriptor copy of this flips to 1 (thus allowing command queuing) as soon as a write() based on the newer sg_io_hdr structure is detected. |
以下 ioctl() 按字母顺序列出,右侧附有简要说明。[有关更多详细信息,请参阅 sg 文档。]
SG_EMULATED_HOST [indicate if adapter is ide-scsi] SG_GET_COMMAND_Q [command queuing flag state] SG_GET_KEEP_ORPHAN [interrupted SG_IO keep orphan flag state] SG_GET_LOW_DMA ["low dma flag" (<= 16 MB on i386) state] SG_GET_NUM_WAITING [number of responses waiting to be read()] SG_GET_PACK_ID [pack_id of next to read() response (-1 if none)] SG_GET_REQUEST_TABLE [yields array of requests being processed] SG_GET_RESERVED_SIZE [current size of reserved buffer] SG_GET_SCSI_ID [a little more info than the mid level's SCSI_IOCTL_GET_IDLUN ioctl] SG_GET_SG_TABLESIZE [max entries in host's scatter gather table] SG_GET_TIMEOUT [yields timeout (unit: jiffies (10ms on i386))] SG_GET_TRANSFORM [state of ide-scsi's transform flag] SG_IO [send given SCSI command and wait for response] SG_NEXT_CMD_LEN [change command length of next command] SG_SCSI_RESET [send a SCSI bus, device or host reset] SG_SET_COMMAND_Q [set command queuing state {old=0, new=1}] SG_SET_DEBUG [set debug level {0}] SG_SET_KEEP_ORPHAN [set SG_IO's keep orphan flag {0}] SG_SET_FORCE_LOW_DMA [force DMA buffer low (<= 16 MB on i386) {0}] SG_SET_FORCE_PACK_ID [so read() can fetch by pack_id {0}] SG_SET_RESERVED_SIZE [change default buffer size {SG_DEF_RESERVED_SIZE}] SG_SET_TIMEOUT [change current timeout {60 secs} ] SG_SET_TRANSFORM [set ide-scsi's ATAPI transform flag {0}] open() [recognized oflags: O_RDONLY, O_RDWR, O_EXCL, O_NONBLOCK] close() read() write() ioctl() poll() [used when in O_NONBLOCK mode] fasync() [enables generation of SIGIO signal for read()] |
WEB. 以下参考资料可在 Web 上找到。如果这些链接中的任何一个失效,请通知作者。
[W1] SCSI(草案)标准、资源:www.t10.org
[W2] Eric Youngdale 是 Linux SCSI 子系统的首席架构师: www.andante.org/scsi.html
[W4] 作者的 scsi generic (sg) 站点是: www.torque.net/sg。Linux 文档项目的站点包括 www.tldp.org/HOWTO/SCSI-Generic-HOWTO/ 。该文档的(可能较新的)版本可以在 www.torque.net/sg/p/sg_v3_ho 找到。sg_utils 和 sg3_utils 软件包(作为 tarball 以及二进制和源代码 rpms)也可以在此页面上找到。这些软件包以及 sg 驱动程序可用的其他软件包在 www.torque.net/sg/u_index.html 讨论。
[W5] Richard Gooch 的 devfs 站点: www.atnf.csiro.au/~rgooch/linux/docs/devfs.html
[W6] Kurt Garloff 的站点(包括 scsidev 和 scsiinfo 实用程序): www.garloff.de/kurt/linux/。Kurt 还在该站点提供损坏介质抢救程序 dd_rescue: www.garloff.de/kurt/linux/ddrescue
[W7] Drew Eckhardt 1996 年的 SCSI-HOWTO (ASCII): metalab.unc.edu/pub/Linux/docs/HOWTO/unmaintained/SCSI-HOWTO
[W8] Linux 文档项目 (LDP): tldp.org
[W9] SCSI 贸易协会网站包含大量有用信息: www.scsita.org
[W10] SCSI FAQ 站点 - 有用的信息和链接来源: www.scsifaq.org
NEWSGROUPS. 以下条目实际上是 reflectors,而不是新闻组。各种 Web 位置存档其内容(例如 marc.theaimsgroup.com)。
[N1] Linux SCSI reflector< linux-scsi@vger.kernel.org >。这是一个相对低容量(每月约 200 个帖子)的 Linux SCSI 特定组,许多 SCSI 子系统维护者都在监控它。
[N2] Linux 内核 reflector< linux-kernel@vger.kernel.org >。这是一个相对高容量(每月约 5000 个帖子)的组,用于 Linux 内核的所有方面。应首先尝试 Linux SCSI reflector。
BOOKS. 以下是作者认为有用的一些书籍。
[B1] Alessandro Rubini 和 Jonathan Corbet 著的 "Linux Device Drivers" 第二版 [O'Reilly 2001 ISBN 0-596-00008-1]。这是一本关于 Linux 设备驱动程序的经典书籍,包含一些关于 SCSI 子系统的信息。它很好地涵盖了块子系统,并提供了许多字符设备驱动程序的例子。本书已更新至 Linux 2.4 系列内核,并包含关于 Linux 2.2 和 2.0 系列的信息。强烈推荐本书。作者和出版商无私地以 GNU 自由文档许可证 (版本 1.1) 提供了本书。可以在以下网址找到 HTML 版本: www.xml.com/ldd/chapter/book 。
[B2] M. Welsh, M. K. Dalheimer & L. Kaufman 著的 "Running Linux" 第三版 [O'Reilly 1999 ISBN 1-56592-469-X]。这是一本经典的 Linux 书籍,包含一些 SCSI 配置信息。
[B3] Brian Sawert 著的 "The Programmer's Guide to SCSI" [Addison Wesley 1998 ISBN 0-201-18538-5]。本书涵盖了许多 SCSI 主题,包括 Linux (sg) 和 Windows 使用的 ASPI/ASPI32 的直通机制。
致谢。 作者感谢以下贡献:
Kai Mkisara (st)<Kai.Makisara at metla dot fi>
Jens Axboe (sr)<axboe at suse dot de>
Richard Gooch (devfs)<rgooch at atnf dot csiro dot au>
Tim Waugh (ppa, imm, ppscsi + docbook)<twaugh at redhat dot com>
Gadi Oxman (ide-scsi)<gadio at netvision dot net dot il>
更正和建议。 请将任何更正或建议发送给作者,地址是:<dgilbert at interlog dot com>或<dougg at torque dot net> .
[1] | SCSI 标准允许单个总线上存在多个启动器。虽然有一些补丁可以改善这种情况,但在 Linux 中对此支持不佳。 | ||
[2] | 如果 15 个分区限制太严格,可以考虑使用逻辑卷管理器 (LVM)。请参阅/usr/src/linux/Documentation/LVM-HOWTO。LVM 还允许逻辑分区跨越多个块设备。 | ||
[3] | grub 的一个小问题是/etc/grub.conf是指向/boot/grub/grub.conf的符号链接。 当/boot是一个单独的分区时,这可能很有用。 | ||
[4] | 如果根文件系统位于由较低级别(适配器)驱动程序控制的 SCSI 设备上,则存在一个排序问题,因为该设备包含/etc/modules.conf文件。 此外,引导加载程序如何从 SCSI 设备(通常来自(主)引导记录)获取初始内核映像也是一个问题。 后者通常由系统或适配器卡的 BIOS 处理。 | ||
[5] | 使用 mkinitrd 的一个例子:假设根分区位于连接到 Adaptec 控制器的 SCSI 磁盘上,该控制器需要 aic7xxx 驱动程序。 在构建一个将 aic7xxx 驱动程序指定为模块的内核之后,将映像加载到正常位置(可能在/boot目录中)。 接下来,确保在/etc/modules.conf文件中有一行类似 "alias scsi_hostadapter aic7xxx" 的内容。 然后从/boot目录执行类似 mkinitrd /boot/initrd-2.4.5.img 2.4.5 的行(这假设正在构建 lk 2.4.5)。 这应导致创建文件initrd-2.4.5.img。 然后应该向/etc/lilo.conf添加一个如下所示的部分
| ||
[6] | PCI 适配器比旧的 ISA 适配器对于初始化代码来说更“安全”。 因此,PCI 适配器的初始化顺序不太可能导致死锁。 在这种情况下,可以通过更改 SCSI 子系统 Makefile 中的条目顺序来修改内置驱动程序的初始化顺序(以及 SCSI 适配器编号)(/usr/src/linux/drivers/scsi/Makefile)。 注意:某些适配器可能被多个较低级别的驱动程序识别(例如,那些基于 NCR 芯片组的适配器)。 | ||
[7] | 逗号或冒号都可以作为 "scsihosts" 的分隔符。 这意味着 "scsihosts=advansys,imm,,ide-scsi" 也是有效的。 此外,如果机器的引导序列涉及 "initrd" 阶段(查看/etc/grub.conf或/etc/lilo.conf以确定是否是这种情况),则在更改 "scsihosts" 引导时间参数后,应运行 mkinitrd 命令。 这将生成一个新的 initrd 映像,需要将其放置在正确的位置(最有可能在/boot目录中)。 | ||
[8] | 使用 "scsihosts" 可能会导致计算机的 BIOS 在一个磁盘上找到引导扇区(以及 lilo 或 grub 中设置的引导时间参数),而内核在另一个磁盘上找到根分区的情况。 当这是未计划的时,这可能会非常令人困惑。 因此,在 lilo 或 grub 的配置中更改(或添加)"scsihosts" 后,最好引导机器以查看访问了哪些磁盘。 | ||
[9] | "add-single-device" 和 "remove-single-device" 的解析相当不灵活。 因此,最好与演示的语法保持一致,没有额外的空格(也没有制表符)。 | ||
[10] | ATA 是先前称为 IDE 和/或 EIDE 的现代名称。 请注意,由于历史原因,在 Linux 中控制 ATA 设备的子系统称为 "IDE" 子系统。 | ||
[11] | 其他 ATA 设备(如磁带和软盘)通常使用 ATAPI 接口。 但是,绝大多数 ATA 磁盘不使用 ATAPI 接口。 | ||
[12] | 在 linux 2.4 内核系列中,当使用 ide-scsi 驱动程序以便 cdrecord 可以控制 ATAPI (IDE) cd 刻录机时,问题有所增加。 该问题可能与 IDE 子系统尝试优化其控制设备上的数据传输速度的激进方式有关。 一些遇到超时和机器锁死的人发现,通过 hdparm 命令降低 DMA 设置可以解决该问题。 如果 cd 刻录机连接到/dev/hdd,那么用户报告了使用以下两个命令之一成功的情况
| ||
[13] | 据报道,在某些发行版中,尝试使用 hdparm 命令失败。 在这种情况下,请使用 "echo ... > /proc/ide/hdx/settings" 格式。 | ||
[14] | 此列表是从 www.kernel.org 发布的官方 2.4 系列内核编译而成的。 发行版可以自由定制官方内核,这可能会影响 SCSI 子系统中支持(或更改)的内容。 例如,此机器报告此内核:“2.4.18-27.8.0”。 因此,它大致基于官方 2.4.18 内核,供应商已为其发行版的 "8.0" 级别“修改”了 27 次。 作为更改类型的一个例子,官方 2.4.18 中的 aic7xxx 驱动程序不支持 Adaptec 的 Ultra 320 系列 PCI 适配器;但是,该供应商的版本支持。 |