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

在那茫茫人海中,我找到了这两行,

   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_modsd_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子系统的入门.

 
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值