Linux那些事儿之我是SCSI硬盘(2)依然probe

虽然scsi disk不难,但是如果你以为scsi disk这个模块每个函数都像init_sd()一样简单,那么我只能说你属于那种被蜘蛛咬了就以为自己是蜘蛛侠,被雷电劈了就以为自己是闪电侠,摸了一次高压电就以为自己是沈殿霞.你不服?咱们来看sd_probe,这个函数就不是那么简单.

   1566 /**

   1567  *      sd_probe - called during driver initialization and whenever a

   1568  *      new scsi device is attached to the system. It is called once

   1569  *      for each scsi device (not just disks) present.

   1570  *      @dev: pointer to device object

   1571  *

   1572  *      Returns 0 if successful (or not interested in this scsi device

   1573  *      (e.g. scanner)); 1 when there is an error.

   1574  *

   1575  *      Note: this function is invoked from the scsi mid-level.

   1576  *      This function sets up the mapping between a given

   1577  *      <host,channel,id,lun> (found in sdp) and new device name

   1578  *      (e.g. /dev/sda). More precisely it is the block device major

   1579  *      and minor number that is chosen here.

   1580  *

   1581  *      Assume sd_attach is not re-entrant (for time being)

   1582  *      Also think about sd_attach() and sd_remove() running coincidentally.

   1583  **/

   1584 static int sd_probe(struct device *dev)

   1585 {

   1586         struct scsi_device *sdp = to_scsi_device(dev);

   1587         struct scsi_disk *sdkp;

   1588         struct gendisk *gd;

   1589         u32 index;

   1590         int error;

   1591

   1592         error = -ENODEV;

   1593         if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC)

   1594                 goto out;

   1595

   1596         SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp,

   1597                                         "sd_attach/n"));

   1598

   1599         error = -ENOMEM;

   1600         sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL);

   1601         if (!sdkp)

   1602                 goto out;

   1603

   1604         gd = alloc_disk(16);

   1605         if (!gd)

   1606                 goto out_free;

   1607

   1608         if (!idr_pre_get(&sd_index_idr, GFP_KERNEL))

   1609                 goto out_put;

   1610

   1611         spin_lock(&sd_index_lock);

   1612         error = idr_get_new(&sd_index_idr, NULL, &index);

   1613         spin_unlock(&sd_index_lock);

   1614

   1615         if (index >= SD_MAX_DISKS)

   1616                 error = -EBUSY;

   1617         if (error)

   1618                 goto out_put;

   1619

   1620         sdkp->device = sdp;

   1621         sdkp->driver = &sd_template;

   1622         sdkp->disk = gd;

   1623         sdkp->index = index;

   1624         sdkp->openers = 0;

   1625

   1626         if (!sdp->timeout) {

   1627                 if (sdp->type != TYPE_MOD)

   1628                         sdp->timeout = SD_TIMEOUT;

   1629                 else

   1630                         sdp->timeout = SD_MOD_TIMEOUT;

   1631         }

   1632

   1633         class_device_initialize(&sdkp->cdev);

   1634         sdkp->cdev.dev = &sdp->sdev_gendev;

   1635         sdkp->cdev.class = &sd_disk_class;

   1636         strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);

   1637

   1638         if (class_device_add(&sdkp->cdev))

   1639                 goto out_put;

   1640

   1641         get_device(&sdp->sdev_gendev);

   1642

   1643         gd->major = sd_major((index & 0xf0) >> 4);

   1644         gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);

   1645         gd->minors = 16;

   1646         gd->fops = &sd_fops;

   1647

   1648         if (index < 26) {

   1649                 sprintf(gd->disk_name, "sd%c", 'a' + index % 26);

   1650         } else if (index < (26 + 1) * 26) {

   1651                 sprintf(gd->disk_name, "sd%c%c",

   1652                         'a' + index / 26 - 1,'a' + index % 26);

   1653         } else {

   1654                 const unsigned int m1 = (index / 26 - 1) / 26 - 1;

   1655                 const unsigned int m2 = (index / 26 - 1) % 26;

   1656                 const unsigned int m3 =  index % 26;

   1657                 sprintf(gd->disk_name, "sd%c%c%c",

   1658                         'a' + m1, 'a' + m2, 'a' + m3);

   1659         }

   1660

   1661         gd->private_data = &sdkp->driver;

   1662         gd->queue = sdkp->device->request_queue;

   1663

   1664         sd_revalidate_disk(gd);

   1665

   1666         gd->driverfs_dev = &sdp->sdev_gendev;

   1667         gd->flags = GENHD_FL_DRIVERFS;

   1668         if (sdp->removable)

   1669                 gd->flags |= GENHD_FL_REMOVABLE;

   1670

   1671         dev_set_drvdata(dev, sdkp);

   1672         add_disk(gd);

   1673

   1674         sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk/n",

   1675                   sdp->removable ? "removable " : "");

   1676

   1677         return 0;

   1678

   1679  out_put:

   1680         put_disk(gd);

   1681  out_free:

   1682         kfree(sdkp);

   1683  out:

   1684         return error;

   1685 }

