SCSI子系统基础学习笔记 - 3. SCSI设备探测
目录
- 1. 前言
- 2.SCSI总线扫描方式
- 3.scsi_scan_host
- 参考文档
1. 前言
本专题我们开始学习SCSI子系统的相关内容。本专题主要参考了《存储技术原理分析》、ULA、ULK的相关内容。本专题主要以硬件UFS为例,记录SCSI子系统的框架流程。
在系统启动过程中,扫描到SCSI主机适配器后,操作系统开始加载SCSI主机适配器驱动,即底层驱动。SCSI主机适配器驱动根据SCSI主机适配器模板分配SCSI主机适配器描述符,并添加到系统。在此之后需要通过SCSI主机适配器启动SCSI总线的扫描。
以UFS为例,UFS控制器不仅作为SCSI总线设备,同时也作为platform总线设备,它是通过ufshcd_pltfrm_init来执行Scsi_Host分配与添加,同时对于SCSI设备(即UFS device)的扫描是在ufshcd_async_scan完成。
对于ufs,执行路径为:
ufs_qcom_probe->ufshcd_pltfrm_init->ufshcd_init->async_schedule(ufshcd_async_scan, hba)->ufshcd_probe_hba->scsi_scan_host
kernel版本:5.10
平台:arm64
注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“
2.SCSI总线扫描方式
SCSI总线扫描的目的是通过协议特定或芯片特定的方式探测挂接在主机适配器后面的target和LUN,为他们在内存中构建相应的数据结构,将他们添加到系统中,不同的主机适配器可能实现不同的拓扑结构和设备添加机制,列举三种:
对于SPI协议,SCSI主机适配器驱动可以调用SCSI中间层提供的扫描算法完成SCSI总线设备的扫描,扫描过程描述如下:
注:
1.对于UFS设备来讲,SCSI低层驱动的queuecommand就是ufshcd_queuecommand
2.INQUIRY、REPORT_LUNS命令是SCSI命令,由它构建CDB,组成了UFS的UTP层UPIU的Transfer specific fields
SCSI中间层提供扫描SCSI总线的服务函数是scsi_scan_host,它一般在适配器平台驱动的probe中执行,它采用的就是上面描述的向各个<channel, id, lun>发送INQUIRY的命令方式
3.scsi_scan_host
void scsi_scan_host(struct Scsi_Host *shost)|--data = scsi_prep_async_scan(shost);| if (!data)| do_scsi_scan_host(shost);| scsi_autopm_put_host(shost);| return;|--async_schedule(do_scan_async, data);|--do_scan_async(void *_data, async_cookie_t c)|--struct async_scan_data *data = _data;|--struct Scsi_Host *shost = data->shost;|--do_scsi_scan_host(shost);|--scsi_finish_async_scan(data);
对于ufs,执行路径为:
ufs_qcom_probe->ufshcd_pltfrm_init->ufshcd_init->async_schedule(ufshcd_async_scan, hba)->ufshcd_probe_hba->scsi_scan_host
scsi_scan_host对指定的scsi_host进行扫描,通过异步扫描host, channel, target, device, 最终将扫描到的lun加入到系统中
scsi_prep_async_scan:为异步扫描做准备,如果是同步扫描则不做任何准备
async_schedule(do_scan_async, data):异步执行do_scan_async->do_scsi_scan_host:
do_scsi_scan_host(shost);|--if (shost->hostt->scan_finished)| if (shost->hostt->scan_start)| shost->hostt->scan_start(shost);| else| scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,SCAN_WILD_CARD, 0);| |--if (!shost->async_scan)| | scsi_complete_async_scans();| |--if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0)| scsi_scan_channel(shost, channel, id, lun, rescan);| | //扫描所有可能的目标节点或特定ID的目标节点| |--__scsi_scan_target(&shost->shost_gendev, channel,id, lun, rescan);| | //分配目标节点,如果目标节点没有扫描到LU,后面会释放| |--starget = scsi_alloc_target(parent, channel, id); | | //对要求扫描所有LU的情况,则先扫描LU0| |--res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL);| |--if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT)| | //通过对LU0(REPORT LUN)发命令查询已经实现的LU号,并对其进行扫描| | if (scsi_report_lun_scan(starget, bflags, rescan) != 0)| | //顺序扫描所有的LUN| | scsi_sequential_lun_scan(starget, bflags,starget->scsi_level, rescan);| | |--for (lun = 1; lun < max_dev_lun; ++lun)| | //对指定编号的LU进行探测| | scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan,NULL)| |--scsi_autopm_put_target(starget);| |--scsi_target_reap(starget);| |--put_device(&starget->dev);
异步执行do_scan_async->do_scsi_scan_host:
如果host controller驱动中定义了scan_finished则由host底层驱动完成扫描,这一般是非标准的做法,标准的扫描过程一般通过中间层实现
.scsi_scan_host_selected
扫描选定的主机适配器,其中会调用scsi_scan_channel(shost, channel, id, lun,0)scsi_scan_channel
扫描channel对应ufs就是ufs总线数目,每条总线接一个ufs target,目前只实现一条总线,接一个ufs target,遍历对channel下的每个target执行__scsi_scan_target。__scsi_scan_target扫描每个target,执行scsi_probe_and_add_lun先扫描LUN0,如果扫描LUN0收到回应,则通过scsi_sequential_lun_scan进一步扫描所有的LUN,为lun创建scsi_device,期间会创建派发队列,并通过命令探测lun是否存在,如果存在则将lun加入到系统中
scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan,NULL)|--struct scsi_device *sdev;| struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);| //如果sdev不存在则分配并初始化|--sdev = scsi_alloc_sdev(starget, lun, hostdata);| |--sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,GFP_KERNEL);| |--初始化sdev| | |--INIT_WORK(&sdev->event_work, scsi_evt_thread)| | | INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue)| | | sdev->sdev_gendev.parent = get_device(&starget->dev);| | | sdev->sdev_target = starget; | | | sdev->hostdata = hostdata;| | |--sdev->request_queue = scsi_mq_alloc_queue(sdev);//创建多队列| | | sdev->request_queue->queuedata = sdev;| | |--scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun ? sdev->host->cmd_per_lun : 1);| | | //链进target->devices| | |--scsi_sysfs_device_initialize(sdev);| //发送SCSI_INQUERY命令探测逻辑单元,result contains valid SCSI INQUIRY data.|--scsi_probe_lun(sdev, result, result_len, &bflags)|--scsi_add_lun(sdev, result, &bflags, shost->async_scan);
scsi_probe_and_add_lun对指定编号的LU进行探测,参数分为为:目标节点指针,LU编号,输出参数,输出参数,扫描次数,传递给scsi_alloc_sdev函数的参数。scsi_probe_and_add_lun分为两个阶段:
1.scsi_probe_lun发送SCSI INQUIRY命令逻辑单元;
2.如果响应则表明逻辑单元存在且有效,将它通过scsi_add_lun添加到系统
scsi_alloc_sdev: 如果内存中没有找到对应的scsi_dev则分配。其中会通过scsi_mq_alloc_queue创建多队列并初始化;通过scsi_sysfs_device_initialize将sdev链入target->devices链表,对scsi_dev向SCSI总线及scsidev class注册的device的初始化。前面在添加添加SCSI适配器到系统时说明了Scsi_Host的添加时机,而此处就是scsi_target和scsi_dev的添加时机,添加后如下:
scsi_probe_lun:发送SCSI_INQUERY命令探测逻辑单元, result保存了结果
scsi_add_lun:如果相应逻辑单元有效,则添加到系统中。根据SCSI INQUERY命令的响应数据和标志位来初始化SCSI DEV描述符的各个域。scsi_sysfs_add_sdev(sdev)将scsi dev及其对应的目标节点添加到sysfs,并创建对应的属性文件,此处会用到scsi_device的两个成员内嵌通用设备和内嵌类设备。执行此函数将会添加scsi_device,引发devcice_add(scsi_device->device),而sd_init->scsi_register_driver时会执行driver_add,匹配成功将执行 sd_probe,从此处可以看出每一个探测到的scsi_devei也就是每个逻辑单元LU都会执行一次sd_probe。关于sd_probe的介绍请参考 SCSI子系统基础学习笔记 - 4.scsi_probe
参考文档
存储技术原理分析
SCSI子系统基础学习笔记 - 3. SCSI设备探测相关推荐
- SCSI子系统基础学习笔记 (之UFS子系统) - 2.2 UFS子系统初始化之ufshcd_async_scan
目录 1. 前言 2. ufshcd_async_scan |- -ufshcd_probe_hba |- -ufshcd_add_lus 3. 总结 参考文档 1. 前言 本专题我们开始学习SCSI ...
- SCSI子系统基础学习笔记 (之UFS子系统) - 2.1UFS子系统初始化之ufs_qcom_probe
目录 1. 前言 2.ufs_qcom_probe |- -ufshcd_alloc_host |- -ufshcd_init 参考文档 1. 前言 本专题我们开始学习SCSI子系统的相关内容.本专题 ...
- SCSI子系统基础学习笔记 (之UFS子系统) - 3. UFS命令处理
目录 1. 前言 2. scsi_queue_rq |- -ufshcd_queuecommand 3. ufshcd_intr 1. 前言 本专题我们开始学习SCSI子系统的相关内容.本专题主要参考 ...
- SCSI子系统基础学习笔记 (之UFS子系统) - 1.2 概述(软件部分)
目录 1. 前言 2. UFS子系统软件架构 3. UFS模块框图 4. UFS领域模型 参考文档 1. 前言 本专题我们开始学习SCSI子系统的相关内容.本专题主要参考了<存储技术原理分析&g ...
- guido正式发布python年份_Python 基础学习笔记.docx
Python 基础学习笔记 基于<Python语言程序设计基础(第2版)> 第一部分 初识Python语言 第1章 程序设计基本方法 1.1 计算机的概念 计算机是根据指令操作数据的设备, ...
- ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步
http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...
- 【UI界面设计】PS基础学习笔记
[UI界面设计]PS基础学习笔记 一.概述 1.行业规范: 2.介绍 二.PS入门 1.安装 2.基本介绍 3.新建项目 4.PS的基本使用流程 5.项目保存 6.抠图 7.修图 8.修人像图 9.如 ...
- C基础学习笔记——01-C基础第02天(用户权限、VI操作、Linux服务器搭建)
在学习C基础总结了笔记,并分享出来.有问题请及时联系博主:Alliswell_WP,转载请注明出处. 01-C基础第02天(用户权限.VI操作.Linux服务器搭建) 打开终端:ctrl+alt+t ...
- 多人网络游戏服务器开发基础学习笔记 II: 帧同步 | 游戏客户端预测原理分析 | FPS 游戏状态同步
这篇是对书本 网络多人游戏架构与编程 的学习第二篇(第一篇:多人网络游戏服务器开发基础学习笔记 I:基本知识 | 游戏设计模式 | 网游服务器层次结构 | 游戏对象序列化 | 游戏 RPC 框架 | ...
- 尚学堂JAVA基础学习笔记_2/2
尚学堂JAVA基础学习笔记_2/2 文章目录 尚学堂JAVA基础学习笔记_2/2 写在前面 第10章 IO技术 1. IO入门 2. IO的API 3. 装饰流 4. IO实战 5. CommonsI ...
最新文章
- 深度学习中的随机梯度下降(SGD)简介
- php数组,常量,遍历等
- 第12课第3节 字符设备驱动程序之查询方式的按键驱动程序
- 图的存储结构matlab,matlab存储 一幅图像的的函数为( )
- php记一笔在线记账管理系统源码
- “S“ is the acronym for Super
- html得到上传文件类型后缀,js获取上传文件后缀名(附js提交form表单)
- python elif可以单独使用_elif可以单独使用。( )_学小易找答案
- 全网最全教你轻松把vue项目部署到IIS服务器
- 高等代数第3版下 [丘维声 著] 2015年版_义务教育数学课程标准(2011年版)(部分内容)...
- python处理地震sac数据_自己开发的一个SEED格式地震数据转换为SAC格式数据,并完成世界时整天波形合并的Python脚本...
- matlab仿真怎么添加干扰信号,噪声干扰信号的matlab仿真
- JSP基本语法(2)函数
- WiFi偏门协议(四):增强的传输机制802.11aa
- 算法的陷阱:超级平台、算法垄断与场景欺骗
- MacOS Ventura 13.1 (22C65) 正式版带 OC 0.8.7 and winPE 双分区原版黑苹果镜像
- 网络供电(POE)的功率
- Mac电脑快速切换输入法!自动切换输入法!
- latex中文小标题_科学网—一个较为完整的中文图书Latex模板 - 张金龙的博文
- windows下python运行的方法