浅析Linux SCSI子系统:IO路径

文章目录

概述

SCSI子系统向上与块层对接,由块层提交的对块设备的IO请求,会由SCSI子系统转换成SCSI协议的标准命令,然后调用Scsi_Host结构的queuecommand回调下发到低层驱动执行;低层驱动会将SCSI命令和数据发送给真实的设备,并在请求完成后,调用scsi_cmd结构中的scsi_done回调,将请求响应信息返回给SCSI中层,SCSI中层完成请求响应的解析后,将结果返回给块层。

scsi_cmd:SCSI命令

复制代码
struct scsi_cmnd {
	struct scsi_request req;
	struct scsi_device *device;
	struct list_head list;     // 用于链入到关联SCSI设备的SCSI命令链表中
	struct list_head eh_entry;     // 用于链入到SCSI Host的错误恢复链表中
	struct delayed_work abort_work;

	struct rcu_head rcu;

	int eh_eflags;
	unsigned long serial_number;

	unsigned long jiffies_at_alloc;

	int retries;   // SCSI命令已重试的次数
	int allowed;   // SCSI命令允许重试的次数

	unsigned char prot_op;     // DIF操作类型
	unsigned char prot_type;   // DIF保护类型
	unsigned char prot_flags;

	unsigned short cmd_len;
	enum dma_data_direction sc_data_direction;

	unsigned char *cmnd;

	struct scsi_data_buffer sdb;  // SCSI命令的数据缓冲区
	struct scsi_data_buffer *prot_sdb;     // SCSI命令的保护数据缓冲区

	unsigned underflow;	
	unsigned transfersize;

	struct request *request;

	unsigned char *sense_buffer;   // 存放sense信息的缓冲区
				
	void (*scsi_done) (struct scsi_cmnd *);    // 底层驱动完成IO请求后,调用scsi_done将结果返回给SCSI

	unsigned char *host_scribble;	

	int result;    // 存放低层驱动返回的IO状态信息
	int flags;
};

result字段

result携带了驱动或SCSI中层在完成SCSI命令处理后返回的一些结果信息,一共包含4个字段。

  • driver_byte:由SCSI中层进行设置;
  • host_byte:存放底层驱动返回的状态信息;
  • msg_byte:存放主机适配自身的一些信息;
  • status_byte:存放目标设备返回的状态信息,由SCSI协议定义。

proto_op字段

proto_op字段描述了SCSI命令的DIF操作类型,由scsi_prot_operations枚举类型定义:

复制代码
enum scsi_prot_operations {
	SCSI_PROT_NORMAL = 0,

	SCSI_PROT_READ_INSERT,
	SCSI_PROT_WRITE_STRIP,
	
	SCSI_PROT_READ_STRIP,
	SCSI_PROT_WRITE_INSERT,

	SCSI_PROT_READ_PASS,
	SCSI_PROT_WRITE_PASS,
}

proto_type字段

proto_type字段描述了SCSI命令支持的DIF保护类型,由t10_dif_type枚举类型定义:

复制代码
enum t10_dif_type {
	T10_PI_TYPE0_PROTECTION = 0x0,
	T10_PI_TYPE1_PROTECTION = 0x1,
	T10_PI_TYPE2_PROTECTION = 0x2,
	T10_PI_TYPE3_PROTECTION = 0x3,
}

SCSI命令下发

scsi_request_fn

scsi_dev_queue_ready

scsi_dev_queue_ready检查SCSI设备运行IO情况,确认是否允许下发新的IO。函数检查的维度有两个:

  • 检查SCSI设备的IO请求队列是否已满。若满,则不允许下发新的IO;
  • 检查SCSI设备是否设置了device_blocked。若设置,则需要等待device_blocked计数减为0时,才允许下发IO。

scsi_host_queue_ready

scsi_host_queue_ready检查主机适配器能否下发新的IO,检查逻辑与scsi_dev_queue_ready类似。

SCSI命令响应

SCSI中层在将SCSI命令请求下发给驱动时,会设置scsi_cmnd结构中的done回调函数,驱动在完成IO请求时,通过调用done回调,将IO响应信息返回给中层。

命令请求完成的软中断处理

IO请求完成的处理流程前半部分在硬中断上下文处理,后半部分的工作回切换到软中断进行处理,SCSI提供的软中断处理入口是scsi_softirq_done函数。scsi_softirq_done的工作如下:

  1. 调用scsi_decide_disposition解析scsi_cmd的返回信息,包括驱动返回状态、sense数据等,确定如何进一步处理scsi_cmd;
  2. 根据scsi_decide_disposition返回的动作,处理scsi_cmnd,分为几种情况:
    • SUCCESS:IO成功完成,将结果返回上层;
    • NEEDS_RETRY/ADD_TO_MLQUEUE:IO重试。把scsi_cmnd重新加入到块设备请求队列处理;
    • 默认情况:IO错误处理。调用scsi_en_scmd_add把scsi_cmnd加入到错误处理队列中,等待错误恢复。

scsi_softirq_done流程示意如下:

相关参考

  • 《存储技术原理分析:基于Linux 2.6内核源代码分析》
相关推荐
用户311879455921834 分钟前
libopenssl-1_0_0-devel-1.0.2p RPM 包安装教程(openSUSE/SLES x86_64)
linux
天航星1 小时前
Docker 安装 Jenkins
java·运维·jenkins
未来之窗软件服务1 小时前
操作系统应用开发(二十四)RustDesk 404错误—东方仙盟筑基期
服务器·远程桌面·仙盟创梦ide·东方仙盟·rustdek
waves浪游2 小时前
Linux基本指令(中)
linux·运维·python
zwhy03112 小时前
TCP服务器设计思路
linux·服务器·网络
荣光波比2 小时前
Docker(三)—— Docker Compose 编排与 Harbor 私有仓库实战指南
运维·docker·容器·云计算
落日漫游2 小时前
DockerCE与cri-docker核心区别解析
运维·docker·kubernetes
-水火-2 小时前
【IDE】Linux下使用openocd烧录bin文件
linux·ide·openocd·bin
YongCheng_Liang2 小时前
Linux 基础命令的 7 大核心模块
linux·运维·服务器
Light602 小时前
领码方案|微服务与SOA的世纪对话(3):方法论新生——DDD、服务网格与AI Ops的融合之道
运维·人工智能·微服务·ddd·soa·服务网格·ai ops