如果我们不看新闻联播,我们又怎么知道自己生活在幸福中呢?如果我们不看probe,我们又怎么知道设备驱动的故事是如何展开的呢?

首先,我们为scsi device准备一个指针,struct scsi_device *sdp,scsi disk准备一个指针,struct scsi_disk *sdkp,此外,甭管是scsi硬盘还是ide硬盘,都少不了一个结构体struct gendisk,这里咱们准备了一个指针struct gendisk *gd.

一路走来的兄弟们一定知道,sd_probe将会由scsi核心层调用,或者也叫scsi mid-level来调用.scsi mid-level在调用sd_probe之前,已经为这个scsi设备准备好了struct device,struct scsi_device,已经为它们做好了初始化,所以这里struct device *dev作为参数传递进来咱们就可以直接引用它的成员了.

这不,1593,就开始判断sdp->type,这是struct scsi_device结构体中的成员char type,它用来表征这个scsi设备是哪种类型的,scsi设备五花八门,而只有这里列出来的这三种是sd_mod所支持的.这其中我们最熟悉的当属TYPE_DISK,它就是普通的scsi磁盘,TYPE_MOD表示的是磁光盘(Magneto-Optical disk),一种采用激光和磁场共同作用的磁光方式存储技术实现的介质,外观和3.5英寸软盘相似,量你也不知道,所以不多说了.另外,TYPE_RBC也算在咱们名下,RBC表示Reduced Block Commands,中文叫命令集,这个也不必多说.

1600,sdkp申请内存.struct scsi_disk定义于include/scsi/sd.h:

     34 struct scsi_disk {

     35         struct scsi_driver *driver;     /* always &sd_template */

     36         struct scsi_device *device;

     37         struct class_device cdev;

     38         struct gendisk  *disk;

     39         unsigned int    openers;        /* protected by BKL for now, yuck */

     40         sector_t        capacity;       /* size in 512-byte sectors */

     41         u32             index;

     42         u8              media_present;

     43         u8              write_prot;

     44         unsigned        WCE : 1;        /* state of disk WCE bit */

     45         unsigned        RCD : 1;        /* state of disk RCD bit, unused */

     46         unsigned        DPOFUA : 1;     /* state of disk DPOFUA bit */

     47 };

看起来,似乎描述一个scsi disk很简单,其实你不要忘了,前面我们还提到另一个结构体struct gendisk,这个结构体来自一个神秘的地方,include/linux/genhd.h:

    113 struct gendisk {

    114         int major;                      /* major number of driver */

    115         int first_minor;

    116         int minors;                     /* maximum number of minors, =1 for

    117                                          * disks that can't be partitioned. */

    118         char disk_name[32];             /* name of major driver */

    119         struct hd_struct **part;        /* [indexed by minor] */

    120         int part_uevent_suppress;

    121         struct block_device_operations *fops;

    122         struct request_queue *queue;

    123         void *private_data;

    124         sector_t capacity;

    125

    126         int flags;

    127         struct device *driverfs_dev;

    128         struct kobject kobj;

    129         struct kobject *holder_dir;

    130         struct kobject *slave_dir;

    131

    132         struct timer_rand_state *random;

    133         int policy;

    134

    135         atomic_t sync_io;               /* RAID */

    136         unsigned long stamp;

    137         int in_flight;

    138 #ifdef  CONFIG_SMP

    139         struct disk_stats *dkstats;

    140 #else

    141         struct disk_stats dkstats;

    142 #endif

    143         struct work_struct async_notify;

    144 };

于是,struct scsi_diskstruct gendisk联手来为我们描述一块磁盘,scsi_diskscsi专用,gendisk中的gen表示general,过了英语四级的都知道,这表示通用,scsi,ide,大家伙都能利用的.

于是1604,alloc_disk就是为我们分配一个gendisk.

但是接下来1608行的sd_index_idr就有些学问了.

下面我们必须用专门一段文字来描述idr.首先在89行我们看到下面这么一句,

     89 static DEFINE_IDR(sd_index_idr);

这被叫做定义一个IDR.印象中大四上刚开学的时候,江湖中开始流传一篇文章叫做”idr”- integer ID management,专门对idr进行了一些介绍,这篇文章最早是发表在LWN(Linux Weekly News)上面.怎奈少不更事的我一直沉迷于上网,聊天,灌水,玩游戏,所以直到今天,依然不知道为什么这玩意儿叫做idr,只是懵懵懂懂的感觉它是一个用来管理一些小整数的工具,具体来说,就是内核中定义了一些函数,几乎所有的函数都被定义在一个文件中,lib/idr.c,关于它的实现咱们自然不必多说,说多了就未免喧宾夺主了,我们只看它的实际效果.

