浅析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内核源代码分析》
相关推荐
sduwcgg29 分钟前
IQ-Learn 在 RTX 3090 服务器上的环境配置与踩坑记录
运维·服务器
呱呱巨基1 小时前
Linux 基础IO
linux·c++·笔记·学习
QFIUNE1 小时前
CD-HIT 详解:序列去冗余、安装使用与聚类结果解析
linux·服务器·机器学习·数据挖掘·conda·聚类
vortex51 小时前
XFCE 桌面环境组件详解:从面板到剪贴板管理
linux·xfce·桌面环境
marsh02062 小时前
43 openclaw熔断与降级:保障系统在异常情况下的可用性
java·运维·网络·ai·编程·技术
摇滚侠2 小时前
Docker 如何查询挂载的目录
运维·docker·容器
勇闯逆流河2 小时前
【Linux】linux进程控制(进程池的详解与实现)
linux·运维·服务器
zhangfeng11333 小时前
部署到服务器上 宝塔系统 使用宝塔在线编辑器 FTP 批量上传 Git 部署 打包上传 codebudyy 编程程序开发
服务器·git·编辑器
WJ.Polar3 小时前
Scapy基本应用
linux·运维·网络·python
lljss20204 小时前
1. NameServer 域名服务器---NS
linux·服务器·前端