探索Linux通用SCSI驱动器
通过 SCSI 命令管理计算机上的数据,并将数据传输到 SCSI 设备。在本文中,作者介绍了一些 SCSI 命令,以及在 Linux® 中使用 SCSI API 时执行 SCSI 命令的方法。他介绍了 SCSI 客户机/服务器模型和存储 SCSI 命令的背景。接下来解释 Linux 通用 SCSI 驱动器 API,并提供一个示例,讨论使用通用驱动器执行 inquiry 命令的系统。
SCSI 客户机/服务器模型
在主机和存储介质进行通信期间,主机通常充当 SCSI 启动程序。在计算机存储中,SCSI 启动程序是启动 SCSI 会话的端点,这意味着它会发送 SCSI 命令。存储介质通常充当 SCSI 目标,它接收和处理 SCSI 命令。SCSI 目标等待启动程序的命令,然后提供请求的输入/输出数据转换。
SCSI 目标通常为启动程序提供一个或多个逻辑单元号(LUN)。在计算机存储介质上,LUN 仅是分配给逻辑单元的号码。逻辑单元是一个 SCSI 协议实体,实际的 I/O 操作只处理这种实体。每个 SCSI 目标可以提供一个或多个逻辑单元;它本身不执行 I/O,但代替特定的逻辑单元执行。
在存储区域中,LUN 通常表示一个主机能够执行读写操作的 SCSI 磁盘。图 1 显示 SCSI 客户机/服务器模型是如何工作的。
图 1. SCSI 客户机/服务器模型
启动程序首先向目标发送命令,然后目标解码命令并向启动程序请求数据,或将数据发送给启动程序。在这之后,目标将状态发送给启动程序。如果状态损坏,启动程序将向目标发送一个请求检测(sense)指令。目标将返回检测数据,告知启动程序哪里出错。
现在我们研究与存储相关的 SCSI 命令。
![]() ![]() |
![]()
|
与存储相关的 SCSI 命令
与存储相关的 SCSI 命令一般是在 SCSI Architecture Model (SAM)、SCSI Primary Commands (SPC) 和 SCSI Block Commands (SBC) 中定义的:
- SAM 定义 SCSI 系统模型、SCSI 标准集的功能性分区,以及适用于所有 SCSI 实现和实现标准的需求。
- SPC 定义对所有 SCSI 设备模型通用的行为。
- SBC 定义命令集扩展,以方便操作 SCSI 直接访问块设备。
每个 SCSI 命令都由 Command Descriptor Block (CDB) 描述,它定义 SCSI 设备执行的操作。SCSI 命令涉及到用于向 SCSI 设备传输数据(或从中输出数据)的数据命令,以及用于设置 SCSI 设备的配置参数的非数据命令。表 1 列出了最常使用的命令。
表 1. 最常用的 SCSI 命令
命令 | 描述 |
---|---|
Inquiry | 请求目标设备的摘要信息 |
Test/Unit/Ready | 检测目标设备是否准备好进行传输 |
READ | 从 SCSI 目标设备传输数据 |
WRITE | 向 SCSI 目标设备传输数据 |
Request Sense | 请求最后一个命令的检测数据 |
Read Capacity | 请求存储容量信息 |
所有 SCSI 命令都要以操作代码的第一个字节为开端,以表明它所代表的操作。并且所有 SCSI 命令都要包含一个控制字节。这个字节通常是该命令的最后一个字节,用于表示与供应商相关的信息等等。
现在开始探索通用 SCSI 驱动器。
![]() ![]() |
![]()
|
Linux 通用 SCSI 驱动器
Linux 中的 SCSI 设备的命名方式能够帮助用户识别设备。例如,第一个 SCSI CD-ROM 是 /dev/scd0。SCSI 磁盘的标签为 /dev/sda、/dev/sdb 和 /dev/sdc 等。当设备初始化完成时,Linux SCSI 磁盘驱动器接口仅发送 SCSI READ
和 WRITE
命令。
这些 SCSI 设备可能具有通用的名称和接口,比如 /dev/sg0、/dev/sg1 或 /dev/sga、/dev/sgb 等。通过这些通用的 驱动器接口,您就可以将 SCSI 命令直接发送到 SCSI 设备,而不需要经过在 SCSI 磁盘上创建(并装载到某个目录)的文件系统。在图 2 中,您可以看到不同的应用程序如何与 SCSI 设备通信。
通过 Linux 通用驱动器接口,您可以构建能够向 SCSI 设备发送更多 SCSI 命令的应用程序。也就是说您又多了一种选择。要确定哪个 SCSI 设备表示某个 sg 接口,您可以使用 sg_map
命令列出所有映射:
[root@taomaoy ~]# sg_map -i |
如何使用 Red Hat 或 Fedora,则要安装 sg3_utils
。现在我们看看如何执行典型的 SCSI 系统调用命令。
![]() ![]() |
![]()
|
典型的 SCSI 通用驱动器命令
对于字符设备,SCSI 通用驱动器支持许多典型的系统调用,比如open()
、close()
、read()
、write
、poll()
和 ioctl()
。向特定的 SCSI 设备发送 SCSI 命令的步骤也非常简单:
- 打开 SCSI 通用设备文件(比如 sg1)获取 SCSI 设备的文件描述符。
- 准备好 SCSI 命令。
- 设置相关的内存缓冲区。
- 调用
ioctl()
函数执行 SCSI 命令。 - 关闭设备文件。
典型的 ioctl()
函数类似于:ioctl(fd,SG_IO,p_io_hdr);
。
这里的 ioctl()
函数必须具有 3 个参数:
fd
是设备文件的文件描述符。通过调用open()
成功打开设备文件之后,将需要获取这个参数。SG_IO
表明将sg_io_hdr
对象作为ioctl()
函数的第三个参数提交,并且在 SCSI 命令结束时返回。p_io_hdr
是指向sg_io_hdr
对象的指针,该对象包含 SCSI 命令和其他设置。
SCSI 通用驱动器的最重要数据结构是 struct sg_io_hdr
,它在 scsi/sg.h 中定义,并且包含如何使用 SCSI 命令的信息。清单 1 给出了这个结构的定义。
清单 1. sg_io_hdr 结构的定义
typedef struct sg_io_hdr |
不需要用到这个结构中的所有字段,因此这?仅列出最常用的字段:
interface_id
:一般应该设置为S
。dxfer_direction
:用于确定数据传输的方向;常常使用以下值之一:SG_DXFER_NONE
:不需要传输数据。比如 SCSI Test Unit Ready 命令。SG_DXFER_TO_DEV
:将数据传输到设备。使用 SCSI WRITE 命令。SG_DXFER_FROM_DEV
:从设备输出数据。使用 SCSI READ 命令。SG_DXFER_TO_FROM_DEV
:双向传输数据。SG_DXFER_UNKNOWN
:数据的传输方向未知。
cmd_len
:指向 SCSI 命令的cmdp
的字节长度。mx_sb_len
:当sense_buffer
为输出时,可以写回到sbp
的最大大小。dxfer_len
:数据传输的用户内存的长度。dxferp
:指向数据传输时长度至少为dxfer_len
字节的用户内存的指针。cmdp
:指向将要执行的 SCSI 命令的指针。sbp
:缓冲检测指针。timeout
:用于使特定命令超时。status
:由 SCSI 标准定义的 SCSI 状态字节。
总而言之,当用这种方法传输数据时,cmdp
必须指向其长度存储在 cmd_len
中的 SCSI CDB;sbp
指向最大长度为 mx_sb_len
的用户内存。如果出现错误,将把检测数据写回到这个位置。dxferp
指向内存;数据将根据 dxfer_direction
传输到 SCSI 设备或从中传输出来。
最后,我们看看 inquiry 命令,以及如何使用通用驱动器执行它。
![]() ![]() |
![]()
|
例子:执行一个 inquiry 命令
inquiry 命令是所有 SCSI 设备实现的最常用的 SCSI 命令。这个命令用于请求 SCSI 设备的基本信息,并且常常用作 ping
操作,以测试 SCSI 设备是否在线。表 2 显示如何定义 SCSI 标准。
表 2. inquiry 命令格式定义
位 7 | 位 6 | 位 5 | 位 4 | 位 3 | 位 2 | 位 1 | 位 0 | |
---|---|---|---|---|---|---|---|---|
字节 0 | Operation code = 12h | |||||||
字节 1 | LUN | Reserved | EVPD | |||||
字节 2 | Page code | |||||||
字节 3 | Reserved | |||||||
字节 4 | Allocation length | |||||||
字节 5 | Control |
如果 EVPD 参数位(用于启用关键产品数据)为 0 并且 Page Code 参数字节为 0,那么目标将返回标准 inquiry 数据。如果 EVPD 参数为 1,那么目标将返回对应 page code 字段的特定于供应商的数据。
清单 2 显示了使用 SCSI 通用 API 的源代码片段。我们先看看设置 sg_io_hdr
的示例。
清单 2. 设置 sg_io_hdr
struct sg_io_hdr * init_io_hdr() { |
这些函数还用于设置 sg_io_hdr
对象。其中的一些字段指向用户空间内存;当执行完毕时,来自 SCSI 命令的 inquiry 输出数据将复制到 dxferp
指向的内存。如果出现错误并且需要检测数据,检测数据将复制到 sbp
指向的位置。清单 3 显示了一个向 SCSI 目标发送 inquiry 命令的示例。
清单 3. 向 SCSI 目标发送 inquiry 命令
int execute_Inquiry(int fd, int page_code, int evpd, struct sg_io_hdr * p_hdr) { |
因此,这个函数首先根据 inquiry 标准格式准备 CDB,然后调用 ioctl()
函数,提交文件描述符SG_IO
和 sg_io_hdr
对象;返回的状态存储在 sg_io_hdr
对象的 status
字段中。
现在我们看看应用程序如何使用这个函数执行 inquiry 命令,如清单 4 所示:
清单 4. 应用程序执行 inquiry 命令
unsigned char sense_buffer[SENSE_LEN]; |
发送 SCSI 命令的步骤非常简单。首先必须分配用户空间数据缓冲区和检测缓冲区,并将它们指向sg_io_hdr
对象。然后打开设备驱动器并获取文件描述符。有了这些参数之后,就可以将 SCSI 命令发送到目标设备。当这个命令完成时,SCSI 目标的输出将被复制到用户空间缓冲区。
清单 5. 使用参数将 SCSI 命令发送到目标设备
void show_vendor(struct sg_io_hdr * hdr) { |
SCSI Inquiry Command(Page Code 和 EVPD 字段皆设置为 0)的标准响应很复杂。根据标准,供应商 ID 从第 8 字节扩展到第 15 字节,产品 ID 从第 16 字节扩展到第 31 字节,产品版本从第 32 字节扩展到第 35 字节。必须获取这些信息,以检查命令是否成功执行。
在构建这个简单的示例之后,可以在 /dev/sg0 上运行它,这通常是本地硬盘。您将得到以下结果:
[root@taomaoy scsi_test]# ./scsi_test /dev/sg0 |
结果和 sg_map
工具报告的一样。
![]() ![]() |
![]()
|
结束语
Linux 提供一个 SCSI 设备通用驱动器和一个应用程序编程接口,您可以通过它们构建能够将 SCSI 命令直接发送到 SCSI 设备的应用程序。您可以手动发送 SCSI 命令并在 sg_io_hdr
中设置其他相关参数,然后调用 ioctl()
执行 SCSI 命令并从同一个 sg_io_hdr
对象中获取输出。
探索Linux通用SCSI驱动器的更多相关文章
- 探索Linux内核:Kconfig / kbuild的秘密
探索Linux内核:Kconfig / kbuild的秘密 文章目录 探索Linux内核:Kconfig / kbuild的秘密 深入了解Linux配置/构建系统的工作原理 Kconfig kbuil ...
- 探索 Linux 系统的启动过程
引言 之所以想到写这些东西,那是因为我确实想让大家也和我一样,把 Linux 桌面系统打造成真真正正日常使用的工具,而不是安装之后试用几把再删掉.我是真的在日常生活和工作中都使用 Linux,比如在 ...
- Linux 相关scsi命令
Linux 相关scsi命令 由于前段时间存储扩容,对存储操作较多,下面记录了常用的操作: lsscsi命令:显示scsi设备信息 #lsscsi [0:0:0:2] disk IBM ...
- linux下scsi共享磁盘的简单搭建
linux下scsi共享磁盘的简单搭建 Scsi 共享磁盘需要我先有空余的分区,或者可以在虚拟机里面添加一块磁盘,安装所需的软件我在虚拟机里面添加了一块硬盘,分了一个主分区,sdb1 1G,将这个用s ...
- Linux通用小技能
Linux通用小技能 前言 无论你用ubuntu还是centos,通通没问题,运维这东西,踩坑写文档就是了. 小技能 新磁盘挂载 不管是阿里云还是腾讯云,还是自己的机器,请记住这条命令. mkfs.e ...
- linux 通用时钟框架CCF
linux CCF 时钟框架 简单介绍 这里讲的时钟是给soc各组件提供时钟的树状框架,并非内核使用的时间,和其它模块一样,clk也有框架,用以适配不同的平台.适配层之上是客户代码和接口,也就是各模块 ...
- linux通用邻居基础架构
1.为每一个协议提供一个缓存来存放L3到L2的转换结果. 2.提供在缓存中添加.删除.改变和查找一个特定映射项的函数.查找函数必须要快,因为它会影响整个系统的性能. 3.为每一个协议缓存的数据项提供一 ...
- Ubuntu 18.04 安装微信(Linux通用)
Linux相关的知识:https://www.cnblogs.com/dunitian/p/4822808.html#linux 新增谷歌浏览器添加到桌面的彻底删除:https://www.cnblo ...
- Linux系统SCSI磁盘扫描机制解析及命令实例(转)
转载请在文首保留原文出处:EMC中文支持论坛 介绍 Linux系统扫描SCSI磁盘有几种方式?Linux新增LUN之后,能否不重启主机就认出设备?如果安装了PowerPath,动态添加/删除LUN的命 ...
随机推荐
- Ubuntu下查看硬盘分区UUID的方法&所有Linux目录樹
在Ubuntu中UUID的两种获取方法,至于UUID是什么,你可以大概理解为分区的标识符,像条形码那样. 在终端中输入下面的命令就可心查看到分区UUID了.命令1.sudo blkid 命令2.ls ...
- CodeForces 993A Two Squares(数学 几何)
https://codeforces.com/problemset/problem/993/A 题意: 给你两个矩形,第一行是一个正面表示的矩形,第二个是一个旋转四十五度角的矩形,问这两个矩形是否相交 ...
- RDD(六)——分区器
RDD的分区器 Spark目前支持Hash分区和Range分区,用户也可以自定义分区,Hash分区为当前的默认分区,Spark中分区器直接决定了RDD中分区的个数.RDD中每条数据经过Shuffle过 ...
- mysql之存储过程(三)
带参数的存储过程: 特别说明: 在游标中是不支持对形参的判断的,外部可以 调用操作: call settlexxxxx_common("1970-11",999); 定义如下: ...
- winform把所有dll打包成一个exe
大家都知道做winform开发,是可以利用visual studio进行打包的,但是这种打包的方式需要双击安装,那么有没有什么方法,可以把winform程序打包成绿色版呢?当然,这里的“绿色版”也是相 ...
- SVN一直清理解决
svn作为我们经常使用的版本管理服务器,在使用过程中经常需要通过clean up操作来完成本地文件与服务器文件信息及版本信息同步,然而有时会在执行清理命令时提示“清理失败,请执行清理”,并且提示的中文 ...
- Keywords|Result|Final check
科研论文写作 风格最好是excited,不要过于谦虚. Reference不要过多引用自己的paper,可以多引用本刊物的paper. Acknowledgement:感谢帮助input的人员,可以n ...
- jmeter接口自动化测试,数据驱动玩法
总体思路:excel管理测试数据,判断不同的接口请求方法,取登陆token值为全局变量方便后面接口调用,预期结果断言: 1.设置获取excel数据源: 2.设置取token以及设置为全局变量: 3.i ...
- Office.MsoLanguageID枚举常量(采用API函数取出)
msoLanguageIDAfrikaans (&H436) msoLanguageIDAlbanian (&H41C) msoLanguageIDAmharic (&H45E ...
- Linux中vim的基本操作
Vim三种模式之间的相互转换: 1.拷贝当前行 yy,拷贝当前行的向下五行 5yy,粘贴使用p: 2.删除当前行 dd,删除当前行的向下五行 5dd: 3.在文件中查找某个单词[命令行模式下 /关键 ...