实际上我们一共调用了三个来自lib/idr.c的函数,或者更确切的说是四个,因为上面这个宏DEFINE_IDR也是一个函数的包装,总的来说,如果我们需要使用idr工具,我们就需要首先调用idr_init函数,或者使用它的马夹DEFINE_IDR,这算是初始化,也叫做创建一个idr对象,其实就是申请一个struct idr结构体变量.然后使用两个函数,一个是idr_pre_get(),一个是idr_get_new(),当我们日后觉得这个idr已经没有利用价值了,我们则可以调用另一个函数,idr_remove()来完成过河拆桥的工作.

我们看到1608行调用idr_pre_get(),其第一个参数就是我们之前初始化的&sd_index_idr,第二个参数是一个掩码,和我们以往每一次申请内存时一样,通常传递的就是GFP_KERNEL.这个函数有点与众不同的是,它返回0表示出错,返回非0才表示正常,典型的抽疯式函数.

1612,idr_get_new(),就是获得下一个availableID,保存在第三个参数中,即我们这里的index,第二个参数不是太常用,传递个NULL就可以了.一切正常将返回0.

index必须小于SD_MAX_DISKS,这个宏定义于include/scsi/sd.h:

     12  * This is limited by the naming scheme enforced in sd_probe,

     13  * add another character to it if you really need more disks.

     14  */

     15 #define SD_MAX_DISKS    (((26 * 26) + 26 + 1) * 26)

比这个宏还大就肯定出错了.关于这个宏,曾几何时,我也和你一样,丈二和尚摸不着头脑,我也曾彷徨,也曾犹豫,也曾困惑,后来有一天我终于明白了,26代表的是英文字母的个数,而下面我们马上就能看到,Linux中对scsi disk的命名规则正是利用了26个英文字母.

不信你就看16431659,这一段同时也正是idr的精华.最终你会发现,gd->disk_name一定是在sda-sdz之间,或者是在sdaasdzz之间,或者是在sdaaasdzzz之间.算一下,是不是正好数量为SD_MAX_DISKS.index的取值范围则是[0,SD_MAX_DISKS)之间,只取整数.举例来说,如果你只有一块硬盘,那么你能看到的是,/dev/sda,如果你有多块硬盘,比如像我下面这个例子中的一样,

localhost:~ # fdisk -l

 

Disk /dev/sda: 146.1 GB, 146163105792 bytes

255 heads, 63 sectors/track, 17769 cylinders

Units = cylinders of 16065 * 512 = 8225280 bytes

 

   Device Boot      Start         End      Blocks   Id  System

/dev/sda1               1         266     2136613+  83  Linux

/dev/sda2            2879       17769   119611957+  83  Linux

/dev/sda3   *         267        1572    10490445   83  Linux

/dev/sda4            1573        2878    10490445   82  Linux swap / Solaris

 

Partition table entries are not in disk order

 

Disk /dev/sdb: 5368 MB, 5368709120 bytes

166 heads, 62 sectors/track, 1018 cylinders

Units = cylinders of 10292 * 512 = 5269504 bytes

 

   Device Boot      Start         End      Blocks   Id  System

 

Disk /dev/sdc: 5368 MB, 5368709120 bytes

166 heads, 62 sectors/track, 1018 cylinders

Units = cylinders of 10292 * 512 = 5269504 bytes

 

   Device Boot      Start         End      Blocks   Id  System

 

Disk /dev/sdd: 5368 MB, 5368709120 bytes

166 heads, 62 sectors/track, 1018 cylinders

Units = cylinders of 10292 * 512 = 5269504 bytes

 

   Device Boot      Start         End      Blocks   Id  System

 

Disk /dev/sde: 5368 MB, 5368709120 bytes

166 heads, 62 sectors/track, 1018 cylinders

Units = cylinders of 10292 * 512 = 5269504 bytes

 

   Device Boot      Start         End      Blocks   Id  System

这个例子中我的机器里是5scsi硬盘,那么它们的名字分别是sda,sdb,sdc,sdd,sde,但是如果你他妈的比较变态,一台机器里接了30块硬盘,那么没啥说的,它们就会依次被命名为sda,sdb,…,sdx,sdy,sdz,这还不够,只有26,接下来的硬盘名称就叫做sdaa,sdab,sdac,sdad,总共凑满30.但如果你觉得这还不够变态,你非要挑战极限,你非要play zhuangbility,那么在用完了sdaasdzz之后,Linux还允许你用sdaaa,sdaab,…,一直到sdzzz.总之,Linux,你最多可以使用的硬盘数撑死就是SD_MAX_DISKS.当然,我还是奉劝你,别这么干,毕竟孔子曾经曰过:”莫装B,B遭雷劈!”

