infi.storagemodelでストレージデバイスのhtclパラメータを取得する方法

3828 ワード

infi.storagemodelはgithubのオープンソースプロジェクトで、次のリンクがあります.https://github.com/Infinidat/infi.storagemodel
その中の/infi/storagemodel/linuxディレクトリの下のLinuxStorageModel(UnixStorageModel)クラスでは、同じディレクトリの下の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は、1つまたは複数の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]の4つの数字は、この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は2つのパラメータを返しますfour_in_oneとhost_unique_id,このfour in oneのパラメータは実は私たちが必要とするhctlパラメータで、get_を見に戻ります.hctl_for_sd_デバイス関数はどのようにこの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は1番目の8ビット、channelは2番目の8ビット、lunは3番目の8ビット、targetは4番目の8ビット、lsscsiが出てくる[0:0:1:0]対応するfour_in_oneパラメータは:0|0|0|1であり,この32ビットのバイナリ数の10進数は1である.