Exemple #1
0
/* Return of 0 -> success, -1 -> failure, 2 -> try again */
static int
read_capacity(int sg_fd, int * num_sect, int * sect_sz)
{
    int res;
    unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char rcBuff[64];
    unsigned char sense_b[64];
    sg_io_hdr_t io_hdr;

    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(rcCmdBlk);
    io_hdr.mx_sb_len = sizeof(sense_b);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = sizeof(rcBuff);
    io_hdr.dxferp = rcBuff;
    io_hdr.cmdp = rcCmdBlk;
    io_hdr.sbp = sense_b;
    io_hdr.timeout = DEF_TIMEOUT;

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("read_capacity (SG_IO) error");
        return -1;
    }
    res = sg_err_category3(&io_hdr);
    if (SG_LIB_CAT_UNIT_ATTENTION == res)
        return 2; /* probably have another go ... */
    else if (SG_LIB_CAT_CLEAN != res) {
        sg_chk_n_print3("read capacity", &io_hdr, 1);
        return -1;
    }
    *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) |
                (rcBuff[2] << 8) | rcBuff[3]);
    *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
               (rcBuff[6] << 8) | rcBuff[7];
#ifdef SG_DEBUG
    fprintf(stderr, "number of sectors=%d, sector size=%d\n",
            *num_sect, *sect_sz);
#endif
    return 0;
}
int main(int argc, char * argv[])
{
    int sg_fd, k, ok;
    uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] =
                {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0};
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    uint8_t inBuff[ID_RESPONSE_LEN];
    uint8_t sense_buffer[32];
    int do_packet = 0;
    int verbose = 0;
    int extend = 0;
    int chk_cond = 0;   /* set to 1 to read register(s) back */
    int protocol = 4;   /* PIO data-in */
    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
    int t_length = 2;   /* 0 -> no data transferred, 2 -> sector count */
    const uint8_t * cucp;

    memset(inBuff, 0, sizeof(inBuff));
    for (k = 1; k < argc; ++k) {
        if (0 == strcmp(argv[k], "-p"))
            ++do_packet;
        else if (0 == strcmp(argv[k], "-v"))
            ++verbose;
        else if (0 == strcmp(argv[k], "-vv"))
            verbose += 2;
        else if (0 == strcmp(argv[k], "-vvv"))
            verbose += 3;
        else if (0 == strcmp(argv[k], "-V")) {
            fprintf(stderr, "version: %s\n", version_str);
            exit(0);
        } else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        usage();
        return 1;
    }

    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg__sat_identify: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }

    /* Prepare ATA PASS-THROUGH COMMAND (16) command */
    apt_cdb[6] = 1;   /* sector count */
    apt_cdb[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE :
                                 ATA_IDENTIFY_DEVICE);
    apt_cdb[1] = (protocol << 1) | extend;
    apt_cdb[2] = (chk_cond << 5) | (t_dir << 3) |
                 (byte_block << 2) | t_length;
    if (verbose) {
        fprintf(stderr, "    ata pass through(16) cdb: ");
        for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k)
            fprintf(stderr, "%02x ", apt_cdb[k]);
        fprintf(stderr, "\n");
    }

    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(apt_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = ID_RESPONSE_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = apt_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg__sat_identify: SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        if (verbose)
            sg_chk_n_print3(">>> ATA_16 command", &io_hdr, 1);
        /* check for ATA Return Descriptor */
        cucp = sg_scsi_sense_desc_find(io_hdr.sbp, io_hdr.sb_len_wr,
                                       SAT_ATA_RETURN_DESC);
        if (cucp && (cucp[3])) {
            if (cucp[3] & 0x4) {
                printf("error in returned FIS: aborted command\n");
                printf("    try again with%s '-p' option\n",
                       (do_packet ? "out" : ""));
                break;
            }
        }
        ok = 1;         /* not sure what is happening so output response */
        if (0 == verbose) {
            printf(">>> Recovered error on ATA_16, may have failed\n");
            printf("    Add '-v' for more information\n");
        }
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        printf("Response for IDENTIFY %sDEVICE ATA command:\n",
               (do_packet ? "PACKET " : ""));
        dWordHex((const unsigned short *)inBuff, 256, 0,
                 sg_is_big_endian());
    }

    close(sg_fd);
    return 0;
}
Exemple #3
0
/* Returns 0 -> successful, various SG_LIB_CAT_* positive values,
 * -2 -> recoverable (ENOMEM), -1 -> unrecoverable error */
static int
sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block,
         int bs, int cdbsz, int fua, int dpo, int do_mmap, int * diop)
{
    unsigned char wrCmd[MAX_SCSI_CDBSZ];
    unsigned char senseBuff[SENSE_BUFF_LEN];
    struct sg_io_hdr io_hdr;
    int k, res;

    if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, dpo)) {
        pr2serr(ME "bad wr cdb build, to_block=%" PRId64 ", blocks=%d\n",
                to_block, blocks);
        return SG_LIB_SYNTAX_ERROR;
    }

    memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = cdbsz;
    io_hdr.cmdp = wrCmd;
    io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
    io_hdr.dxfer_len = bs * blocks;
    if (! do_mmap)
        io_hdr.dxferp = buff;
    io_hdr.mx_sb_len = SENSE_BUFF_LEN;
    io_hdr.sbp = senseBuff;
    io_hdr.timeout = DEF_TIMEOUT;
    io_hdr.pack_id = (int)to_block;
    if (do_mmap)
        io_hdr.flags |= SG_FLAG_MMAP_IO;
    else if (diop && *diop)
        io_hdr.flags |= SG_FLAG_DIRECT_IO;
    if (verbose > 2) {
        pr2serr("    write cdb: ");
        for (k = 0; k < cdbsz; ++k)
            pr2serr("%02x ", wrCmd[k]);
        pr2serr("\n");
    }

#if 1
    while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) &&
            ((EINTR == errno) || (EAGAIN == errno)))
        sleep(1);
    if (res < 0) {
        perror(ME "SG_IO error (sg_write)");
        return -1;
    }
#else
    while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
            ((EINTR == errno) || (EAGAIN == errno)))
        ;
    if (res < 0) {
        if (ENOMEM == errno)
            return -2;
        perror("writing (wr) on sg device, error");
        return -1;
    }

    while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
            ((EINTR == errno) || (EAGAIN == errno)))
        ;
    if (res < 0) {
        perror("writing (rd) on sg device, error");
        return -1;
    }