算了我们言归正传,1643,gd->major被赋了值,自从在张江软件园某不知名的小公司里笔试过那道不用临时变量交换两个变量的值之后,我曾深刻的反省自己为何当初没有好好学习谭浩强老师那本<<C程序设计>>中的位运算.痛定思痛之后,我终于能看懂眼前这代码了,当然首先我们得明白这个sd_major为何物?

    247 /*

    248  * Device no to disk mapping:

    249  *

    250  *       major         disc2     disc  p1

    251  *   |............|.............|....|....| <- dev_t

    252  *    31        20 19          8 7  4 3  0

    253  *

    254  * Inside a major, we have 16k disks, however mapped non-

    255  * contiguously. The first 16 disks are for major0, the next

    256  * ones with major1, ... Disk 256 is for major0 again, disk 272

    257  * for major1, ...

    258  * As we stay compatible with our numbering scheme, we can reuse

    259  * the well-know SCSI majors 8, 65--71, 136--143.

    260  */

    261 static int sd_major(int major_idx)

    262 {

    263         switch (major_idx) {

    264         case 0:

    265                 return SCSI_DISK0_MAJOR;

    266         case 1 ... 7:

    267                 return SCSI_DISK1_MAJOR + major_idx - 1;

    268         case 8 ... 15:

    269                 return SCSI_DISK8_MAJOR + major_idx - 8;

    270         default:

    271                 BUG();

    272                 return 0;       /* shut up gcc */

    273         }

    274 }

看起来挺复杂,其实不然,我们前面说过,scsi disk的主设备号是已经固定好了的,它就是瓜分了8,65-71,128-135这几个号,这里SCSI_DISK0_MAJOR就是8,SCSI_DISK1_MAJOR就是65,SCSI_DISK8_MAJOR就是128.sd_major()接受的参数就是indexbit4bit7,而它取值范围自然就是015,这也正是sd_major()switch/case语句判断的范围,即实际上major_idx就是主设备号的一个索引,就说是在这个16个主设备号中它算老几.first_minor就是对应于本index的第一个次设备号,我们可以用代入法得到,index0,first_minor0,index1,first_minor16,index2,first_minor32.另一方面,minor本身表示本index下有多少个次设备号,这个大家都是一样的,都是16.我们通过下面这个例子也能看到:

[root@localhost ~]# cat /proc/partitions

major minor  #blocks  name

 

   8     0  285474816 sda

   8     1    2104483 sda1

   8     2   16779892 sda2

   8     3          1 sda3

   8     5   20972826 sda5

   8     6   20482843 sda6

   8     7   20482843 sda7

   8     8   10241406 sda8

   8     9   20482843 sda9

   8    10   20482843 sda10

   8    11   20482843 sda11

   8    12   20482843 sda12

   8    13   20482843 sda13

   8    14   20482843 sda14

   8    15   20482843 sda15

   8    16    5242880 sdb

   8    32    5242880 sdc

   8    48    5242880 sdd

   8    64    5242880 sde

很显然,对于sda,其次设备是从0开始,对于sdb,次设备号从16开始,对于sdc,则从32开始,sdd则从48开始,每个index或者说每个disk_name下面有16个次设备号.也因此一块SCSI硬盘就是最多15个分区.

除此之外,sd_probe中主要就是些简单的赋值了.当然也不全是,比如1633行到1639行这一段,它的效果就是让这个设备出现在了sysfsclass子目录下面,比如下面这个例子:

localhost:~ # cat /sys/class/scsi_device/

0:0:8:0/ 0:2:0:0/ 1:0:0:0/ 1:0:0:1/ 1:0:0:2/ 1:0:0:3/

每一个scsi设备都在这个占了一个子目录.

1641行这个get_device不用多说,访问一个struct device的第一步,增加引用计数.以后不用的时候自然会有一个相对的函数put_device被调用.

1671,dev_set_drvdata,就是设置dev->driver_data等于sdkp,即让struct device的指针devstruct scsi_disk的指针sdkp给联系起来.这就是所谓的朋友多了路好走,关系网建立得越大,日后使用起来就越方便.

最后,特别提醒两个赋值.第一个是,1621,sdkp->driver等于&sd_template,另一个是1646,gd->fops等于&sd_fops.这两行赋值对咱们整个故事的意义,不亚于1979年那个春天有一位老人在中国的南海边划了一个圈对中国的重大意义.在咱们讲完sd_probe之后,这两个赋值将引领我们展开下面的故事.

关于sd_probe,眼瞅着就要完了,但是很显然,有两个函数我们还没有提到,它们就是1664行的sd_revalidate_disk()以及1672行的add_disk(),这两个函数是如此的重要,以至于我们有必要在下一节专门来讲述它们.

 
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值