1. 前言
本专题我们开始学习SCSI子系统的相关内容。本专题主要参考了《存储技术原理分析》、ULA、ULK的相关内容。本专题主要以硬件UFS为例,记录SCSI子系统的框架流程。
驱动通过消息传递机制获得的SCSI设备最终都被添加到系统中。实际上,它被挂接在SCSI总线类型(scsi_bus_type),实际代码参考分配SCSI设备描述符时,调用的scsi_alloc_sdev->scsi_sysfs_device_initialize函数。
接下来,要真正用上这些设备,就需要高层驱动,这些高层驱动挂载SCSI总线类型,在被加载时,扫描并认领总线类型上未被绑定的SCSI设备。
SCSI设备属于sdev_class类,Linux SCSI子系统实现了sg(SCSI通用接口)和ses(SCSI磁盘柜服务)接口,注册到这个类下。他们都相当于类特定的高层驱动。
上一节在scsi设备探测时讲到scsi_sysfs_add_sdev(sdev)执行此函数将会添加scsi_device,引发devcice_add(scsi_device->device),而sd_init->scsi_register_driver时会执行driver_add,匹配成功将执行 sd_probe,从此处可以看出每一个探测到的scsi_devei也就是每个逻辑单元LU都会执行一次sd_probe,本文就说明一下sd_probe的执行过程。
kernel版本:5.10
平台:arm64
注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“
2. SCSI驱动模型

- scsi_device
给出了作为SCSI设备方面的属性 - scsi_disk
给出了作为SCSI磁盘方面的属性,它作为SCSI设备的代表与上层IO关联 - gendisk
给出了作为通用磁盘方面的属性
这三个结构之间相互联系,通过任何一个结构,可以找到另外两个结构。
在SCSI设备被发现(scsi_scan_host),或者SCSI(高层)驱动被加载(init_sd->scsi_register_driver)时,会在SCSI总线类型上和驱动链表中驱动或者设备链表中的设备尝试绑定。在SCSI总线类型(scsi_bus_type,文件drivers/scsi/scsi_sysfs.c)中定义的match回调函数将首先被调用,这个匹配函数就是scsi_bus_match。SCSI总线类型将设备和驱动的匹配留给驱动来做。
如果总线类型的match回调函数匹配成功,接下来会调用总线类型或驱动的probe回调函数。对于SCSI总线没有定义probe回调,因此会调用scsi_driver的probe,也就是sd_probe。
因此,总结SCSI系统的工作模式:
SCSI中层注册SCSI总线类型; SCSI较高层注册SCSI设备驱动;SCSI较低层(SCSI HBA驱动)则负责扫描SCSI总线得到所有的SCSI设备,SCSI设备将和SCSI设备驱动的匹配是根据SCSI INQUIRY响应中的SCSI设备类型域。
3. init_sd
static int __init init_sd(void)
|--for (i = 0; i < SD_MAJORS; i++)
| if (register_blkdev(sd_major(i), "sd") != 0)
| continue;
| majors++;
| blk_register_region(sd_major(i), SD_MINORS, NULL,sd_default_probe, NULL, NULL);
| //注册scsi_disk类
|--class_register(&sd_disk_class);
|--sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,0, 0, NULL);
<

本文详细介绍了Linux内核中SCSI子系统的框架,特别是SCSI磁盘驱动的初始化和探测过程。从init_sd函数开始,讲解了如何注册SCSI设备驱动,以及scsi_probe和sd_probe函数在设备探测中的作用。sd_probe是SCSI磁盘驱动的关键入口,负责创建scsi_disk和gendisk结构,初始化设备,并根据SCSI设备类型进行相应的设置。通过对gendisk和scsi_device的关联,建立了SCSI设备与Linux系统的连接。
最低0.47元/天 解锁文章
4423

被折叠的 条评论
为什么被折叠?