#endif
    if (verbose > 2)
        pr2serr("      duration=%u ms\n", io_hdr.duration);
    res = sg_err_category3(&io_hdr);
    switch (res) {
    case SG_LIB_CAT_CLEAN:
        break;
    case SG_LIB_CAT_RECOVERED:
        sg_chk_n_print3("Writing, continuing", &io_hdr, verbose > 1);
        break;
    case SG_LIB_CAT_NOT_READY:
    case SG_LIB_CAT_MEDIUM_HARD:
        return res;
    case SG_LIB_CAT_ABORTED_COMMAND:
    case SG_LIB_CAT_UNIT_ATTENTION:
    case SG_LIB_CAT_ILLEGAL_REQ:
    default:
        sg_chk_n_print3("writing", &io_hdr, verbose > 1);
        return res;
    }
    if (diop && *diop &&
            ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
        *diop = 0;      /* flag that dio not done (completely) */
    return 0;
}
Exemple #4
0
int main(int argc, char * argv[])
{
    int sg_fd, k, ok /*, sg_fd2 */;
    uint8_t inq_cdb [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    uint8_t tur_cdb [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0};
    uint8_t inqBuff[INQ_REPLY_LEN];
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    uint8_t sense_buffer[32];
    int do_extra = 0;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-x", argv[k], 2))
            do_extra = 1;
        else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_excl [-x] <sg_device>'\n");
        return 1;
    }

    /* N.B. An access mode of O_RDWR is required for some SCSI commands */
    if ((sg_fd = open(file_name, O_RDWR | O_EXCL | O_NONBLOCK)) < 0) {
        snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    /* Just to be safe, check we have a new sg device by trying an ioctl */
    if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
        printf(ME "%s doesn't seem to be an new sg device\n",
               file_name);
        close(sg_fd);
        return 1;
    }
#if 0
    if ((sg_fd2 = open(file_name, O_RDWR | O_EXCL)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 ME "error opening file: %s a second time", file_name);
        perror(ebuff);
        return 1;
    } else {
        printf(ME "second open of %s in violation of O_EXCL\n", file_name);
        close(sg_fd2);
    }
#endif

    /* Prepare INQUIRY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(inq_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = INQ_REPLY_LEN;
    io_hdr.dxferp = inqBuff;
    io_hdr.cmdp = inq_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror(ME "Inquiry SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on INQUIRY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("INQUIRY command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        char * p = (char *)inqBuff;
        int f = (int)*(p + 7);
        printf("Some of the INQUIRY command's results:\n");
        printf("    %.8s  %.16s  %.4s  ", p + 8, p + 16, p + 32);
        printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n",
               !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1));
        /* Extra info, not necessary to look at */
        if (do_extra)
            printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n",
                   io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
    }


    /* Prepare TEST UNIT READY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(tur_cdb);
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_NONE;
    io_hdr.cmdp = tur_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror(ME "Test Unit Ready SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on Test Unit Ready, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1);
        break;
    }

    if (ok)
        printf("Test Unit Ready successful so unit is ready!\n");
    else
        printf("Test Unit Ready failed so unit may _not_ be ready!\n");

    if (do_extra)
        printf("TEST UNIT READY duration=%u millisecs, resid=%d, "
               "msg_status=%d\n", io_hdr.duration, io_hdr.resid,
                (int)io_hdr.msg_status);

    sleep(60);
    close(sg_fd);
    return 0;
}
int main(int argc, char * argv[])
{
    int sg_fd, k, ok;
    unsigned char apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] =
                {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0};
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char inBuff[SMART_READ_DATA_RESPONSE_LEN];
    unsigned char sense_buffer[32];
    int verbose = 0;
    int extend = 0;
    int chk_cond = 0;   /* set to 1 to read register(s) back */
    int protocol = 4;   /* PIO data-in */
    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
    int t_length = 2;   /* 0 -> no data transferred, 2 -> sector count */
    const unsigned char * bp = NULL;

    for (k = 1; k < argc; ++k) {
        if (0 == strcmp(argv[k], "-v"))
            ++verbose;
        else if (0 == strcmp(argv[k], "-vv"))
            verbose += 2;
        else if (0 == strcmp(argv[k], "-vvv"))
            verbose += 3;
        else if (0 == strcmp(argv[k], "-V")) {
            fprintf(stderr, "version: %s\n", version_str);
            exit(0);
        } else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_sat_smart_rd_data [-v] [-V] <device>'\n");
        return 1;
    }

    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_sat_smart_rd_data: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }

    /* Prepare ATA PASS-THROUGH COMMAND (16) command */
    apt_cdb[4] = ATA_SMART_READ_DATA;   /* feature (7:0) */
    apt_cdb[6] = 1;   /* number of block (sector count) */
    apt_cdb[10] = 0x4f;    /* lba_mid (7:0) */
    apt_cdb[12] = 0xc2;    /* lba_high (7:0) */
    apt_cdb[14] = ATA_SMART;
    apt_cdb[1] = (protocol << 1) | extend;
    apt_cdb[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) |
                 t_length;
    if (verbose) {
        fprintf(stderr, "    ata pass through(16) cdb: ");
        for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k)
            fprintf(stderr, "%02x ", apt_cdb[k]);
        fprintf(stderr, "\n");
    }

    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(apt_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = SMART_READ_DATA_RESPONSE_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = apt_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_sat_smart_rd_data: SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
                                     SAT_ATA_RETURN_DESC);
        if (NULL == bp) {
            if (verbose > 1)
                printf("ATA Return Descriptor expected in sense but not "
                       "found\n");
            sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
        } else if (verbose)
            sg_chk_n_print3("ATA Return Descriptor", &io_hdr, 1);
        if (bp && bp[3])
            printf("error=0x%x, status=0x%x\n", bp[3], bp[13]);
        else
            ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        printf("Response:\n");
        dWordHex((const unsigned short *)inBuff, 256, 0,
                 sg_is_big_endian());
    }

    close(sg_fd);
    return 0;
}
Exemple #6
0
int main(int argc, char * argv[])
{
    int sg_fd, k, ok;
    unsigned char inqCmdBlk [INQ_CMD_LEN] =
                                {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    unsigned char turCmdBlk [TUR_CMD_LEN] =
                                {0x00, 0, 0, 0, 0, 0};
    unsigned char inqBuff[INQ_REPLY_LEN];
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char sense_buffer[32];
    int do_extra = 0;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-x", argv[k], 2))
            do_extra = 1;
        else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_simple_aio [-x] <sg_device>'\n");
        return 1;
    }

    /* An access mode of O_RDWR is required for write()/read() interface */
    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
		 "sg_simple_aio: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    /* Just to be safe, check we have a new sg device by trying an ioctl */
    if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
        printf("sg_simple_aio: %s doesn't seem to be an new sg device\n",
               file_name);
        close(sg_fd);
        return 1;
    }

    /* Prepare INQUIRY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(inqCmdBlk);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = INQ_REPLY_LEN;
    io_hdr.dxferp = inqBuff;
    io_hdr.cmdp = inqCmdBlk;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

#if 1
    {
        struct iocb a_iocb;
        struct iocb * iocb_arr[1];
        io_context_t io_ctx;
        int res;

        if (0 != (res = io_queue_init(1, &io_ctx))) {
            printf("io_queue_init: failed %s\n", strerror(-res));
            close(sg_fd);
            return 1;
        }
        iocb_arr[0] = &a_iocb;
        io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0);
        io_set_callback(iocb_arr[0], my_io_callback);
        res = io_submit(io_ctx, 1, iocb_arr);
        if (1 != res) {
            printf("io_submit: returned %d\n", res);
            close(sg_fd);
            return 1;
        }
    }
#else
    if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
        perror("sg_simple_aio: Inquiry write error");
        close(sg_fd);
        return 1;
    }
#endif
    /* sleep(3); */
    if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
        perror("sg_simple_aio: Inquiry read error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on INQUIRY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("INQUIRY command error", &io_hdr);
        break;
    }

    if (ok) { /* output result if it is available */
        char * p = (char *)inqBuff;
        int f = (int)*(p + 7);
        printf("Some of the INQUIRY command's results:\n");
        printf("    %.8s  %.16s  %.4s  ", p + 8, p + 16, p + 32);
        printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n",
               !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1));
        /* Extra info, not necessary to look at */
        if (do_extra)
            printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n",
                   io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
    }

    /* Prepare TEST UNIT READY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(turCmdBlk);
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_NONE;
    io_hdr.cmdp = turCmdBlk;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple_aio: Test Unit Ready SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on Test Unit Ready, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("Test Unit Ready command error", &io_hdr);
        break;
    }

    if (ok)
        printf("Test Unit Ready successful so unit is ready!\n");
    else
        printf("Test Unit Ready failed so unit may _not_ be ready!\n");

    if (do_extra)
        printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n",
               io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);

    close(sg_fd);
    return 0;
}
Exemple #7
0
int getPowerMode(char * file_name, int verbose) {
	char ebuff[EBUFF_SZ];
	int extend = 0, sg_fd;
	int chk_cond = 1;   /* set to 1 to read register(s) back */
	int protocol = 3;   /* non-dat data-in */
	int t_dir = 1;      /* 0 -> to device, 1 -> from device */
	int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
	int t_length = 0;   /* 0 -> no data transferred, 2 -> sector count */
	unsigned char sense_buffer[64];
	int k;
	const unsigned char * ucp = NULL;
	
	unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] =
	{SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0};
	sg_io_hdr_t io_hdr;
	
	if ((sg_fd = open(file_name, O_RDWR)) < 0) {
		snprintf(ebuff, EBUFF_SZ,
			"sg_sat_chk_power: error opening file: %s", file_name);
		perror(ebuff);
		return PM_STATUS_UNKNOWN;
	}
	
	/* Prepare ATA PASS-THROUGH COMMAND (16) command */
	aptCmdBlk[14] = ATA_CHECK_POWER_MODE;
	aptCmdBlk[1] = (protocol << 1) | extend;
	aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) |
	(byte_block << 2) | t_length;
	if (verbose) {
		fprintf(stderr, "    ata pass through(16) cdb: ");
		for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k)
			fprintf(stderr, "%02x ", aptCmdBlk[k]);
		fprintf(stderr, "\n");
	}
	
	memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
	io_hdr.interface_id = 'S';
	io_hdr.cmd_len = sizeof(aptCmdBlk);
	io_hdr.mx_sb_len = sizeof(sense_buffer);
	io_hdr.dxfer_direction = SG_DXFER_NONE;
	io_hdr.dxfer_len = 0;
	io_hdr.dxferp = NULL;
	io_hdr.cmdp = aptCmdBlk;
	io_hdr.sbp = sense_buffer;
	io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
	
	if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
		perror("sg_sat_chk_power: SG_IO ioctl error");
		close(sg_fd);
		return 1;
	}
	
	/* error processing: N.B. expect check condition, no sense ... !! */
	switch (sg_err_category3(&io_hdr)) {
	case SG_LIB_CAT_CLEAN:
		break;
	case SG_LIB_CAT_RECOVERED:  /* sat-r09 (latest) uses this sk */
	case SG_LIB_CAT_NO_SENSE:   /* earlier SAT drafts used this */
		/* XXX: Until the spec decides which one to go with. 20060607 */
		ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
			SAT_ATA_RETURN_DESC);
		if (NULL == ucp) {
			if (verbose > 1)
			printf("ATA Return Descriptor expected in sense but not "
				"found\n");
			sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
		} else if (verbose)
		sg_chk_n_print3("ATA Return Descriptor, as expected",
			&io_hdr, 1);
		if (ucp && ucp[3]) {
			if (ucp[3] & 0x4)
				printf("error in returned FIS: aborted command\n");
			else
				printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]);
		}
		break;
	default:
		fprintf(stderr, "unexpected SCSI sense category\n");
		ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
			SAT_ATA_RETURN_DESC);
		if (NULL == ucp)
			sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
		else if (verbose)
		sg_chk_n_print3("ATA Return Descriptor, as expected",
			&io_hdr, 1);
		if (ucp && ucp[3]) {
			if (ucp[3] & 0x4)
				printf("error in returned FIS: aborted command\n");
			else
				printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]);
		}
		break;
	}
	int ret = PM_STATUS_UNKNOWN;
	if (ucp) {
		switch (ucp[5]) {       /* sector_count (7:0) */
		case 0xff:
			if(verbose)
				printf("In active mode or idle mode\n");
			ret = PM_STATUS_ACTIVE;
			break;
		case 0x80:
			if(verbose)
				printf("In idle mode\n");
			ret = PM_STATUS_IDLE;
			break;
		case 0x41:
			if(verbose)
				printf("In NV power mode and spindle is spun or spinning up\n");
			ret = PM_STATUS_UNKNOWN;
			break;
		case 0x40:
			if(verbose)
				printf("In NV power mode and spindle is spun or spinning down\n");
			ret = PM_STATUS_UNKNOWN;
			break;
		case 0x0:
			if(verbose)
				printf("In standby mode\n");
			ret = PM_STATUS_STANDBY;
			break;
		default:
			printf("unknown power mode (sector count) value=0x%x\n", ucp[5]);
			break;
		}
	} 
	close(sg_fd);
	return ret;    
}
int main(int argc, char * argv[])
{
    int sg_fd, k;
    uint8_t apt_cdb[SAT_ATA_PASS_THROUGH16_LEN] =
                {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0};
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    uint8_t sense_buffer[64];
    int verbose = 0;
    int extend = 0;
    int chk_cond = 1;   /* set to 1 to read register(s) back */
    int protocol = 3;   /* non-dat data-in */
    int t_dir = 1;      /* 0 -> to device, 1 -> from device */
    int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */
    int t_length = 0;   /* 0 -> no data transferred, 2 -> sector count */
    const uint8_t * bp = NULL;

    for (k = 1; k < argc; ++k) {
        if (0 == strcmp(argv[k], "-v"))
            ++verbose;
        else if (0 == strcmp(argv[k], "-vv"))
            verbose += 2;
        else if (0 == strcmp(argv[k], "-vvv"))
            verbose += 3;
        else if (0 == strcmp(argv[k], "-V")) {
            fprintf(stderr, "version: %s\n", version_str);
            exit(0);
        } else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_sat_chk_power [-v] [-V] <device>'\n");
        return 1;
    }

    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_sat_chk_power: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }

    /* Prepare ATA PASS-THROUGH COMMAND (16) command */
    apt_cdb[14] = ATA_CHECK_POWER_MODE;
    apt_cdb[1] = (protocol << 1) | extend;
    apt_cdb[2] = (chk_cond << 5) | (t_dir << 3) |
                   (byte_block << 2) | t_length;
    if (verbose) {
        fprintf(stderr, "    ata pass through(16) cdb: ");
        for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k)
            fprintf(stderr, "%02x ", apt_cdb[k]);
        fprintf(stderr, "\n");
    }

    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(apt_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_NONE;
    io_hdr.dxfer_len = 0;
    io_hdr.dxferp = NULL;
    io_hdr.cmdp = apt_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_sat_chk_power: SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* error processing: N.B. expect check condition, no sense ... !! */
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        break;
    case SG_LIB_CAT_RECOVERED:  /* sat-r09 (latest) uses this sk */
    case SG_LIB_CAT_NO_SENSE:   /* earlier SAT drafts used this */
        /* XXX: Until the spec decides which one to go with. 20060607 */
        bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
                                     SAT_ATA_RETURN_DESC);
        if (NULL == bp) {
            if (verbose > 1)
                printf("ATA Return Descriptor expected in sense but not "
                       "found\n");
            sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
        } else if (verbose)
            sg_chk_n_print3("ATA Return Descriptor, as expected",
                             &io_hdr, 1);
        if (bp && bp[3]) {
            if (bp[3] & 0x4)
                printf("error in returned FIS: aborted command\n");
            else
                printf("error=0x%x, status=0x%x\n", bp[3], bp[13]);
        }
        break;
    default:
        fprintf(stderr, "unexpected SCSI sense category\n");
        bp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer),
                                     SAT_ATA_RETURN_DESC);
        if (NULL == bp)
            sg_chk_n_print3("ATA_16 command error", &io_hdr, 1);
        else if (verbose)
            sg_chk_n_print3("ATA Return Descriptor, as expected",
                             &io_hdr, 1);
        if (bp && bp[3]) {
            if (bp[3] & 0x4)
                printf("error in returned FIS: aborted command\n");
            else
                printf("error=0x%x, status=0x%x\n", bp[3], bp[13]);
        }
        break;
    }

    if (bp) {
        switch (bp[5]) {       /* sector_count (7:0) */
        case 0xff:
            printf("In active mode or idle mode\n");
            break;
        case 0x80:
            printf("In idle mode\n");
            break;
        case 0x41:
            printf("In NV power mode and spindle is spun or spinning up\n");
            break;
        case 0x40:
            printf("In NV power mode and spindle is spun or spinning down\n");
            break;
        case 0x0:
            printf("In standby mode\n");
            break;
        default:
            printf("unknown power mode (sector count) value=0x%x\n", bp[5]);
            break;
        }
    } else
        fprintf(stderr, "Expecting a ATA Return Descriptor in sense and "
                "didn't receive it\n");

    close(sg_fd);
    return 0;
}
Exemple #9
0
static int
find_out_about_buffer(int sg_fd)
{
        uint8_t rb_cdb[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        uint8_t rbBuff[RB_DESC_LEN];
        uint8_t sense_buffer[32];
        struct sg_io_hdr io_hdr;
        int k, res;

        rb_cdb[1] = RB_MODE_DESC;
        rb_cdb[8] = RB_DESC_LEN;
        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
        io_hdr.interface_id = 'S';
        io_hdr.cmd_len = sizeof(rb_cdb);
        io_hdr.mx_sb_len = sizeof(sense_buffer);
        io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
        io_hdr.dxfer_len = RB_DESC_LEN;
        io_hdr.dxferp = rbBuff;
        io_hdr.cmdp = rb_cdb;
        io_hdr.sbp = sense_buffer;
        io_hdr.timeout = 60000;     /* 60000 millisecs == 60 seconds */

        if (verbose) {
                pr2serr("    read buffer [mode desc] cdb: ");
                for (k = 0; k < (int)sizeof(rb_cdb); ++k)
                        pr2serr("%02x ", rb_cdb[k]);
                pr2serr("\n");
        }
        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
                perror(ME "SG_IO READ BUFFER descriptor error");
                return -1;
        }
        /* now for the error processing */
        res = sg_err_category3(&io_hdr);
        switch (res) {
        case SG_LIB_CAT_RECOVERED:
                sg_chk_n_print3("READ BUFFER descriptor, continuing",
                                &io_hdr, true);
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
                __attribute__((fallthrough));
                /* FALL THROUGH */
#endif
#endif
        case SG_LIB_CAT_CLEAN:
                break;
        default: /* won't bother decoding other categories */
                sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr,
                                true);
                return res;
        }

        buf_capacity = sg_get_unaligned_be24(rbBuff + 1);
        buf_granul = (uint8_t)rbBuff[0];
