浅析Linux SCSI子系统:设备管理

文章目录

    • 概述
    • 设备管理数据结构
      • scsi_host_template:SCSI主机适配器模板
      • scsi_host:SCSI主机适配器
        • 主机适配器支持DIF
      • scsi_target:SCSI目标节点
      • scsi_device:SCSI设备
    • 添加主机适配器
      • 构建sysfs目录
    • 添加SCSI设备
      • 挂载Lun
        • IO请求队列初始化
    • 相关参考

概述

Linux SCSI子系统通过SCSI主机适配器(HBA)接入所有SCSI存储设备,在Linux系统中,可以安装多种主机适配器,SCSI中层会提供主机适配器的统一抽象,这些主机适配器的厂商提供具体的低层驱动实现;主机适配器接入到SCSI子系统后,SCSI会通过扫描或者低层驱动主动上报的方式,接入主机适配器下挂的所有SCSI存储设备。

设备管理数据结构

Linux SCSI子系统通过Scsi_Host、scsi_target和scsi_device数据结构分别来描述SCSI主机适配器、目标节点和逻辑单元,它们之间的关系如下:
在这里插入图片描述

  • Linux系统支持安装多个主机适配器,所有接入的主机适配器在SCSI中层都会有对应的Scsi_Host结构。Scsi_Host结构描述了SCSI主机适配器的通用属性和方法,由低层驱动根据scsi_host_template进行创建并注册到SCSI子系统中;
  • Scsi_Host维护了两个设备链表:target链表和device链表,其中target链表管理所有的scsi_targe结构,device链表管理所有的scsi_device结构。

scsi_host_template:SCSI主机适配器模板

scsi_host_template描述了SCSI主机适配器的公共属性和接口,包括主机队列深度、命令处理回调、错误处理回调等。低层驱动自定义SCSI主机适配器模板,SCSI中层会提供接口由低层驱动调用,根据SCSI主机适配器模板信息生成相应的Scsi_Host实例。

struct scsi_host_template {struct module *module;const char *name;int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);      // SCSI命令下发接口int (* eh_abort_handler)(struct scsi_cmnd *);  // 错误恢复:取消指定的SCSI命令int (* eh_device_reset_handler)(struct scsi_cmnd *);   // 错误恢复:复位SCSI设备int (* eh_target_reset_handler)(struct scsi_cmnd *);   // 错误恢复:复位SCSI目标节点int (* eh_bus_reset_handler)(struct scsi_cmnd *);      // 错误恢复:复位SCSI总线int (* eh_host_reset_handler)(struct scsi_cmnd *);     // 错误恢复:复位SCSI主机适配器int (* slave_alloc)(struct scsi_device *);     // 添加SCSI设备时,中层调用让驱动传递设备私有数据int (* slave_configure)(struct scsi_device *); void (* slave_destroy)(struct scsi_device *);  // 删除SCSI设备时,中层调用让驱动释放设备私有数据int (* target_alloc)(struct scsi_target *);    // 添加SCSI目标时,中层调用让驱动传递设备私有数据void (* target_destroy)(struct scsi_target *);     // 删除SCSI目标时,中层让驱动释放设备私有数据int (* scan_finished)(struct Scsi_Host *, unsigned long);void (* scan_start)(struct Scsi_Host *);int (* change_queue_depth)(struct scsi_device *, int);     // 调整SCSI设备的队列深度int (* map_queues)(struct Scsi_Host *shost);enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);      // 低层驱动自定义IO超时处理策略int (*host_reset)(struct Scsi_Host *shost, int reset_type);int can_queue;int this_id;unsigned short sg_tablesize;unsigned short sg_prot_tablesize;unsigned int max_sectors;unsigned long dma_boundary;short cmd_per_lun;unsigned char present;int tag_alloc_policy;unsigned track_queue_depth:1;unsigned supported_mode:2;unsigned unchecked_isa_dma:1;unsigned use_clustering:1;unsigned emulated:1;unsigned skip_settle_delay:1;unsigned no_write_same:1;unsigned force_blk_mq:1;unsigned int max_host_blocked;
};

scsi_host:SCSI主机适配器

SCSI主机适配器通常也是PCI设备,由内核的PCI子系统负责扫描接入。

