通过单个函数发送各种scsi命令

时间:2014-03-13 01:04:32

标签: c linux hard-drive scsi

我一直在玩scsi命令,我可以发送一些基本命令,如不同的inquirys等。

我一直用这个例子来生成我的查询。我正在努力使这个示例使用不同的scsi命令。

http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/pexample.html

我已经更改为通过结构接受不同的scsi命令的函数,它还返回基于输出的结构。这完美地适用于调查。但是,如果我发送READ CAPACITY(16)命令,则函数会在if语句中触发:

(io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)

我是scsi编程的新手,所以我可能会做一些完全错误的事情......

我的READ CAPACITY(16)命令就是这样:

scsi_read_capacity.cmdblk[0]=0x9e;
scsi_read_capacity.cmdblk[13]=32;

CDB的其余部分为0!

这是代码:

#include <stdio.h>
#include <sys/ioctl.h>
#include <scsi/sg.h> 


/* global struct to store return data from a scsi cmd*/

typedef struct SCSI_data {
    unsigned char    data[1024];

    unsigned char    raw_sens[252];
    unsigned char    sense_key;
    unsigned char    additional_sense_code;
    unsigned char    additional_sense_qualifier;
    unsigned char    additional_sense_length;

    unsigned char    sense_data_descriptors[10][244];

    int              result;
} SCSI_data;



/* global struct to store return data from a scsi cmd*/

typedef struct SCSI_cmd {
    int              sg_fd;
    unsigned char    cmdblk[32];
    int              cmdblklength;
    int              allocation_length;
    int              xfer;
    int              timeout;

} SCSI_cmd;


SCSI_data send_scsicmd(SCSI_cmd cmdobject) {
    int k;;

    unsigned char inqBuff[cmdobject.allocation_length];
    unsigned char sense_buffer[252];

    SCSI_data output_data;
    sg_io_hdr_t io_hdr;

    /* Prepare INQUIRY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = cmdobject.cmdblklength;
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = cmdobject.xfer;
    io_hdr.dxfer_len = cmdobject.allocation_length;
    io_hdr.dxferp = inqBuff;
    io_hdr.cmdp = cmdobject.cmdblk;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = cmdobject.timeout;

    if (ioctl(cmdobject.sg_fd, SG_IO, &io_hdr) < 0) {
        output_data.result=2;
        return output_data;
    }

    /* now for the error processing */
    if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
        output_data.result=1;
        if (io_hdr.sb_len_wr > 0) {
            printf("INQUIRY sense data: ");
            for (k = 0; k < io_hdr.sb_len_wr; ++k) {
                if ((k > 0) && (0 == (k % 10)))
                    printf("\n  ");
                printf("0x%02x ", sense_buffer[k]);
            }
            printf("\n");
        }

        if (io_hdr.masked_status)
            printf("INQUIRY SCSI status=0x%x\n", io_hdr.status);

        if (io_hdr.host_status)
            printf("INQUIRY host_status=0x%x\n", io_hdr.host_status);

        if (io_hdr.driver_status)
            printf("INQUIRY driver_status=0x%x\n", io_hdr.driver_status);
    }

    else {  /* assume INQUIRY response is present */
        output_data.result=0;
        for (k=0;k<cmdobject.allocation_length;k++) {
            output_data.data[k]=inqBuff[k];
        }
    }
    return output_data;
}


int main(int argc, char * argv[]) {

    FILE *driveptr=fopen(argv[1], "r");

    int i;

    SCSI_data   scsi_data_read_capacity;

    SCSI_cmd    scsi_read_capacity;


    scsi_read_capacity.sg_fd=fileno(driveptr);
    scsi_read_capacity.cmdblk[0]=0x9e;
    scsi_read_capacity.cmdblk[13]=32;
    scsi_read_capacity.cmdblklength=16;
    scsi_read_capacity.xfer=SG_DXFER_FROM_DEV;
    scsi_read_capacity.allocation_length=32;
    scsi_read_capacity.timeout=1000;

    scsi_data_read_capacity=send_scsicmd(scsi_read_capacity);

    if (scsi_data_read_capacity.result==0) {
        printf("    capacity in blocks: %02x%02x%02x%02x%02x%02x%02x%02x\n",
            scsi_data_read_capacity.data[0],
            scsi_data_read_capacity.data[1],
            scsi_data_read_capacity.data[2],
            scsi_data_read_capacity.data[3],
            scsi_data_read_capacity.data[4],
            scsi_data_read_capacity.data[5],
            scsi_data_read_capacity.data[6],
            scsi_data_read_capacity.data[7]);

        printf("             blocksize: %02x%02x%02x%02x\n",
            scsi_data_read_capacity.data[8],
            scsi_data_read_capacity.data[9],
            scsi_data_read_capacity.data[10],
            scsi_data_read_capacity.data[11]);

    }

    fclose(driveptr);

    return 0;
}

1 个答案:

答案 0 :(得分:0)

我只是一个小问题。我的CDB错了!

我必须使用它:

scsi_read_capacity.cmdblk[0]=0x9E;
scsi_read_capacity.cmdblk[1]=0x10;
scsi_read_capacity.cmdblk[13]=32;

第二个字节必须等于0x10,这是因为scsi cmd 0x9E是一个服务操作命令,它在第二个字节中接受一个定义其行为的参数!