#if 0
        printf("READ BUFFER reports: %02x %02x %02x %02x\n",
               rbBuff[0], rbBuff[1], rbBuff[2], rbBuff[3]);
#endif
        if (verbose)
                printf("READ BUFFER reports: buffer capacity=%d, offset "
                       "boundary=%d\n", buf_capacity, buf_granul);
        return 0;
}
Exemple #10
0
int write_buffer (int sg_fd, unsigned ssize)
{
        uint8_t wb_cdb[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        int bufSize = ssize + addwrite;
        uint8_t * free_wbBuff = NULL;
        uint8_t * wbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_wbBuff,
                                                  false);
        uint8_t sense_buffer[32];
        struct sg_io_hdr io_hdr;
        int k, res;

        if (NULL == wbBuff)
                return -1;
        memset(wbBuff, 0, bufSize);
        do_fill_buffer ((int*)wbBuff, ssize);
        wb_cdb[1] = RWB_MODE_DATA;
        sg_put_unaligned_be24((uint32_t)bufSize, wb_cdb + 6);
        memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
        io_hdr.interface_id = 'S';
        io_hdr.cmd_len = sizeof(wb_cdb);
        io_hdr.mx_sb_len = sizeof(sense_buffer);
        io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
        io_hdr.dxfer_len = bufSize;
        io_hdr.dxferp = wbBuff;
        io_hdr.cmdp = wb_cdb;
        io_hdr.sbp = sense_buffer;
        io_hdr.pack_id = 1;
        io_hdr.timeout = 60000;     /* 60000 millisecs == 60 seconds */
        if (verbose) {
                pr2serr("    write buffer [mode data] cdb: ");
                for (k = 0; k < (int)sizeof(wb_cdb); ++k)
                        pr2serr("%02x ", wb_cdb[k]);
                pr2serr("\n");
        }

        if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
                perror(ME "SG_IO WRITE BUFFER data error");
                free(wbBuff);
                return -1;
        }
        /* now for the error processing */
        res = sg_err_category3(&io_hdr);
        switch (res) {
        case SG_LIB_CAT_RECOVERED:
            sg_chk_n_print3("WRITE BUFFER data, continuing", &io_hdr, true);
#if defined(__GNUC__)
#if (__GNUC__ >= 7)
            __attribute__((fallthrough));
            /* FALL THROUGH */
#endif
#endif
        case SG_LIB_CAT_CLEAN:
                break;
        default: /* won't bother decoding other categories */
                sg_chk_n_print3("WRITE BUFFER data error", &io_hdr, true);
                free(wbBuff);
                return res;
        }
        if (free_wbBuff)
                free(free_wbBuff);
        return res;
}
int main(int argc, char * argv[])
{
    FILE *pFile;
    time_t rawtime;
    struct tm * timeinfo;
    int sg_fd, k, ok, i, j;
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char sense_buffer[32];
    unsigned char FourBytes[4];
    unsigned char Viking[] = "VT";
    unsigned char filename[22];

    unsigned char r10CmdBlk[7][READ10_CMD_LEN] =
             { {0xF0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
               {0xF0, 0x0A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0},
               {0x28, 0x00, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
               {0xF0, 0xAA, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 1, 0, 0, 0, 0},
               {0xF0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
               {0xF1, 0x03, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 1, 0, 0, 0, 0},
               {0xF0, 0x2C, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
    unsigned char inBuff[READ10_REPLY_LEN], saveBuff[READ10_REPLY_LEN];
    unsigned int Total_MU=0, Total_LBA=0, LBA_per_MU=0, HalfLBA_per_MU=0, LED_result=0;
    
    unsigned char inqCmdBlk [2][INQ_CMD_LEN] =
             { {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}, {0x12, 0, 0x80, 0, INQ_REPLY_LEN, 0} };
    unsigned char inqBuff[INQ_REPLY_LEN];
    unsigned char VendorID[8], ProductID[16], ProductRevision[4], UnitSerialNumber[18], UnitProductNumber[18];

    unsigned char capCmdBlk [READCAP_CMD_LEN] =
              {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    unsigned char capBuff[READCAP_REPLY_LEN];
    unsigned int  BlockSize=0, DiskSize=0;
    unsigned char LED_Status_Byte=0, LED_Ready=0, LED_Busy=0;
    
    time( &rawtime );
    timeinfo = localtime( &rawtime );
    
    for (k = 1; k < argc; ++k) {
        if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_read_SM3252_LED <sg_device>'\n");
        return 1;
    }

    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_read_SM325: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    /* Just to be safe, check we have a new sg device by trying an ioctl */
    if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
        printf("sg_read_SM325: %s doesn't seem to be a new sg device\n",
               file_name);
        close(sg_fd);
        return 1;
    }

    /* 1. Prepare INQUIRY command for Vendor ID, Product ID, Product Revision */
    /**************************************************************************/
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(inqCmdBlk[inq_basic_info]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = INQ_REPLY_LEN;
    io_hdr.dxferp = inqBuff;
    io_hdr.cmdp = inqCmdBlk[inq_basic_info];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple1: Inquiry SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on INQUIRY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("INQUIRY command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        char * p = (char *)inqBuff;
        int f = (int)*(p + 7);
#ifdef DEBUG_FLAG
	    printf(" inquiry buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
   		memcpy( inqBuff, io_hdr.dxferp, sizeof(inqBuff));
	    for (i=0; i<16; i++)  /* 16 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	         printf("%02X ", inqBuff[(i*32)+j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif
   		memcpy( VendorID, p + 8, sizeof(VendorID));
   		memcpy( ProductID, p + 16, sizeof(ProductID));
   		memcpy( ProductRevision, p + 32, sizeof(ProductRevision));
    }

    /* 2. Prepare INQUIRY command for Unit Serial Number */
    /*****************************************************/
    io_hdr.cmd_len = sizeof(inqCmdBlk[inq_unit_serial_number]);
    io_hdr.cmdp = inqCmdBlk[inq_unit_serial_number];

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple1: Inquiry SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on INQUIRY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("INQUIRY command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        char * p = (char *)inqBuff;
        int f = (int)*(p + 7);
#ifdef DEBUG_FLAG
        printf("Unit Serial Number: %.16s \n", p + 4);
	    printf(" inquiry buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
   		memcpy( inqBuff, io_hdr.dxferp, sizeof(inqBuff));
	    for (i=0; i<16; i++)  /* 16 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	         printf("%02X ", inqBuff[(i*32)+j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif
   		memcpy( UnitSerialNumber, p + 4, sizeof(UnitSerialNumber));
    }

    /* 3. Prepare READ CAPACITY command for Block Size and Disk Size */
    /*****************************************************************/
    io_hdr.cmd_len = sizeof(capCmdBlk);
    io_hdr.dxfer_len = READCAP_REPLY_LEN;
    io_hdr.dxferp = capBuff;
    io_hdr.cmdp = capCmdBlk;

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple1: READ CAPACITY SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on READ CAPACITY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("READ CAPACITY command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
#ifdef DEBUG_FLAG
	    printf(" readcap buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
   		memcpy( capBuff, io_hdr.dxferp, sizeof(capBuff));
        printf("                 ");
        for (j=0; j<8; j++)
	        printf("%02X ", capBuff[j]);
	    printf("\n");
#endif
        FourBytes[0] = capBuff[7];
        FourBytes[1] = capBuff[6];
        FourBytes[2] = capBuff[5];
        FourBytes[3] = capBuff[4];
        BlockSize  = *(int *)FourBytes;
        FourBytes[0] = capBuff[3];
        FourBytes[1] = capBuff[2];
        FourBytes[2] = capBuff[1];
        FourBytes[3] = capBuff[0];
        DiskSize  = ((*(int *)FourBytes) + 1) * BlockSize;
    }

    /* 1. Prepare READ_10 command for reading basic information */
    /************************************************************/
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r10CmdBlk[basic_info]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = READ10_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r10CmdBlk[basic_info];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
	   perror("sg_read_SM325: Inquiry SG_IO ioctl error");
	   close(sg_fd);
	   return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
       case SG_LIB_CAT_CLEAN:
	      ok = 1;
	      break;
       case SG_LIB_CAT_RECOVERED:
	      printf("Recovered error on READ_10, continuing\n");
	      ok = 1;
	      break;
       default: /* won't bother decoding other categories */
	      sg_chk_n_print3("READ_10 command error", &io_hdr, 1);
	      break;
    }

    if (ok) { /* output result if it is available */
	    memcpy( sense_buffer, io_hdr.sbp, sizeof(sense_buffer));

#ifdef DEBUG_FLAG
	    printf("\n  STEP 1: READ BASIC INFORMATION\n");
	    /* Print out io_hdr.deferp */
	    printf("   reply buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
	    memcpy( inBuff, io_hdr.dxferp, sizeof(inBuff));
	    for (i=0; i<8; i++)  /* 8 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	         printf("%02X ", inBuff[(i*32+)j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif
        Total_MU   = inBuff[1];
        FourBytes[0] = inBuff[0x17];
        FourBytes[1] = inBuff[0x16];
        FourBytes[2] = inBuff[0x15];
        FourBytes[3] = inBuff[0x14];
        Total_LBA  = *(int *)FourBytes;
        LBA_per_MU = Total_LBA / Total_MU;
        HalfLBA_per_MU = LBA_per_MU / 2;

#ifdef DEBUG_FLAG
        printf("Total MU       = %d\n", Total_MU);
        printf("Total LBA      = %d (0x%X)\n", Total_LBA, Total_LBA);
        printf("LBA per MU     = %d\n", LBA_per_MU);
        printf("HalfLBA per MU = %d\n\n", HalfLBA_per_MU);
        printf("Done\n");
#endif
    }

    /* 2. Prepare READ_10 command for reading LED setting information */
    /************************************************************/
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r10CmdBlk[read_LED]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = READ10_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r10CmdBlk[read_LED];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
	   perror("sg_read_SM325: Inquiry SG_IO ioctl error");
	   close(sg_fd);
	   return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
       case SG_LIB_CAT_CLEAN:
	      ok = 1;
	      break;
       case SG_LIB_CAT_RECOVERED:
	      printf("Recovered error on READ_10, continuing\n");
	      ok = 1;
	      break;
       default: /* won't bother decoding other categories */
	      sg_chk_n_print3("READ_10 command error", &io_hdr, 1);
	      break;
    }

    if (ok) { /* output result if it is available */
	    memcpy( sense_buffer, io_hdr.sbp, sizeof(sense_buffer));
	    memcpy( inBuff, io_hdr.dxferp, sizeof(inBuff));

	    /* Save a back up buffer to compare it later to saveBuff */
	    memcpy( saveBuff, io_hdr.dxferp, sizeof(saveBuff));

#ifdef DEBUG_FLAG1
	    printf("\n  STEP 2: READ LED SETTING INFORMATION\n");
	    /* Print out io_hdr.deferp */
	    printf("   reply buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
	    for (i=0; i<32; i++)  /* 32 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+15);

	      for (j=0; j<16; j++)
	         printf("%02X ", inBuff[(i*16)+j]);
	   
	      printf("\n");
	      printf("Char   %3d-%3d = ", i*j, (i*j)+15);

	      for (j=0; j<16; j++)
	         printf("%2c ", inBuff[(i*16)+j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif
        for (i=0; i<18; i++)
        {
	        UnitProductNumber[i] = inBuff[86+(i*2)];
        }
        
        strcpy(filename, UnitProductNumber);
        strcat(filename, ".txt");
        
        pFile=fopen(filename, "a");
        if(pFile==NULL)
        {
            printf("Error opening log file.\n");
        }
    
        if (strncmp(Viking, VendorID, 2) != 0)
        {
            printf("NO RECONFIG - Not a Viking drive.\n");
            fprintf(pFile, "%s, %s, %s, %s", UnitProductNumber, UnitSerialNumber, VendorID, asctime(timeinfo));
            fclose(pFile);
            return 0;
        }
        
        LED_Status_Byte = inBuff[0x187];
        LED_Ready       = (LED_Status_Byte & 0x06) >> 1;
        LED_Busy        = (LED_Status_Byte & 0x60) >> 5;

#ifdef DEBUG_FLAG
        printf("LED_Status_Byte = 0x%X\n", LED_Status_Byte);
        printf("LED_Ready       = %d\n", LED_Ready);
        printf("LED_Busy        = %d\n", LED_Busy);
        printf("Done\n");
#endif
    }

    /* 3. Prepare READ_10 command for writing LED setting information */
    /************************************************************/
#ifdef DEBUG_FLAG
	printf("\n  STEP 3: WRITE LED SETTING INFORMATION\n");
#endif
    if (inBuff[0x187] == 0x82)
    {
        LED_result = 0;
        printf("Already configured ");
    }
    else if (inBuff[0x187] == 0x80)
    {
        inBuff[0x187] = 0x82;
#ifdef DEBUG_FLAG
        printf("Updating the CID table...\n");
#endif
    }
    
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r10CmdBlk[write_LED]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
    io_hdr.dxfer_len = READ10_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r10CmdBlk[write_LED];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
	   perror("sg_read_SM325: Inquiry SG_IO ioctl error");
	   close(sg_fd);
	   return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
       case SG_LIB_CAT_CLEAN:
	      ok = 1;
	      break;
       case SG_LIB_CAT_RECOVERED:
	      printf("Recovered error on READ_10, continuing\n");
	      ok = 1;
	      break;
       default: /* won't bother decoding other categories */
	      sg_chk_n_print3("READ_10 command error", &io_hdr, 1);
	      break;
    }

    if (ok) { /* output result if it is available */
	    memcpy( sense_buffer, io_hdr.sbp, sizeof(sense_buffer));

#ifdef DEBUG_FLAG1
	    /* Print out io_hdr.deferp */
	    printf("   reply buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
	    memcpy( inBuff, io_hdr.dxferp, sizeof(inBuff));
	    for (i=0; i<16; i++)  /* 16 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	      {
	         printf("%02X ", inBuff[(i*32)+j]);
	         
	         if (inBuff[(i*32)+j] != saveBuff[(i*32)+j])
	         {
   	            printf("<* ");
	         }
	      }
	   
	      printf("\n");
	    }
        printf("\n");
#endif
        LED_Status_Byte = inBuff[0x187];
        LED_Ready       = (LED_Status_Byte & 0x06) >> 1;
        LED_Busy        = (LED_Status_Byte & 0x60) >> 5;

#ifdef DEBUG_FLAG
        printf("LED_Status_Byte = 0x%X\n", LED_Status_Byte);
        printf("LED_Ready       = %d\n", LED_Ready);
        printf("LED_Busy        = %d\n", LED_Busy);
        printf("Done\n");
#endif
    }

    /* 4. Prepare READ_10 command for reading LED setting information */
    /************************************************************/
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r10CmdBlk[read_LED]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = READ10_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r10CmdBlk[read_LED];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
	   perror("sg_read_SM325: Inquiry SG_IO ioctl error");
	   close(sg_fd);
	   return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
       case SG_LIB_CAT_CLEAN:
	      ok = 1;
	      break;
       case SG_LIB_CAT_RECOVERED:
	      printf("Recovered error on READ_10, continuing\n");
	      ok = 1;
	      break;
       default: /* won't bother decoding other categories */
	      sg_chk_n_print3("READ_10 command error", &io_hdr, 1);
	      break;
    }

    if (ok) { /* output result if it is available */
	    memcpy( sense_buffer, io_hdr.sbp, sizeof(sense_buffer));

#ifdef DEBUG_FLAG
	    printf("\n  STEP 4: READ LED SETTING INFORMATION AFTER A WRITE\n");
	    /* Print out io_hdr.deferp */
	    printf("   reply buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
	    memcpy( inBuff, io_hdr.dxferp, sizeof(inBuff));
	    for (i=0; i<16; i++)  /* 16 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	         printf("%02X ", inBuff[(i*32)+j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif

        /* Compare the back up buffer against the newly read buffer to ensure no changes */
        for (i=0; i<sizeof(inBuff); i++)
        {
            if (inBuff[i] != saveBuff[i])
            {
                if (i == 0x187) /* LED Byte */
                {
                    continue;
                }
                else
                {
                    LED_result = 2;
                    printf("FAILED - Buffer comparison failed.\n");
                    fprintf(pFile, "%s, %s, FAILED Buffer Comparison, %s", UnitProductNumber, UnitSerialNumber, asctime(timeinfo));
                }
            }
        }
        
        LED_Status_Byte = inBuff[0x187];
        LED_Ready       = (LED_Status_Byte & 0x06) >> 1;
        LED_Busy        = (LED_Status_Byte & 0x60) >> 5;

        if (inBuff[0x187] == 0x82)
        {
            LED_result = 1;
            printf("PASSED.\n");
            fprintf(pFile, "%s, %s, PASSED, %s", UnitProductNumber, UnitSerialNumber, asctime(timeinfo));
        }
        else 
        {
            LED_result = 2;
            printf("FAILED - Re-test or reject.\n");
            fprintf(pFile, "%s, %s, FAILED, %s", UnitProductNumber, UnitSerialNumber, asctime(timeinfo));
        }
    }
    
    /* 5. Prepare READ_10 command for reset the drive */
    /************************************************************/
#ifdef DEBUG_FLAG
	printf("\n  STEP 5: RESET THE USB DRIVE...\n");
#endif
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r10CmdBlk[reset_drive]);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
    io_hdr.dxfer_len = READ10_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r10CmdBlk[reset_drive];
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
	   perror("sg_read_SM325: Inquiry SG_IO ioctl error");
	   close(sg_fd);
	   return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
       case SG_LIB_CAT_CLEAN:
	      ok = 1;
	      break;
       case SG_LIB_CAT_RECOVERED:
	      printf("Recovered error on READ_10, continuing\n");
	      ok = 1;
	      break;
       default: /* won't bother decoding other categories */
	      break;
    }

    if (ok) { /* output result if it is available */
	    memcpy( sense_buffer, io_hdr.sbp, sizeof(sense_buffer));

#ifdef DEBUG_FLAG
	    /* Print out io_hdr.deferp */
	    printf("   reply buffer  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F\n");
	    printf("                 -----------------------------------------------------------------------------------------------\n");
	    memcpy( inBuff, io_hdr.dxferp, sizeof(inBuff));
	    for (i=0; i<16; i++)  /* 16 rows */
	    {
	      printf("       %3d-%3d = ", i*j, (i*j)+31);

	      for (j=0; j<32; j++)
	         printf("%02X ", inBuff[(i*32)+j]);
	   
	      printf("\n");
	    }
        printf("\n");
#endif
    }

    /*    Print out the results   */
    /******************************/
#ifdef DEBUG_FLAG
    printf("\n   *********** THE RESULT IS: **********\n\n");

    printf("Vendor Identification  : %.8s\n", VendorID);
    printf("Product Identification : %.16s\n", ProductID);
    printf("Product Revision Level : %.4s\n", ProductRevision);
    printf("Unit Serial Number     : %.16s\n", UnitSerialNumber);
    printf("Block Size : %d Bytes\n", BlockSize);
    printf("Disk Size  : %.2f MiB or %.2f MB\n\n", (float)(DiskSize / BYTES_IN_MiB), (float)(DiskSize / BYTES_IN_MB));

    switch (LED_result)
    {
       case 0:
          printf("The drive has already been updated.\n");
          break;
       case 1:
          printf("PASSED.\n");
          break;
       case 2:
          printf("FAILED.  Re-test the drive or send to RMA.\n");
          break;
       default:   
          break;
    }
#endif
    
    fclose(pFile);
    close(sg_fd);
    return 0;
}
Exemple #12
0
/* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */
static int
sg_finish_io(int wr, Rq_elem * rep)
{
    int res;
    sg_io_hdr_t io_hdr;
    sg_io_hdr_t * hp;
#if 0
    static int testing = 0;     /* thread dubious! */
#endif

    memset(&io_hdr, 0 , sizeof(sg_io_hdr_t));
    /* FORCE_PACK_ID active set only read packet with matching pack_id */
    io_hdr.interface_id = 'S';
    io_hdr.dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
    io_hdr.pack_id = rep->blk;

    while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr,
                        sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno))
        ;
    if (res < 0) {
        perror("finishing io on sg device, error");
        return -1;
    }
    if (rep != (Rq_elem *)io_hdr.usr_ptr) {
        fprintf(stderr,
                "sg_finish_io: bad usr_ptr, request-response mismatch\n");
        exit(1);
    }
    memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t));
    hp = &rep->io_hdr;

    switch (sg_err_category3(hp)) {
        case SG_LIB_CAT_CLEAN:
            break;
        case SG_LIB_CAT_RECOVERED:
            fprintf(stderr, "Recovered error on block=%d, num=%d\n",
                    rep->blk, rep->num_blks);
            break;
        case SG_LIB_CAT_UNIT_ATTENTION:
            return 1;
        default:
            {
                char ebuff[EBUFF_SZ];
                snprintf(ebuff, EBUFF_SZ, "%s blk=%d",
                         rep->wr ? "writing": "reading", rep->blk);
                sg_chk_n_print3(ebuff, hp, 1);
                return -1;
            }
    }
#if 0
    if (0 == (++testing % 100)) return -1;
#endif
    if (rep->dio &&
        ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
        rep->dio_incomplete = 1; /* count dios done as indirect IO */
    else
        rep->dio_incomplete = 0;
    rep->resid = hp->resid;
    if (rep->debug > 8)
        fprintf(stderr, "sg_finish_io: completed %s, blk=%d\n",
                wr ? "WRITE" : "READ", rep->blk);
    return 0;
}
Exemple #13
0
int
main(int argc, char * argv[])
{
    bool done;
    int sg_fd, k, ok, ver_num, pack_id, num_waiting, access_count;
    int sg_fd2 = -1;
    int sock = -1;
    uint8_t inq_cdb[INQ_CMD_LEN] =
                                {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
                                {0x1d, 0, 0, 0, 0, 0};
    uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
    sg_io_hdr_t io_hdr[MAX_Q_LEN];
    sg_io_hdr_t rio_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
    const char * second_fname = NULL;
    const char * cp;
    struct sg_scsi_id ssi;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-f", argv[k], 2))
            do_fork = true;
        else if (0 == memcmp("-h", argv[k], 2)) {
            file_name = 0;
            break;
        } else if (0 == memcmp("-l=", argv[k], 3)) {
            q_len = atoi(argv[k] + 3);
            if ((q_len > 511) || (q_len < 1)) {
                printf("Expect -l= to take a number (q length) between 1 "
                       "and 511\n");
                file_name = 0;
                break;
            }
        } else if (0 == memcmp("-o", argv[k], 2))
            ioctl_only = true;
        else if (0 == memcmp("-r=", argv[k], 3)) {
            reserve_buff_sz = atoi(argv[k] + 3);
            if (reserve_buff_sz < 0) {
                printf("Expect -r= to take a number 0 or higher\n");
                file_name = 0;
                break;
            }
        } else if (0 == memcmp("-s=", argv[k], 3)) {
            sleep_secs = atoi(argv[k] + 3);
            if (sleep_secs < 0) {
                printf("Expect -s= to take a number 0 or higher\n");
                file_name = 0;
                break;
            }
        } else if (0 == memcmp("-t", argv[k], 2))
            q_at_tail = true;
        else if (0 == memcmp("-vvvv", argv[k], 5))
            verbose += 4;
        else if (0 == memcmp("-vvv", argv[k], 4))
            verbose += 3;
        else if (0 == memcmp("-vv", argv[k], 3))
            verbose += 2;
        else if (0 == memcmp("-v", argv[k], 2))
            verbose += 1;
        else if (0 == memcmp("-V", argv[k], 2)) {
            printf("%s\n", version_str);
            file_name = 0;
            break;
        } else if (0 == memcmp("-w", argv[k], 2))
            write_only = true;
        else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else if (NULL == second_fname)
            second_fname = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("No filename (sg device) given\n\n");
        usage();
        return 1;
    }

    /* An access mode of O_RDWR is required for write()/read() interface */
    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    if (verbose)
        fprintf(stderr, "opened given file: %s successfully, fd=%d\n",
                file_name, sg_fd);

    if (ioctl(sg_fd, SG_GET_VERSION_NUM, &ver_num) < 0) {
        pr2serr("ioctl(SG_GET_VERSION_NUM) failed, errno=%d %s\n", errno,
                strerror(errno));
        goto out;
    }
    printf("Linux sg driver version: %d\n", ver_num);

    if (second_fname) {
        if ((sg_fd2 = open(second_fname, O_RDWR)) < 0) {
            snprintf(ebuff, EBUFF_SZ,
                     "%s: error opening file: %s", __func__, second_fname);
            perror(ebuff);
            return 1;
        }
        if (verbose)
            fprintf(stderr, "opened second file: %s successfully, fd=%d\n",
                    second_fname, sg_fd2);
    }

    if (do_fork) {
        int pid;
        int sv[2];

        if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) < 0) {
            perror("socketpair");
            exit(1);
        }
        printf("socketpair: sv[0]=%d, sv[1]=%d sg_fd=%d\n", sv[0], sv[1],
               sg_fd);
        pid = fork();
        if (pid < 0) {
            perror("fork() failed");
            goto out;
        } else if (0 == pid) {
            relative_cp = "child ";
            is_parent = false;
            close(sv[0]);
            sock = sv[1];
        } else {
            relative_cp = "parent ";
            is_parent = true;
            childs_pid = pid;
            close(sv[1]);
            sock = sv[0];
        }
    }

    cp = do_fork ? relative_cp : "";
    if (tst_ioctl(file_name, sg_fd, second_fname, sg_fd2, sock, cp))
        goto out;
    if (ioctl_only)
        goto out;

    if (do_fork && !is_parent)
        return 0;

    printf("start write() calls\n");
    for (k = 0; k < q_len; ++k) {
        /* Prepare INQUIRY command */
        memset(&io_hdr[k], 0, sizeof(sg_io_hdr_t));
        io_hdr[k].interface_id = 'S';
        /* io_hdr[k].iovec_count = 0; */  /* memset takes care of this */
        io_hdr[k].mx_sb_len = (uint8_t)sizeof(sense_buffer);
        if (0 == (k % 3)) {
            io_hdr[k].cmd_len = sizeof(sdiag_cdb);
            io_hdr[k].cmdp = sdiag_cdb;
            io_hdr[k].dxfer_direction = SG_DXFER_NONE;
        } else {
            io_hdr[k].cmd_len = sizeof(inq_cdb);
            io_hdr[k].cmdp = inq_cdb;
            io_hdr[k].dxfer_direction = SG_DXFER_FROM_DEV;
            io_hdr[k].dxfer_len = INQ_REPLY_LEN;
            io_hdr[k].dxferp = inqBuff[k];
        }
        io_hdr[k].sbp = sense_buffer[k];
        io_hdr[k].mx_sb_len = SENSE_BUFFER_LEN;
        io_hdr[k].timeout = 20000;     /* 20000 millisecs == 20 seconds */
        io_hdr[k].pack_id = k + 3;      /* so pack_id doesn't start at 0 */
        /* default is to queue at head (in SCSI mid level) */
        if (q_at_tail)
            io_hdr[k].flags |= SG_FLAG_Q_AT_TAIL;
        else
            io_hdr[k].flags |= SG_FLAG_Q_AT_HEAD;
        /* io_hdr[k].usr_ptr = NULL; */

        if (write(sg_fd, &io_hdr[k], sizeof(sg_io_hdr_t)) < 0) {
            pr2serr("%ssg write errno=%d [%s]\n", cp, errno, strerror(errno));
            close(sg_fd);
            return 1;
        }
    }

    memset(&ssi, 0, sizeof(ssi));
    if (ioctl(sg_fd, SG_GET_SCSI_ID, &ssi) < 0)
        pr2serr("ioctl(SG_GET_SCSI_ID) failed, errno=%d %s\n",
                errno, strerror(errno));
    else {
        printf("host_no: %d\n", ssi.host_no);
        printf("  channel: %d\n", ssi.channel);
        printf("  scsi_id: %d\n", ssi.scsi_id);
        printf("  lun: %d\n", ssi.lun);
        printf("  pdt: %d\n", ssi.scsi_type);
        printf("  h_cmd_per_lun: %d\n", ssi.h_cmd_per_lun);
        printf("  d_queue_depth: %d\n", ssi.d_queue_depth);
    }
    if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
        pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
                errno, strerror(errno));
    else
        printf("first available pack_id: %d\n", pack_id);
    if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
        pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
                errno, strerror(errno));
    else
        printf("num_waiting: %d\n", num_waiting);

    sleep(sleep_secs);

    if (write_only)
        goto out;

    if (do_fork)
        printf("\n\nFollowing starting with get_pack_id are all CHILD\n");
    if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
        pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
                errno, strerror(errno));
    else
        printf("first available pack_id: %d\n", pack_id);
    if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
        pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
                errno, strerror(errno));
    else
        printf("num_waiting: %d\n", num_waiting);

    printf("\nstart read() calls\n");
    for (k = 0, done = false; k < q_len; ++k) {
        if ((! done) && (k == q_len / 2)) {
            done = true;
            printf("\n>>> half way through read\n");
            if (ioctl(sg_fd, SG_GET_PACK_ID, &pack_id) < 0)
                pr2serr("ioctl(SG_GET_PACK_ID) failed, errno=%d %s\n",
                        errno, strerror(errno));
            else
                printf("first available pack_id: %d\n", pack_id);
            if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting) < 0)
                pr2serr("ioctl(SG_GET_NUM_WAITING) failed, errno=%d %s\n",
                        errno, strerror(errno));
            else
                printf("num_waiting: %d\n", num_waiting);
            if (ioctl(sg_fd, SG_GET_ACCESS_COUNT, &access_count) < 0)
                pr2serr("ioctl(SG_GET_ACCESS_COUNT) failed, errno=%d %s\n",
                        errno, strerror(errno));
            else
                printf("access_count: %d\n", access_count);
        }
        memset(&rio_hdr, 0, sizeof(sg_io_hdr_t));
        rio_hdr.interface_id = 'S';
        if (read(sg_fd, &rio_hdr, sizeof(sg_io_hdr_t)) < 0) {
            perror("sg read error");
            close(sg_fd);
            return 1;
        }
        /* now for the error processing */
        ok = 0;
        switch (sg_err_category3(&rio_hdr)) {
        case SG_LIB_CAT_CLEAN:
            ok = 1;
            break;
        case SG_LIB_CAT_RECOVERED:
            printf("Recovered error, continuing\n");
            ok = 1;
            break;
        default: /* won't bother decoding other categories */
            sg_chk_n_print3("command error", &rio_hdr, 1);
            break;
        }

        if (ok) { /* output result if it is available */
            if (0 == (rio_hdr.pack_id % 3))
                printf("SEND DIAGNOSTIC %d duration=%u\n", rio_hdr.pack_id,
                       rio_hdr.duration);
            else
                printf("INQUIRY %d duration=%u\n", rio_hdr.pack_id,
                       rio_hdr.duration);
        }
    }

out:
    close(sg_fd);
    if (sg_fd2 >= 0)
        close(sg_fd2);
    return 0;
}
Exemple #14
0
int main(int argc, char * argv[])
{
    int sg_fd, k, ok;
    unsigned char r16_cdb [READ16_CMD_LEN] =
                {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0};
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char inBuff[READ16_REPLY_LEN];
    unsigned char sense_buffer[32];

    for (k = 1; k < argc; ++k) {
        if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_simple16 <sg_device>'\n");
        return 1;
    }

    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_simple16: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    /* Just to be safe, check we have a new sg device by trying an ioctl */
    if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
        printf("sg_simple16: %s doesn't seem to be an new sg device\n",
               file_name);
        close(sg_fd);
        return 1;
    }

    /* Prepare READ_16 command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(r16_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = READ16_REPLY_LEN;
    io_hdr.dxferp = inBuff;
    io_hdr.cmdp = r16_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    /* io_hdr.flags = 0; */     /* take defaults: indirect IO, etc */
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple16: Inquiry SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on READ_16, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("READ_16 command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        printf("READ_16 duration=%u millisecs, resid=%d, msg_status=%d\n",
               io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
    }

    close(sg_fd);
    return 0;
}
Exemple #15
0
int main(int argc, char * argv[])
{
    int sg_fd, k, ok;
    unsigned char inq_cdb[INQ_CMD_LEN] =
                                {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    unsigned char tur_cdb[TUR_CMD_LEN] =
                                {0x00, 0, 0, 0, 0, 0};
    unsigned char * inqBuff;
    unsigned char * inqBuff2;
    sg_io_hdr_t io_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    unsigned char sense_buffer[32];
    int do_extra = 0;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-x", argv[k], 2))
            do_extra = 1;
        else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_simple4 [-x] <sg_device>'\n");
        return 1;
    }

    /* N.B. An access mode of O_RDWR is required for some SCSI commands */
    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_simple4: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    /* Just to be safe, check we have a new sg device by trying an ioctl */
    if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30122)) {
        printf("sg_simple4: %s needs sg driver version >= 3.1.22\n",
               file_name);
        close(sg_fd);
        return 1;
    }

    /* since I know this program will only read from inqBuff then I use
       PROT_READ rather than PROT_READ | PROT_WRITE */
    inqBuff = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE,
                                    MAP_SHARED, sg_fd, 0);
    if (MAP_FAILED == inqBuff) {
        snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() on "
                 "file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    if (inqBuff[0])
        printf("non-null char at inqBuff[0]\n");
    if (inqBuff[5000])
        printf("non-null char at inqBuff[5000]\n");

    /* Prepare INQUIRY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(inq_cdb);
    /* io_hdr.iovec_count = 0; */  /* memset takes care of this */
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len = INQ_REPLY_LEN;
    /* io_hdr.dxferp = inqBuff; // ignored in mmap-ed IO */
    io_hdr.cmdp = inq_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */
    io_hdr.flags = SG_FLAG_MMAP_IO;
    /* io_hdr.pack_id = 0; */
    /* io_hdr.usr_ptr = NULL; */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple4: Inquiry SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on INQUIRY, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("INQUIRY command error", &io_hdr, 1);
        break;
    }

    if (ok) { /* output result if it is available */
        char * p = (char *)inqBuff;
        int f = (int)*(p + 7);
        printf("Some of the INQUIRY command's results:\n");
        printf("    %.8s  %.16s  %.4s  ", p + 8, p + 16, p + 32);
        printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n",
               !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1));
        /* Extra info, not necessary to look at */
        if (do_extra)
            printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n",
                   io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
    }


    /* Prepare TEST UNIT READY command */
    memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
    io_hdr.interface_id = 'S';
    io_hdr.cmd_len = sizeof(tur_cdb);
    io_hdr.mx_sb_len = sizeof(sense_buffer);
    io_hdr.dxfer_direction = SG_DXFER_NONE;
    io_hdr.cmdp = tur_cdb;
    io_hdr.sbp = sense_buffer;
    io_hdr.timeout = 20000;     /* 20000 millisecs == 20 seconds */

    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
        perror("sg_simple4: Test Unit Ready SG_IO ioctl error");
        close(sg_fd);
        return 1;
    }

    /* now for the error processing */
    ok = 0;
    switch (sg_err_category3(&io_hdr)) {
    case SG_LIB_CAT_CLEAN:
        ok = 1;
        break;
    case SG_LIB_CAT_RECOVERED:
        printf("Recovered error on Test Unit Ready, continuing\n");
        ok = 1;
        break;
    default: /* won't bother decoding other categories */
        sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1);
        break;
    }

    if (ok)
        printf("Test Unit Ready successful so unit is ready!\n");
    else
        printf("Test Unit Ready failed so unit may _not_ be ready!\n");

    if (do_extra)
        printf("TEST UNIT READY duration=%u millisecs, resid=%d, "
               "msg_status=%d\n",
               io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);

    /* munmap(inqBuff, 8000); */
    /* could call munmap(inqBuff, INQ_REPLY_LEN) here but following close()
       causes this too happen anyway */
