如何通过 ioctl 调用或其他方式确定 SCSI 设备(例如 /etc/sda)是不是为磁盘?

Posted

技术标签:

【中文标题】如何通过 ioctl 调用或其他方式确定 SCSI 设备(例如 /etc/sda)是不是为磁盘?【英文标题】:How to find out if SCSI device (say /etc/sda) is a disk or not via ioctl calls or other?如何通过 ioctl 调用或其他方式确定 SCSI 设备(例如 /etc/sda)是否为磁盘? 【发布时间】:2010-04-23 12:33:10 【问题描述】:

如何通过 ioctl 调用或其他方式确定 SCSI 设备(例如 /dev/sda)是否为磁盘? 我尝试了以下方法,但 ioctl 调用失败。我的 /dev/sda 是 U 盘。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>

int main(int argc, char** argv) 
    char *dev = "/dev/sda";
    struct sg_scsi_id m_id;
    int rc;
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) 
        perror(dev);
    
    memset(&m_id, 0, sizeof (m_id));
    rc = ioctl(fd, SG_GET_SCSI_ID, &m_id);
    if (rc < 0) 
        close(fd);
        printf("FAIL: ioctl SG_GET_SCSI_ID, rc=%d, errno=%d\n", rc, errno);
     else 
        if (m_id.scsi_type == TYPE_DISK || m_id.scsi_type == 14) 
            printf("OK: is disk\n");
         else 
            printf("OK: is NOT disk\n");
        
    
    close(fd);
    return (EXIT_SUCCESS);

// result is: FAIL: ioctl SG_GET_SCSI_ID, rc=-1, errno=22

【问题讨论】:

【参考方案1】:

我已经使用SG_IO 解决了这个问题,并根据INQUIRY command 的规范直接解释二进制数据(字段:外围设备类型)并根据SCSI Peripheral Device Types 解释它们(如果每个开发人员类型是磁盘)是 00h 或 0Eh)

int is_disk_sd(char *dev) 
    unsigned char sense[32];
    struct sg_io_hdr io_hdr;
    char scsi_data[SCSI_LEN];
    struct hd_geometry geo;
    // request for "standard inquiry data"
    unsigned char inq_cmd[] = INQUIRY, 0, 0, 0, SCSI_LEN, 0;
    int fd;

    fd = open(dev, O_RDONLY | O_NONBLOCK);
    if (fd < 0) 
        perror(dev);
    

    memset(&io_hdr, 0, sizeof (io_hdr));
    io_hdr.interface_id = 'S';
    io_hdr.cmdp = inq_cmd;
    io_hdr.cmd_len = sizeof (inq_cmd);
    io_hdr.dxferp = scsi_data;
    io_hdr.dxfer_len = sizeof (scsi_data);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.sbp = sense;
    io_hdr.mx_sb_len = sizeof (sense);
    io_hdr.timeout = 5000;

    if (ioctl(fd, SG_IO, &io_hdr) < 0) 
        close(fd);
        return 0;
     else 
        close(fd);
        if (scsi_data[1] & 0x80) 
            return 0; // support is removable
        
        if ((scsi_data[0] & 0x1f) || ((scsi_data[0] & 0x1f) != 0xe))  // 0 or 14 (00h or 0Eh)
            return 0; // not direct access neither simplified direct access device
        
        return 1;
    

【讨论】:

【参考方案2】:

也许您可以从 /sys/bus/scsi/devices/*/ 文件系统获得有用的信息。

【讨论】:

ty,它确实有帮助,我会通过 ioctl strong 挖掘更多内容。 [root@localhost ~]# cat /proc/scsi/scsi 附加设备:主机:scsi1 频道:00 Id:00 Lun:00 供应商:SanDisk 型号:Cruzer Rev:8.01 类型:直接访问 ANSI SCSI 修订:02【参考方案3】:

HDIO_GET_IDENTITY 似乎适用于我的磁盘,但不适用于闪存驱动器。我认为这是hdparm -i 使用的。

【讨论】:

它在 SATA 磁盘上使用 libata 显示为/dev/sda。我没有要检查的 SCSI 磁盘。

以上是关于如何通过 ioctl 调用或其他方式确定 SCSI 设备(例如 /etc/sda)是不是为磁盘?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Free Pascal 上为接口列表或其他 ioctl 调用 ioctl?

SCSI INQUIRY 命令的 DeviceIoControl 返回错误 50

如何调用 compat_ioctl 或 unlocked_ioctl?

linux ioctl 方法

什么是网络 ioctl 手册页?

为啥 ioctl 调用没有传递给 sys_ioctl?