Linux Scsi子系统框架介绍( 三 )


文章插图
 

  • 实例:
 
Linux Scsi子系统框架介绍

文章插图
 

Linux Scsi子系统框架介绍

文章插图
 

Linux Scsi子系统框架介绍

文章插图
 
可以看到我本地电脑有
  • 6个shost_gendev和6个shost_dev设备 , 对应着硬件上的6个host控制器 。
  • 这6个控制器是sata控制器 , 并且都是一个同一个pcie外设扩展出来的 , 共享一个pcie设备带宽 。
  • sata驱动创建了ata1-ata6无总线挂靠的虚拟设备,Sata驱动不是这里讨论的内容 。但是sata在扫描完port之后 , 对每个port通过下面的函数创建了硬件host对应的struct device:Pci_dev添加到pci_bus
---->触发ahci驱动的probe(ahci_init_on)
---->ahci扫描port个数(这里有6个)之后为每个port在scsi内部申请对应的host的structdevice
ahci_init_one-->ahci_host_activate-->ata_host_register-->ata_scsi_add_hosts
-->scsi_host_alloc和scsi_add_host_with_dma
这里用到了两个scsi子系统重要的对外接入函数 。
(2) target
  • 在scsi内部针对每个target创建了一个名字为“targetk:m:n”的device结构体 , 其中k是host编号 , m是channel编号 , n是id编号 。
 
Linux Scsi子系统框架介绍

文章插图
 

Linux Scsi子系统框架介绍

文章插图
 
  • 这个targe device也被挂在到”scsi”bus总线上 。“scsi” bus的match函数(scsi_bus_match)不允许target不有driver , 所以目前只有一些attribute可以在用户空间使用 。
 
Linux Scsi子系统框架介绍

文章插图
 
(3) lun
  • Scsi子系统针对每个lun创建了两个device对象 , 分别是sdev_gendev和sdev_dev 。
 
Linux Scsi子系统框架介绍

文章插图
 
  • 它们的名字都是k:m:n:lunN , 其中k是host编号 , m是channel编号 , n是id编号 , lunN是lun编号 。例如

Linux Scsi子系统框架介绍

文章插图
 
  • sdev_gendev挂在”scsi” bus上 , 它会触发bus驱动 , 驱动会通过sdev_gendev->type字段 , 来判断该device是否和自己匹配 。例如ufs , ssd的device会触发名为“sd”的驱动 。sd驱动会给匹配上的lun , 在用户空间创建对应的block设备节点 , 类似于sda , sdb这些(sda1,sda2是sda上GPT或者MBR搞出来的逻辑分区 , 不属于scsi内容) 。例如

Linux Scsi子系统框架介绍

文章插图
【Linux Scsi子系统框架介绍】 

Linux Scsi子系统框架介绍

文章插图
 
  • sdev_dev是挂在名为”scsi_device”的class上 , 用作它用 。其中比较重要的sg.c驱动 , 它在这个class上注册了interface(callback) , 当有device挂在这个class上时 , interface会被调用 , 从而间接的创建对应的char设备 。sg比较特殊 , 它会不加区分的给所有进来的lun创建一个对应的字符设备到用户空间 , 类似于sg0 , sg1 。
 
Linux Scsi子系统框架介绍

文章插图
 
(4) 公版驱动在”scsi”bus上挂着很多驱动:
Linux Scsi子系统框架介绍

文章插图
 
  • 这些驱动都通过scsi_register_driver注册到”scsi” bus上 , 如果我们写一个自定义设备驱动 , 也可以这样放置到scsi子系统里 。
  • 这些公版驱动有针对硬盘的 , 磁带的 , 光驱的 , 扫描仪 , ROM等等各种设备的驱动 。
  • 基本上这些驱动都会在自己的probe里面去查看sdev_gendev->type字段 , 判断该device是否和自己匹配 。例如:

Linux Scsi子系统框架介绍

文章插图
 

Linux Scsi子系统框架介绍


推荐阅读