#if 1
    inqBuff2 = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE,
                                     MAP_SHARED, sg_fd, 0);
    if (MAP_FAILED == inqBuff2) {
        snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() 2 on "
                 "file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    if (inqBuff2[0])
        printf("non-null char at inqBuff2[0]\n");
    if (inqBuff2[5000])
        printf("non-null char at inqBuff2[5000]\n");
    {
        pid_t pid;
        pid = fork();
        if (pid) {
            inqBuff2[5000] = 33;
            munmap(inqBuff, 8000);
            sleep(3);
        }
        else {
            inqBuff[5000] = 0xaa;
            munmap(inqBuff, 8000);
            sleep(1);
        }
    }
#endif
    close(sg_fd);
    return 0;
}
Exemple #16
0
int main(int argc, char * argv[])
{
    bool q_at_tail = false;
    bool dur_in_nanosecs = false;
    int sg_fd, k, ok;
    uint8_t inq_cdb[INQ_CMD_LEN] =
                                {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
    uint8_t sdiag_cdb[SDIAG_CMD_LEN] =
                                {0x1d, 0x10 /* PF */, 0, 0, 0, 0};
    uint8_t inqBuff[MAX_Q_LEN][INQ_REPLY_LEN];
    sg_io_hdr_t io_hdr[MAX_Q_LEN];
    sg_io_hdr_t rio_hdr;
    char * file_name = 0;
    char ebuff[EBUFF_SZ];
    uint8_t sense_buffer[MAX_Q_LEN][SENSE_BUFFER_LEN];
    int q_len = DEF_Q_LEN;

    for (k = 1; k < argc; ++k) {
        if (0 == memcmp("-n", argv[k], 2))
            dur_in_nanosecs = true;
        else if (0 == memcmp("-t", argv[k], 2))
            q_at_tail = true;
        else if (0 == memcmp("-l=", argv[k], 3)) {
            q_len = atoi(argv[k] + 3);
            if ((q_len > 511) || (q_len < 1)) {
                printf("Expect -l= to take a number (q length) between 1 "
                       "and 511\n");
                file_name = 0;
                break;
            }

        } else if (*argv[k] == '-') {
            printf("Unrecognized switch: %s\n", argv[k]);
            file_name = 0;
            break;
        }
        else if (0 == file_name)
            file_name = argv[k];
        else {
            printf("too many arguments\n");
            file_name = 0;
            break;
        }
    }
    if (0 == file_name) {
        printf("Usage: 'sg_queue_tst [-l=Q_LEN] [-n] [-t] <sg_device>'\n"
               "where:\n"
               "      -l=Q_LEN    queue length, between 1 and 511 "
               "(def: 16)\n"
               "      -n    duration in nanosecs (def: milliseconds)\n"
               "      -t    queue_at_tail (def: q_at_head)\n");
        return 1;
    }

    /* An access mode of O_RDWR is required for write()/read() interface */
    if ((sg_fd = open(file_name, O_RDWR)) < 0) {
        snprintf(ebuff, EBUFF_SZ,
                 "sg_queue_tst: error opening file: %s", file_name);
        perror(ebuff);
        return 1;
    }
    if (dur_in_nanosecs)
        set_nanosecs(sg_fd);

    for (k = 0; k < q_len; ++k) {
        /* Prepare INQUIRY command */
        memset(&io_hdr[k], 0, sizeof(sg_io_hdr_t));
        io_hdr[k].interface_id = 'S';
        /* io_hdr[k].iovec_count = 0; */  /* memset takes care of this */
        io_hdr[k].mx_sb_len = (uint8_t)sizeof(sense_buffer);
        if (0 == (k % 3)) {
            io_hdr[k].cmd_len = sizeof(sdiag_cdb);
            io_hdr[k].cmdp = sdiag_cdb;
            io_hdr[k].dxfer_direction = SG_DXFER_NONE;
        } else {
            io_hdr[k].cmd_len = sizeof(inq_cdb);
            io_hdr[k].cmdp = inq_cdb;
            io_hdr[k].dxfer_direction = SG_DXFER_FROM_DEV;
            io_hdr[k].dxfer_len = INQ_REPLY_LEN;
            io_hdr[k].dxferp = inqBuff[k];
        }
        io_hdr[k].sbp = sense_buffer[k];
        io_hdr[k].mx_sb_len = SENSE_BUFFER_LEN;
        io_hdr[k].timeout = 20000;     /* 20000 millisecs == 20 seconds */
        io_hdr[k].pack_id = k;
        /* default is to queue at head (in SCSI mid level) */
        if (q_at_tail)
            io_hdr[k].flags |= SG_FLAG_Q_AT_TAIL;
        else
            io_hdr[k].flags |= SG_FLAG_Q_AT_HEAD;
        /* io_hdr[k].usr_ptr = NULL; */

        if (write(sg_fd, &io_hdr[k], sizeof(sg_io_hdr_t)) < 0) {
            perror("sg_queue_tst: sg write error");
            close(sg_fd);
            return 1;
        }
    }
    /* sleep(3); */
    for (k = 0; k < q_len; ++k) {
        memset(&rio_hdr, 0, sizeof(sg_io_hdr_t));
        rio_hdr.interface_id = 'S';
        if (read(sg_fd, &rio_hdr, sizeof(sg_io_hdr_t)) < 0) {
            perror("sg_queue_tst: sg read error");
            close(sg_fd);
            return 1;
        }
        /* now for the error processing */
        ok = 0;
        switch (sg_err_category3(&rio_hdr)) {
        case SG_LIB_CAT_CLEAN:
            ok = 1;
            break;
        case SG_LIB_CAT_RECOVERED:
            printf("Recovered error, continuing\n");
            ok = 1;
            break;
        default: /* won't bother decoding other categories */
            sg_chk_n_print3("command error", &rio_hdr, 1);
            break;
        }

        if (ok) { /* output result if it is available */
            /* if (0 == rio_hdr.pack_id) */
            if (0 == (rio_hdr.pack_id % 3))
                printf("SEND DIAGNOSTIC %d duration=%u %s\n", rio_hdr.pack_id,
                       rio_hdr.duration, (dur_in_nanosecs ? "ns" : "ms"));
            else
                printf("INQUIRY %d duration=%u %s\n", rio_hdr.pack_id,
                       rio_hdr.duration, (dur_in_nanosecs ? "ns" : "ms"));
        }
    }

    close(sg_fd);
    return 0;
}