您的位置:首页 > 运维架构 > Linux

Linux那些事儿之我是SCSI硬盘(1)简简单单初始化

2014-01-10 15:39 453 查看
在那茫茫人海中,我找到了这两行,
1886 module_init(init_sd);
1887 module_exit(exit_sd);
不要问我它们来自哪里,咱们整个故事就是围绕着drivers/sd.c这么一个文件展开,所以除非特别声明的之外,都是来自这个文件.

1831 /**

1832 * init_sd - entry point for this driver (both when built in or when

1833 * a module).

1834 *

1835 * Note: this function registers this driver with the scsi mid-level.

1836 **/

1837 static int __init init_sd(void)

1838 {

1839 int majors = 0, i, err;

1840

1841 SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point/n"));

1842

1843 for (i = 0; i < SD_MAJORS; i++)

1844 if (register_blkdev(sd_major(i), "sd") == 0)

1845 majors++;

1846

1847 if (!majors)

1848 return -ENODEV;

1849

1850 err = class_register(&sd_disk_class);

1851 if (err)

1852 goto err_out;

1853

1854 err = scsi_register_driver(&sd_template.gendrv);

1855 if (err)

1856 goto err_out_class;

1857

1858 return 0;

1859

1860 err_out_class:

1861 class_unregister(&sd_disk_class);

1862 err_out:

1863 for (i = 0; i < SD_MAJORS; i++)

1864 unregister_blkdev(sd_major(i), "sd");

1865 return err;

1866 }

1867

1868 /**

1869 * exit_sd - exit point for this driver (when it is a module).

1870 *

1871 * Note: this function unregisters this driver from the scsi mid-level.

1872 **/

1873 static void __exit exit_sd(void)

1874 {

1875 int i;

1876

1877 SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver/n"));

1878

1879 scsi_unregister_driver(&sd_template.gendrv);

1880 class_unregister(&sd_disk_class);

1881

1882 for (i = 0; i < SD_MAJORS; i++)

1883 unregister_blkdev(sd_major(i), "sd");

1884 }

没什么特别的,一串的注册注销函数.
首先,register_blkdev,注册一个块设备.这个函数也算是骨灰级的了,N年前就有这个函数了.那时候我曾天真的以为这个世界上只有三种设备,块设备,字符设备,网络设备.后来发现世界并非那么简单,生活也并非那么简单,尽管,生,很简单,活,很简单,但生活却不简单.
我们来看一下这个函数的效果,加载sd_mod之前,

localhost:~ # cat /proc/devices

Character devices:

1 mem

2 pty

3 ttyp

4 /dev/vc/0

4 tty

4 ttyS

5 /dev/tty

5 /dev/console

5 /dev/ptmx

7 vcs

10 misc

13 input

29 fb

128 ptm

136 pts

Block devices:

1 ramdisk

3 ide0

7 loop

9 md

253 device-mapper

254 mdp

而通过下面两条命令加载了scsi_mod和sd_mod之后,

localhost:~ # modprobe scsi_mod

localhost:~ # modprobe sd_mod

localhost:~ # cat /proc/devices

Character devices:

1 mem

2 pty

3 ttyp

4 /dev/vc/0

4 tty

4 ttyS

5 /dev/tty

5 /dev/console

5 /dev/ptmx

7 vcs

10 misc

13 input

29 fb

128 ptm

136 pts

Block devices:

1 ramdisk

3 ide0

7 loop

8 sd

9 md

65 sd

66 sd

67 sd

68 sd

69 sd

70 sd

71 sd

128 sd

129 sd

130 sd

131 sd

132 sd

133 sd

134 sd

135 sd

253 device-mapper

254 mdp

可以看到,多了一个叫做sd的家伙.
这里出现的宏SD_MAJORS实际上被定义为16.所以经过16次循环之后,我们看到这里叫sd的有16个.
至于你说这些号码是怎么来的,就像八国联军在中国瓜分势力范围一样,每个国家分一片地,而Linux中所有的主设备号也是被各种各样的设备所瓜分.其中,8,65-71,136-143这么个16个号码就被scsi
disk所霸占了.sd_major()函数的返回值就是这16个数字.每个主设备号可以带256个次设备号.
1850行, class_register,这行的效果就是,

localhost:~ # ls /sys/class/

backlight dma graphics input mem misc net pci_bus scsi_device scsi_disk scsi_host spi_master tty vc vtconsole

看到其中那项scsi_disk了么?这就是class_register这句干的好事.
而1854行,scsi_register_driver则是赤裸裸的注册一个scsi设备驱动.伟大的设备模型告诉我们对于每个设备驱动,有一个与之对应的struct
device_driver结构体,而为了体现各类设备驱动自身的特点,各个子系统可以定义自己的结构体,然后把struct device_driver包含进来如C++中基类和扩展类一样.对于scsi子系统,这个基类就是struct
scsi_driver,这个结构体本身定义于include/scsi/scsi_driver.h:

10 struct scsi_driver {

11 struct module *owner;

12 struct device_driver gendrv;

13

14 int (*init_command)(struct scsi_cmnd *);

15 void (*rescan)(struct device *);

16 int (*issue_flush)(struct device *, sector_t *);

17 int (*prepare_flush)(struct request_queue *, struct request *);

18 };

而咱们也自然定义了一个scsi_driver的结构体实例.它的名字叫做sd_template.

232 static struct scsi_driver sd_template = {

233 .owner = THIS_MODULE,

234 .gendrv = {

235 .name = "sd",

236 .probe = sd_probe,

237 .remove = sd_remove,

238 .suspend = sd_suspend,

239 .resume = sd_resume,

240 .shutdown = sd_shutdown,

241 },

242 .rescan = sd_rescan,

243 .init_command = sd_init_command,

244 .issue_flush = sd_issue_flush,

245 };

这其中,gendrv就是struct device_driver的结构体变量.咱们这么一注册,其直观效果就是:

localhost:~ # ls /sys/bus/scsi/drivers/

sd

而与以上三个函数相反的就是exit_sd()中的另外仨函数,scsi_unregister_driver,class_unregister,unregister_blkdev.这点我想不用我多说,阜成门外华联商厦门口卖盗版光盘那几位哥们儿也能明白怎么回事.
Okay了,这个初始化就这么简单,就这么结束了.相比uhci-hcd的那个初始化,这里的确简单的不得了.实话实说,SCSI硬盘驱动确实是挺简单的.下一步我们就从sd_probe函数看起,某种意义来说,读sd_mod的代码就算是对scsi子系统的入门.

原文见:http://blog.csdn.net/fudan_abc/article/details/1909613
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: