深入浅出SCSI子系统(四)添加适配器到系统

2023-12-28 10:09

本文主要是介绍深入浅出SCSI子系统(四)添加适配器到系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

添加适配器到系统

scsi_host_alloc()

scsi_add_host()


添加适配器到系统

SCSI低层驱动是面向主机适配器的,低层驱动被加载时,首先要添加主机适配器。主机适配器可以在PCI子系统完成ID匹配时添加,或者通过手工方式添加。所有基于硬件PCI接口的主机适配器都采用前一种方式,而UNH iSCSI启动器采用的是后一种方式。

添加主机适配器包括两部分的内容,为主机适配器分配数据结构,将主机适配器添加到系统。SCSI中间层为此提供了两个公共函数:scsi_host_alloc和scsi_add_host。

在低层驱动,主机适配器(控制器的驱动代码中调用,下面以x86 pm8001控制器驱动为例子)

kernel\drivers\scsi\pm8001\pm8001_init.c


static struct scsi_host_template pm8001_sht = {.module			= THIS_MODULE,.name			= DRV_NAME,.queuecommand		= sas_queuecommand,.target_alloc		= sas_target_alloc,.slave_configure	= sas_slave_configure,.scan_finished		= pm8001_scan_finished,.scan_start		= pm8001_scan_start,.change_queue_depth	= sas_change_queue_depth,.bios_param		= sas_bios_param,.can_queue		= 1,.this_id		= -1,.sg_tablesize		= SG_ALL,.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,.use_clustering		= ENABLE_CLUSTERING,.eh_device_reset_handler = sas_eh_device_reset_handler,.eh_bus_reset_handler	= sas_eh_bus_reset_handler,.target_destroy		= sas_target_destroy,.ioctl			= sas_ioctl,.shost_attrs		= pm8001_host_attrs,.track_queue_depth	= 1,
};static int pm8001_pci_probe(struct pci_dev *pdev,const struct pci_device_id *ent)
{struct Scsi_Host *shost = NULL;shost = scsi_host_alloc(&pm8001_sht, sizeof(void *));}

scsi_host_alloc()

下面介绍函数scsi_host_alloc()代码(摘自文件drivers/scsi/hosts.c)

struct Scsi_Host {struct list_head	__devices;struct list_head	__targets;	struct scsi_host_cmd_pool *cmd_pool;spinlock_t		free_list_lock;struct list_head	free_list; /* backup store of cmd structs */struct list_head	starved_list;spinlock_t		default_lock;spinlock_t		*host_lock;struct mutex		scan_mutex;/* serialize scanning activity */struct list_head	eh_cmd_q;struct task_struct    * ehandler;  /* Error recovery thread. */struct completion     * eh_action; /* Wait for specific actions on the					      host. */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;		   /* commands actually active on low-level */atomic_t host_blocked;unsigned int host_failed;	   /* commands that failed.					      protected by host_lock */unsigned int host_eh_scheduled;    /* EH scheduled without command */unsigned int host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */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;unsigned long cmd_serial_number;unsigned active_mode:2;unsigned unchecked_isa_dma:1;unsigned use_clustering:1;unsigned host_self_blocked:1;unsigned reverse_ordering:1;unsigned tmf_in_progress:1;unsigned async_scan:1;unsigned eh_noresume:1;unsigned no_write_same:1;unsigned use_blk_mq:1;unsigned use_cmd_list:1;unsigned short_inquiry:1;struct workqueue_struct *work_q;struct workqueue_struct *tmf_work_q;unsigned no_scsi2_lun_in_cdb:1;unsigned int max_host_blocked;unsigned int prot_capabilities;unsigned char prot_guard_type;unsigned long base;unsigned long io_port;unsigned char n_io_port;unsigned char dma_channel;unsigned int  irq;enum scsi_host_state shost_state;struct device		shost_gendev, shost_dev;struct list_head sht_legacy_list;void *shost_data;struct device *dma_dev;unsigned long hostdata[0]  /* Used for storage of host specific stuff */__attribute__ ((aligned (sizeof(unsigned long))));
};

scsi_host_alloc函数分配一个新的Scsi_Host描述符并进行基本的初始化。第一个参数为指向SCSI主机适配器模板的指针;第二个参数为驱动私有数据分配的额外字节数。返回值为指向Scsi_Host描述符的指针;或者在失败时返回NULL。一次性分配SCSI主机适配器的公有部分和私有部分的情况如下图:

                                       一次性分配SCSI主机适配器的公有部分和私有部分

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{struct Scsi_Host *shost;gfp_t gfp_mask = GFP_KERNEL;shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);if (!shost)return NULL;
}

Scsi_Host的空间一次性分配。使用kzalloc (GFP_KERNEL)

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
}

Scsi_Host是一个庞大的数据结构,它的初始化也比较烦琐,所幸大多数域都可以根据“主机适配器模板”赋值,或者先赋一个默认的值,等待以后再覆写。需要特别说明的是host_no域,即主机适配器编号。主机适配器是在系统范围内编号的,或者说,系统中的主机适配器统一进行编号。在Linux内核中有一个全局变量scsi_host_next_hn,表示下一个新的主机适配器的编号。它的初值为零,每次发现一个新的主机适配器,将全局变量scsi_host_next_hn的值赋给host_no域,然后再递增。

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{/* These three are default values which can be overridden */shost->max_channel = 0;shost->max_id = 8;shost->max_lun = 8;
}