struct Scsi_Host {struct list_head	__devices;    // 管理Host下的所有scsi_devicestruct list_head	__targets;    // 管理Host下的所有scsi_targetstruct list_head	starved_list;struct list_head	eh_cmd_q;struct task_struct    * ehandler;  struct completion     * eh_action; wait_queue_head_t       host_wait;struct scsi_host_template *hostt;      // 指向主机适配器模板的指针struct scsi_transport_template *transportt;union {struct blk_queue_tag	*bqt;struct blk_mq_tag_set	tag_set;};atomic_t host_busy;	atomic_t host_blocked;unsigned int host_failed;	  unsigned int host_eh_scheduled;      unsigned int host_no; int eh_deadline;unsigned long last_reset;unsigned int max_channel;unsigned int max_id;u64 max_lun;unsigned int unique_id;unsigned short max_cmd_len;int this_id;int can_queue;short cmd_per_lun;short unsigned int sg_tablesize;short unsigned int sg_prot_tablesize;unsigned int max_sectors;unsigned long dma_boundary;unsigned nr_hw_queues;...char work_q_name[20];struct workqueue_struct *work_q;struct workqueue_struct *tmf_work_q;unsigned int max_host_blocked;unsigned int prot_capabilities;unsigned char prot_guard_type;enum scsi_host_state shost_state;struct device		shost_gendev, shost_dev;void *shost_data;unsigned long hostdata[0]  __attribute__ ((aligned (sizeof(unsigned long))));  // 可用于存储低层驱动私有数据
}

主机适配器支持DIF

Scsi_Host的prot_capabilities字段描述了SCSI主机适配器支持DIF的能力。

enum scsi_host_prot_capabilities {SHOST_DIF_TYPE1_PROTECTION = 1 << 0, /* T10 DIF Type 1 */SHOST_DIF_TYPE2_PROTECTION = 1 << 1, /* T10 DIF Type 2 */SHOST_DIF_TYPE3_PROTECTION = 1 << 2, /* T10 DIF Type 3 */SHOST_DIX_TYPE0_PROTECTION = 1 << 3, /* DIX between OS and HBA only */SHOST_DIX_TYPE1_PROTECTION = 1 << 4, /* DIX with DIF Type 1 */SHOST_DIX_TYPE2_PROTECTION = 1 << 5, /* DIX with DIF Type 2 */SHOST_DIX_TYPE3_PROTECTION = 1 << 6, /* DIX with DIF Type 3 */
}

scsi_target:SCSI目标节点

struct scsi_target {struct scsi_device	*starget_sdev_user;struct list_head	siblings;     // 用于挂接在Host的__targets链表中struct list_head	devices;      // 管理目标节点下的所有SCSI设备的链表struct device		dev;struct kref		reap_ref; unsigned int		channel;unsigned int		id; unsigned int		create:1; unsigned int		single_lun:1;	   // 标识是否是单Lununsigned int		pdt_1f_for_no_lun:1;	unsigned int		no_report_luns:1;unsigned int		expecting_lun_change:1;	atomic_t		target_busy;atomic_t		target_blocked;unsigned int		can_queue;unsigned int		max_target_blocked;char			scsi_level;enum scsi_target_state	state;void 			*hostdata;     // 驱动私有数据unsigned long		starget_data[0];    // 驱动私有数据
}

scsi_device:SCSI设备

在SCSI子系统的语义中,SCSI设备对应的才是逻辑单元的概念,也就是我们常说的Lun。

struct scsi_device {struct Scsi_Host *host;struct request_queue *request_queue;   // IO请求队列struct list_head    siblings;      // 用于链接到Host的__devices链表struct list_head    same_target_siblings; atomic_t device_busy;atomic_t device_blocked;	spinlock_t list_lock;struct list_head cmd_list;     // 下发到设备的SCSI命令链表struct list_head starved_entry;unsigned short queue_depth;	unsigned short max_queue_depth;	unsigned short last_queue_full_depth; unsigned short last_queue_full_count; unsigned long last_queue_full_time;unsigned long queue_ramp_up_period;unsigned long last_queue_ramp_up;unsigned int id, channel;u64 lun;unsigned int manufacturer;	unsigned sector_size;	     // 扇区大小void *hostdata;	unsigned char type;char scsi_level;char inq_periph_qual;	...struct list_head event_list;struct work_struct event_work;unsigned int max_device_blocked; atomic_t iorequest_cnt;atomic_t iodone_cnt;atomic_t ioerr_cnt;struct device		sdev_gendev,sdev_dev;struct execute_work	ew; /* used to get process context on put */struct work_struct	requeue_work;struct scsi_device_handler *handler;void			*handler_data;unsigned char		access_state;struct mutex		state_mutex;enum scsi_device_state sdev_state;struct task_struct	*quiesced_by;unsigned long		sdev_data[0];
} 

添加主机适配器

