业余的SSD探索笔记

来源:互联网 发布:access数据库能仓库 编辑:程序博客网 时间:2024/04/30 08:06

目前在日本从事SSD的开发,
日本太拘泥于硬件,导致软件开发的效率和品质比较低下。
(写完代码之后Debug和Test全凭DebugLog和MemoryDump。。。)

于是就有了一个想法,
是不是能写一个一个便于SSD开发的模拟环境呢?
同时自己也想试试全面的学习整个存储的stack(也太贪心了。。)

1.基本构想

层次 构成 备考 Application/Test FIO linux下主流的IQ测试软件,开源 Kernel Linux 。。。 Driver 标准的 linux NVMe Driver 。。。 虚拟机 Qemu 可以参考LightNvm的Qemu 虚拟设备 Qemu 可以参考VSSIM,以及LightNvm的Qemu FLT 也许把现在的工作中写的简化一下拿过来也ok 。。。 虚拟NAND SLC,MLC,TLC,3D EagleTree可以参考

2.进展及步骤记录

由于懂得不多,就一点一点学习研究,一点一点构建吧
首先从搭建一个可以用GDB来调试 NVMe Driver 以及 虚拟的NVMe 设备的环境开始。

目前做到的是:
1. 成功的编译支持nvme的qemu
2. 成功的编译linux(带nvme driver,带debug info)
3. qemu上面成功运行linux,成功的挂载了虚拟的nvme设备。
4. 成功的用gdb来debug NVMe Driver
5. 成功的用gdb来debug NVMe 虚拟设备
接下来:
6. 分析NVMe Driver的代码
7. 分析NVMe 虚拟设备的代码

Qemu的编译及调试:

https://github.com/OpenChannelSSD/qemu-nvme.git
TBD(用的是lightNvm的qemu环境)

Linux的编译及调试:

参考文章:

http://www.linux-magazine.com/Online/Features/Qemu-and-the-Kernel

遇上的问题及解决的办法:

本来是尝试在64位的linux上面进行调试的,但是试了一下发现gdb还不能支持qemu上的64位的linux的调试(从start_kernel开始的调试)
换成了32bit的linux之后问题就解决了

make qemu_x86_64_defconfig
使用时遇上了 “gdb replay g packet is too long”的问题,查了一下面的内容,发现好像是gdb的问题,还没得到解决。
http://stackoverflow.com/questions/8662468/remote-g-packet-reply-is-too-long
https://lists.nongnu.org/archive/html/qemu-discuss/2014-10/msg00069.html
http://stackoverflow.com/questions/8662468/remote-g-packet-reply-is-too-long
http://augustl.com/blog/2014/gdb_progress/
https://sourceware.org/bugzilla/show_bug.cgi?id=13984

Linux Driver的基本解析:

详细的分析可以参考:
http://blog.csdn.net/panzhenjie/article/details/51581063
这里只是列出基本的Function Tree及动作Sequence


相关系统文件及信息

/proc/devices : 代表某种设备对应的主设备号,而不是设备的实例
/proc/iomem:IO空间映射
/dev: 代表某种设备的实例
lspci -k


Function Tree (Version 4.5.3)


nvme_init
├nvme_workq = alloc_workqueue : 创建一个全局的workqueue
├nvme_core_init
│├register_blkdev : 注册一个名字叫nvme的块设备
│├__register_chrdev : 注册一个名字叫nvme的字符设备
│└class_create(THIS_MODULE, “nvme”);
└pci_register_driver :
注册了一个pci驱动(属性和callback表)
- 包括:name:“nvme”,
- id_table
- nvme_probe函数
- nvme_remove函数
- nvme_remove函数
- pm ops:(nvme_suspend,nvme_resume)
- error handler:(nvme_error_detect,nvme_slot_reset,nvme_error_resume,nvme_reset_notify)

nvme_exit
├pci_unregister_driver
├nvme_core_exit
└destory_workqueue

nvme_probe
├dev_to_node
├kzalloc_node(sizeof( * dev))
├kzalloc_node(num_possible_cpus() * sizeof( * dev->entry)):msi相关信息(cpu core个)
├kzalloc_node((num_possible_cpus() + 1) * sizeof(void * )):admin queue(1个)+ io queue(cpu core个)的相关信息
├get_device
├pci_set_drvdata
├nvme_dev_map
│├bars = pci_select_bars:pci设备的配置空间里有6个32位的bar寄存器,每一位代表一个bar(base address register)是否被置位
│├pci_request_selected_regions(pdev, bars, “nvme”):把对应的这个几个bar保留起来,不让别人使用。 (结果可以在/proc/iomem中确认)
│└dev->bar = ioremap:把pci bar的物理地址映射到虚拟地址
├INIT_WORK(&dev->scan_work, nvme_dev_scan);
├INIT_WORK(&dev->reset_work, nvme_reset_work);
├INIT_WORK(&dev->remove_work, nvme_remove_dead_ctrl_work);
├init_completion(&dev->ioq_wait);
├nvme_setup_prp_pools:创建dma pool,后面就可以通过其他dma函数从dma pool中获得memory
│├dev->prp_page_pool = dma_pool_create(“prp list page”, dev->dev,PAGE_SIZE, PAGE_SIZE, 0);
│└dev->prp_small_pool = dma_pool_create(“prp list 256”, dev->dev,256, 256, 0);
├nvme_init_ctrl
│├nvme_set_instance
│├device_create_with_group
│├get_device
│├dev_set_drvdata
│├ida_init
│├spin_lock
│├
│├
└queue_work(nvme_workq):调度nvme_reset_work

PCIe的基础知识

目前在看下面的文章补补PCIe相关知识:
http://blog.sina.com.cn/s/articlelist_1685243084_3_1.html
http://free-electrons.com/doc/pci-drivers.pdf

0 0
原创粉丝点击