将max_channel初始化为0,将max_id和max_lun初始化为8,这些域都被先赋予一些默认的值,在本函数返回后,低层驱动可以对这些域进行覆写。

我们关注sysfs文件系统有关的代码。先把主机适配器的子目录树画在图:

                                                                SCSI总线的sysfs

 主机适配器子目录树下包含主机适配器自身的属性文件,以及目标节点子树和更下级的SCSI设备子树。

标记①为主机适配器目录名host#,其中#为主机适配器编号;

标记②为目标节点目录名target#:#:#,其中#:#:#分别为主机适配器编号、通道编号和ID编号;

标记③为SCSI设备目录名#:#:#:#,其中#:#:#分别为主机适配器编号、通道编号、ID编号,以及逻辑单元编号。

struct Scsi_Host {struct device		shost_gendev, shost_dev;
}

主机适配器属于shost_class类(类名为scsi_host),为了和类关联起来,在左下部分看到有同名的子目录树。因此,每个主机适配器定义了两个内嵌设备描述符,分别和这两个灰色标记的目录对应。对应上层host#目录的内嵌设备描述符为shost_gendev域,被称为内嵌通用设备;对应下层host#目录的内嵌设备描述符为shost_dev域,被称为内嵌类设备。

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{//初始化内嵌通用设备device_initialize(&shost->shost_gendev);dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);shost->shost_gendev.bus = &scsi_bus_type;shost->shost_gendev.type = &scsi_host_type;//初始化内嵌类设备device_initialize(&shost->shost_dev);shost->shost_dev.parent = &shost->shost_gendev;shost->shost_dev.class = &shost_class;dev_set_name(&shost->shost_dev, "host%d", shost->host_no);shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
}

初始化内嵌通用设备,初始化内嵌类设备。它们之间是相互关联的,内嵌通用设备为内嵌类设备的父设备shost->shost_dev.parent = &shost->shost_gendev。

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{shost->ehandler = kthread_run(scsi_error_handler, shost,"scsi_eh_%d", shost->host_no);
}

在Linux系统中,每个主机适配器都有一个SCSI错误恢复内核线程。启动之,线程名为scsi_eh_#,其中#为主机适配器编号,线程执行的主体函数为scsi_error_handler。关于更详细的描述,参见后面的SCSI错误恢复。

struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{scsi_proc_hostdir_add(shost->hostt);
}

调用scsi_proc_hostdir_add,在proc文件系统中为这个主机适配器添加一个目录

scsi_add_host()

下面介绍函数scsi_add_host()代码(摘自文件include/scsi/scsi_host.h)

static inline int __must_check scsi_add_host(struct Scsi_Host *host,struct device *dev)
{return scsi_add_host_with_dma(host, dev, dev);
}

scsi_add_host函数有两个参数。第一个为指向主机适配器描述符的指针,第二个指向这个SCSI主机适配器在驱动模型中的父设备的device描述符,它决定了这个SCSI主机适配器在sysfs文件系统中的位置,可以为NULL。但对于PCI-SCSI驱动,通常将它设置为对应PCI设备的内嵌驱动模型设备。例如某个SCSI主机适配器对应sysfs文件系统的/sys/devices/pci0000:00/0000:00:07.1/host0/目录。成功返回0,错误返回非0值。

函数scsi_add_host_with_dma()代码(摘自文件drivers/scsi/hosts.c)

int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,struct device *dma_dev)
{error = scsi_setup_command_freelist(shost);
}

在调用scsi_add_host_with_dma时增加了一个参数:主机适配器的DMA设备,它只是用于虚拟主机适配器环境下,在我们这里不需要给予太多关注。对于PCI-SCSI设备,传入的就是对应PCI设备的内嵌驱动模型设备。

scsi_setup_command_freelist函数为主机适配器准备用于分配SCSI命令结构和感测缓冲区的存储池结构,以及准备SCSI命令结构的后备仓库链表。

int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,struct device *dma_dev)
{if (!shost->shost_gendev.parent)shost->shost_gendev.parent = dev ? dev : &platform_bus;
}

确定主机适配器在sysfs中的位置。我们说过,一般情况下,主机适配器会被放在引出它的PCI设备之下,主机适配器驱动一般在调用scsi_add_host函数时会传入对应的pci_dev描述符中的内嵌device地址,在这里赋值给主机适配器内嵌通用设备的parent域。当然,如果传入的dev参数为NULL,我们就把它放在sys/devices/platform/目录下,platform设备是某些特定平台专有的外围设备。

int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,struct device *dma_dev)
{error = device_add(&shost->shost_gendev);error = device_add(&shost->shost_dev);error = scsi_sysfs_add_host(shost);
}

主机适配器的内嵌通用设备和内嵌类设备的初始化已经全部完成。将SCSI子系统的驱动模型设备关系整理如上图所示,为方便理解,其中还包含了后面才会添加的目标节点和SCSI设备。device_add(&shost->shost_gendev);将主机适配器的内嵌通用设备添加到系统中。device_add(&shost->shost_dev);将主机适配器的内嵌类设备添加到系统中。scsi_sysfs_add_host(shost)调用scsi_sysfs_add_host将主机适配器添加到子系统,包括为主机适配器属性添加对应的文件。

int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,struct device *dma_dev)
{scsi_proc_host_add(shost);
}

用于proc文件系统为该主机适配器创建目录项。

这篇关于深入浅出SCSI子系统(四)添加适配器到系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/545603

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景