驱动添加主机适配器前,需要先调用scsi_alloc_host分配Scsi_Host结构。scsi_alloc_host根据驱动填写的主机适配器模板对Scsi_Host结构进行初始化,同时允许驱动传入特定的size,这样SCSI中层在分配Scsi_Host结构时,会在尾部申请额外的空间存储驱动的私有数据。
在这里插入图片描述
完成Scsi_Host的结构申请后,驱动调用scsi_add_host将主机适配器添加到系统中:
在这里插入图片描述

构建sysfs目录

添加主机适配器的过程中,一个很重要的部分就是在sysfs文件系统构建相关的节点,以支持应用程序访问SCSI子系统的相关信息。
在这里插入图片描述

添加SCSI设备

无论是SCSI总线扫描或者是驱动发现的SCSI设备,最后都需要调用scsi_add_device接口将设备添加到系统中。scsi_add_device执行流程如下:

  • 确认SCSI目标节点在系统中是否存在,不存在就会创建新的scsi_target结构;
  • 向SCSI目标节点中添加Lun,即scsi_device。

在这里插入图片描述

挂载Lun

scsi_probe_and_add_lun负责挂载Lun设备到系统中,它的执行流程如下:

  • 确认SCSI设备在系统中是否存在,不存在则创建新的scsi_device结构;
  • 向设备发送INQUIRY命令,设备在正常接入的情况下,会返回INQUIRY数据;
  • 解析INQUIRY数据,初始化SCSI设备信息

在这里插入图片描述

IO请求队列初始化

分配scsi_device结构时,也会初始化设备的IO请求队列。根据主机适配器是否支持多队列,初始化函数也会不同。对于单队列,SCSI使用scsi_old_alloc_queue函数分配IO请求队列。
在这里插入图片描述

相关参考

  • 《存储技术原理分析:基于Linux 2.6内核源代码分析》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为云Stack的学习(三)

四、华为云Stack公共组件 1.华为云Stack公共负载均衡方案介绍 1.1 LVS原理 LVS是四层负载均衡&#xff0c;建立在OSI模型的传输层之上&#xff0c;所以效率非常高。 LVS有两种转发模式&#xff1a; NAT模式的转发主要通过修改IP地址&#xff08;位于OSI模型的第三层网络层&…

Jmeter(二十八):beanshell的使用

Beanshell 是一种轻量级的 Java 脚本,纯 Java 编写的,能够动态的执行标准 java 语法及一些扩展脚本语法,类似于 javaScript,在工作中可能用的多的就是: Beanshell 取样器:跟Http取样器并列Beanshell前置处理器:一般放在Http请求下,在请求前处理一些数据Beanshell后置处…

基于 xhr 实现 axios

基于 xhr 实现 axios 上面我们讲到二次封装 axios &#xff0c;但是现在我们尝试完全脱离 axios&#xff0c;自己实现一个 axios&#xff0c;由于 axios 底层是基于 xhr 做了二次封装&#xff0c;所以我们也可以尝试一下。 xhr 二次封装 src/plugins/xhr.js /*** 请求拦截器…

python web GUI框架-NiceGUI 教程(二)

python web GUI框架-NiceGUI 教程&#xff08;二&#xff09; streamlit可以在一些简单的场景下仍然推荐使用&#xff0c;但是streamlit实在不灵活&#xff0c;受限于它的核心机制&#xff0c;NiceGUI是一个灵活的web框架&#xff0c;可以做web网站也可以打包成独立的exe。 基…

大数据——一文熟悉HBase

1、HBase是什么 HBase是基于HDFS的数据存储&#xff0c;它建立在HDFS文件系统上面&#xff0c;利用了HDFS的容错能力&#xff0c;内部还有哈希表并利用索引&#xff0c;可以快速对HDFS上的数据进行随时读写功能。 Hadoop在已经有一个HiveMapReduce结构的数据读写功能&#x…

②matlab桌面和编辑器

目录 matlab编辑器练习 运行脚本 matlab编辑器练习 您可以通过点击灰色代码框在脚本中输入命令。 准备就绪后&#xff0c;您可以通过点击蓝色的提交按钮提交代码。 任务 在脚本中输入命令 r 3。 2.任务 在脚本中添加命令 x pi*r^2。 附加练习 当您在实时编辑器中完成…

解锁安全高效办公——私有化部署的WorkPlus即时通讯软件

在当今信息时代&#xff0c;高效的沟通与协作对于企业的成功至关重要。然而&#xff0c;随着信息技术的发展&#xff0c;保护敏感信息和数据安全也变得越来越重要。为了满足企业对于安全沟通和高效办公的需求&#xff0c;我们隆重推出私有化部署的WorkPlus即时通讯软件&#xf…

