浅析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.rhkb.cn/news/110016.html

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

相关文章

基于Spring Boot的软件缺陷追踪系统的设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的软件缺陷追踪系统的设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java spri…

【HTML】基础语法讲解

基础语法 1. HTML 结构1.1 认识HTML标签1.2 HTML 文件基本结构1.3 标签层次结构1.4 快速生成代码框架 2. HTML 常见标签2.1 注释标签2.2 标题标签:h1-h62.3 段落标签:p2.4 <br>换行标签2.5 格式化标签2.6 图片标签&#xff1a;img2.7 超链接标签&#xff1a;a2.8 表格标签…

Flutter问题记录 - Unable to find bundled Java version

新版本的Android Studio真的移除了JRE&#xff0c;jre目录找不到&#xff0c;怪不得报错了&#xff0c;不过多了一个jbr目录&#xff0c;找了个以前的Android Studio版本对比 搜了一下jbr&#xff08;JetBrains Runtime&#xff09;&#xff0c;原来IDEA老早就开始用了&#xf…

公网远程访问局域网SQL Server数据库

文章目录 1.前言2.本地安装和设置SQL Server2.1 SQL Server下载2.2 SQL Server本地连接测试2.3 Cpolar内网穿透的下载和安装2.3 Cpolar内网穿透的注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据库的重要性相信大家都有所了解&…

Android studio APK切换多个摄像头(Camera2)

1.先设置camera的权限 <uses-permission android:name"android.permission.CAMERA" /> 2.布局 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"and…

vue中html引入使用<%= BASE_URL %>变量

首先使用src相对路径引入 注意&#xff1a; js 文件放在public文件下 不要放在assets静态资源文件下 否则 可能会报错 GET http://192.168.0.113:8080/src/assets/js/websockets.js net::ERR_ABORTED 500 (Internal Server Error) 正确使用如下&#xff1a;eg // html中引…

go gin 参数绑定常用验证器

https://pkg.go.dev/github.com/go-playground/validator/v10#readme-baked-in-validations min 最小max 最大len 长度限制gt 大于eq 等于ne 不等于eqfield 与某个字段值一样nefield 与某个字段值不一样 package mainimport ("net/http""github.com/gin-gonic…

7.react useReducer使用与常见问题

useReducer函数 1. useState的替代方案.接收一个(state, action)>newState的reducer, 并返回当前的state以及与其配套的dispatch方法2. 在某些场景下,useReducer会比useState更加适用,例如state逻辑较为复杂, 且**包含多个子值**,或者下一个state依赖于之前的state等清楚us…

【Leetcode】124.二叉树中的最大路径和(Hard)

一、题目 1、题目描述 二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root ,返回其…

进行Stable Diffusion的ai训练怎么选择显卡?

Stable Diffusion主要用于从文本生成图像&#xff0c;是人工智能技术在内容创作行业中不断发展的应用。要在本地计算机上运行Stable Diffusion&#xff0c;您需要一个强大的 GPU 来满足其繁重的要求。强大的 GPU 可以让您更快地生成图像&#xff0c;而具有大量 VRAM 的更强大的…

2023年高教社杯 国赛数学建模思路 - 案例:ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模…

微信小程序——van-field中的left-icon属性自定义

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【网络安全带你练爬虫-100练】第19练:使用python打开exe文件

目录 一、目标1&#xff1a;调用exe文件 二、目标2&#xff1a;调用exe打开文件 一、目标1&#xff1a;调用exe文件 1、subprocess 模块允许在 Python 中启动一个新的进程&#xff0c;并与其进行交互 2、subprocess.run() 函数来启动exe文件 3、subprocess.run(["文件路…

无涯教程-机器学习 - 箱形图函数

Box和Whisker图(也简称为boxplots)是另一种有用的技术&#xff0c;可用于检查每个属性的分布情况。以下是此技术的特点- 它本质上是单变量的&#xff0c;总结了每个属性的分布。它为中间值(即中位数)画一条线。它将在25&#xff05;和75&#xff05;周围绘制一个框。它还会绘制…

linux并发服务器 —— 文件IO相关函数(三)

文件IO 以内存为主体&#xff0c;看待输入输出&#xff1b; 标准C库IO函数带有缓冲区&#xff0c;效率较高&#xff1b; 虚拟地址空间 虚拟地址空间是不存在的&#xff0c;一个应用程序运行期间对应一个虚拟地址空间&#xff1b; 虚拟地址空间的大小由CPU决定&#xff0c;位…

对《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》的改进

《VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库》使用的Activex DLL公共对象是需要先注册的。https://blog.csdn.net/weixin_45707491/article/details/132437502?spm1001.2014.3001.5501 Activex DLL事前注册&#xff0c;一次多用说起来也不是啥大问题&#x…

R语言常用数学函数

目录 1. - * / ^ 2.%/%和%% 3.ceiling,floor,round 4.signif,trunc,zapsamll 5.max,min,mean,pmax,pmin 6.range和sum 7.prod 8.cumsum,cumprod,cummax,cummin 9.sort 10. approx 11.approx fun 12.diff 13.sign 14.var和sd 15.median 16.IQR 17.ave 18.five…

css元素定位:通过元素的标签或者元素的id、class属性定位,还不明白的伙计,看这个就行了!

前言 大部分人在使用selenium定位元素时&#xff0c;用的是xpath元素定位方式&#xff0c;因为xpath元素定位方式基本能解决定位的需求。xpath元素定位方式更直观&#xff0c;更好理解一些。 css元素定位方式往往被忽略掉了&#xff0c;其实css元素定位方式也有它的价值&…

WPF自定义命令及属性改变处理

1、项目建构 2、自定义命令 namespace WpfDemo.Base {public class MyCommand : ICommand{Action executeAction;public MyCommand(Action action){executeAction action;}public event EventHandler? CanExecuteChanged;public bool CanExecute(object? parameter){retu…

【从零开始学习JAVA | 第四十六篇】处理请求参数

前言&#xff1a; 在我们之前的学习中&#xff0c;我们已经基本学习完了JAVA的基础内容&#xff0c;从今天开始我们就逐渐进入到JAVA的时间&#xff0c;在这一大篇章&#xff0c;我们将对前后端有一个基本的认识&#xff0c;并要学习如何成为一名合格的后端工程师。今天我们介绍…