美文网首页
infi.storagemodel中如何获取存储设备的htcl参

infi.storagemodel中如何获取存储设备的htcl参

作者: Stansosleepy | 来源:发表于2015-08-06 01:13 被阅读238次

    infi.storagemodel是github上的一个开源的项目,链接如下:
    https://github.com/Infinidat/infi.storagemodel

    在其中的/infi/storagemodel/linux目录下的LinuxStorageModel(UnixStorageModel)类中,需要获取一个Sysfs()对象,这个对象是在同一个目录下的sysfs.py实现的,Sysfs对象内部有一个hctl对象,这个hctl对象是什么呢?

    一、HCTL参数

    在linux中,scsi有4个层级的寻址方案:

    • SCSI adapter number [host]
    • channel number [bus]
    • id number [target]
    • lun [lun]

    解释:
    SCSI适配器编号通常是在计算机内部IO总线上的一个任意的号码,这些适配器通常被叫做HBA(host bus adapter),SCSI适配器编号是由内核指定的,且从0开始增加。
    每一个HBA都控制了一个或多个SCSI总线。
    每个SCSI总线都连接多个SCSI设备,在SCSI中称HBA为initiator,initiator和通常称之为SCSI设备的targets进行通信。

    在lsscsi命令的manpage中,我们可以看到如下的解释,

    Generic SCSI devices can also be accessed via the bsg driver in Linux. By default, the bsg driver's device node names are of the form '/dev/bsg/H:C:T:L'.

    执行lsscsi可以看到如下显示结果:

    [0:0:0:0]    disk    VMware,  VMware Virtual S 1.0   /dev/sda 
    [0:0:1:0]    disk    VMware,  VMware Virtual S 1.0   /dev/sdb 
    [2:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR10 1.00  /dev/sr0 
    

    前面的[0:0:1:0]四个数字就代表了这个scsi设备的hctl参数,分别是:

    • host: SCSI hosts currently attached to the system.调用lsscsi -H可以看到所有host
    • channel
    • target:
    • lun: 逻辑单元数

    二、获取HCTL

    获取HCTL可以通过直接调用lsscsi,更为有效的方法是直接给device发送ioctl的请求,在infi.stragemodel中使用的是后者:

    跟踪hctl的获取方法,Sysfs类中调用了一个方法:

    from infi.sgutils.sg_map import get_hctl_for_sd_device
    #dev_path='/dev/sdb'
    hctl = get_hctl_for_sd_device(dev_path)
    

    这个方法的实现:

    def get_hctl_for_sd_device(device_path):
        from ..ioctl import scsi_ioctl_get_idlun as _ioctl
        #获取一个SCSI_IDLUN对象
        struct = _ioctl(device_path)
        # http://tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html
        # "four_in_one" is made up as follows:
        # (scsi_device_id | (lun << 8) | (channel << 16) | (host_no << 24))
        host = (struct.four_in_one >> 24)
        channel = (struct.four_in_one >> 16) & 0xFF
        target = (struct.four_in_one) & 0xFF
        lun = (struct.four_in_one >> 8) & 0xFF
        result = HCTL(host, channel, target, lun)
        return HCTL(host, channel, target, lun)
    

    scsi_ioctl_get_idlun的实现:

    def scsi_ioctl_get_idlun(device_path):
        from array import array  
        struct_cls = structures.SCSI_IDLUN     
        size = struct_cls.min_max_sizeof().max 
        buffer = array("B", [0]*size)
        #调用下一个函数,op是固定的0x5382,执行结果回写到buffer中
        result = ioctl(device_path, opcodes.SCSI_IOCTL_GET_IDLUN, buffer)
        struct = struct_cls.create_from_string(buffer)
        #返回SCSI_IDLUN(four_in_one=1, host_unique_id=0)
        return struct
    
    def ioctl(device_path, op_number, buffer=None):
        #打开/dev/sdb,拿到句柄
        fd = os.open(device_path, os.O_RDONLY | os.O_NONBLOCK)
        try:
            from fcntl import ioctl as _ioctl
            args = [fd, op_number,]
            if buffer is not None: 
                args.extend([buffer, True])
            #args=[3, 21378, array('B', [0, 0, 0, 0, 0, 0, 0, 0]), True]
            return _ioctl(*args)
        finally:
            os.close(fd)
    

    scsi_ioctl_get_idlun返回两个参数,four_in_one和host_unique_id,这个four in one的参数其实就是我们需要的hctl参数,返回去看get_hctl_for_sd_device函数是怎么解析这个four in one的:

    host = (struct.four_in_one >> 24)
    channel = (struct.four_in_one >> 16) & 0xFF
    target = (struct.four_in_one) & 0xFF
    lun = (struct.four_in_one >> 8) & 0xFF
    result = HCTL(host, channel, target, lun)
    

    可以看出这个参数是一个4*8=32位的int型变量,host是第一个8位,channel是第二个8位,lun是第三个8位,target是第4个8位,lsscsi出来的[0:0:1:0]对应的four_in_one参数为:0|0|0|1,这个32位的二进制数的十进制值为1。

    相关文章

      网友评论

          本文标题:infi.storagemodel中如何获取存储设备的htcl参

          本文链接:https://www.haomeiwen.com/subject/vhxbqttx.html