OpenCV简介

OpenCV简介 OpenCV&#xff08;开源计算机视觉库&#xff1a;http://opencv.org&#xff09;是一个开源库&#xff0c;包含数百种计算机视觉算法。OpenCV 具有模块化结构&#xff0c;主要包括下列模块&#xff1a; 核心功能&#xff08;core&#xff09; - 定义基本数据结构的…

iOS砸壳系列之三:Frida介绍和使用

当涉及从App Store下载应用程序时&#xff0c;它们都是已安装的iOS应用&#xff08;IPA&#xff09;存储在设备上。这些应用程序通常带有保护的代码和资源&#xff0c;以限制用户对其进行修改或者逆向工程。 然而&#xff0c;有时候&#xff0c;为了进行调试、制作插件或者学习…

登高不系安全带自动识别

登高不系安全带自动识别采用yolov8深度学习算法框架模型&#xff0c;登高不系安全带自动识别能够自动检测和识别登高作业人员是否佩戴安全带&#xff0c;过滤其他类似物体的干扰。登高不系安全带自动识别发现有人员未佩戴安全带&#xff0c;将立即触发预警。根据YOLO的设计&…

【算法训练-模拟】模拟设计LRU缓存结构

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是LRU缓存结构设计&#xff0c;这类题目出现频率还是很高的&#xff0c;几乎所有大厂都常考。 当然面对这道题&#xff0c;首先要讲清楚LRU是干什么…

新SDK平台下载开源全志V853的SDK

获取SDK SDK 使用 Repo 工具管理&#xff0c;拉取 SDK 需要配置安装 Repo 工具。 Repo is a tool built on top of Git. Repo helps manage many Git repositories, does the uploads to revision control systems, and automates parts of the development workflow. Repo is…

Redis数据结构:Zset类型全面解析

Redis&#xff0c;作为一种高性能的键值对数据库&#xff0c;因其丰富的数据类型和高效的性能而受到了广泛的关注和使用。在 Redis 的五种主要数据类型中&#xff0c;Zset&#xff08;有序集合&#xff09;类型可能是最复杂&#xff0c;但也是最强大的一种。Zset 不仅可以存储键…

Web 开发 Django 模板

上次为大家介绍了 Django 的模型和自带的管理工具&#xff0c;有了这个工具就可以全自动地根据模型创建后台管理界面&#xff0c;以供网站管理者更方便的管理网站数据。有了网站数据&#xff0c;那怎么样更方便又好看的展示给用户看呢&#xff1f;目前流行的 Web 框架基本都采用…

ssm端游游戏账号销售管理系统源码和论文

ssm端游游戏账号销售管理系统源码和论文069 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面…

基于java swing和mysql实现的仓库商品管理系统(源码+数据库+运行指导视频)

一、项目简介 本项目是一套基于java swing和mysql实现的仓库商品管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经…

嵌入式学习笔记——ARM的编程模式和7种工作模式

ARM提供的指令集 ARM态-ARM指令集&#xff08;32-bit&#xff09; Thumb态-Thumb指令集&#xff08;16-bit&#xff09; Thumb2态-Thumb2指令集&#xff08;16 & 32 bit&#xff09; Thumb指令集是对ARM指令集的一个子集重新编码得到的&#xff0c;指令长度为16位。通常在…

【Spring Boot】数据库持久层框架MyBatis — MyBatis简介

MyBatis简介 本节首先会介绍什么是ORM、什么是MyBatis、MyBatis的特点以及核心概念&#xff0c;最后介绍MyBatis是如何启动、如何加载配置文件的&#xff1f; 1.什么是ORM ORM&#xff08;Object Relational Mapping&#xff0c;对象关系映射&#xff09;是为了解决面向对象…

高亮img、pdf重点部分(html2canvas、pdfjs-dist、react-pdf)

可用业务场景 报销单据审批中&#xff0c;高亮发票部分 需求 后台返回一张图片或者pdf、返回一组坐标&#xff0c;坐标类型[number,number,number,number]&#xff0c;分别代表了x、y、width、height。需要根据坐标在图片上高亮出来坐标位置。如下图 高亮的坐标是&#xff1…

linux————keepalived+LVS(DR模式)

一、作用 使用keepalived解决LVS的单点故障 高可用集群 二、 调度器配置 环境 两台LVS服务 一主一备 两台web服务 采用nginx &#xff08;实现LVS负载均衡&#xff09; 服务ip 主LVS 192.168.100.3 备LVS 192.168.100.6 web1 192.…