blob: 0ec6c7cce6cd3bf544ca1e245cabd6c04ce443da [file] [log] [blame]
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "sg_include.h"
#include "sg_err.h"
/* This program sends a user specified number of TEST UNIT READY commands
to the given sg device. Since TUR is a simple command involing no
data transfer (and no REQUEST SENSE command iff the unit is ready)
then this can be used for timing per SCSI command overheads.
* Copyright (C) 2000-2003 D. Gilbert
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
Invocation: sg_turs [-t] [-n=<number_of_turs>] <sg_device>
The value give to "-n=" can have the following multipliers:
'c','C' *1 'b','B' *512 'k' *1024 'K' *1000
'm' *(1024^2) 'M' *(1000^2) 'g' *(1024^3) 'G' *(1000^3)
Version 03.08 (20020406)
*/
#define TUR_CMD_LEN 6
int get_num(char * buf)
{
int res, num;
char c;
res = sscanf(buf, "%d%c", &num, &c);
if (0 == res)
return -1;
else if (1 == res)
return num;
else {
switch (c) {
case 'c':
case 'C':
return num;
case 'b':
case 'B':
return num * 512;
case 'k':
return num * 1024;
case 'K':
return num * 1000;
case 'm':
return num * 1024 * 1024;
case 'M':
return num * 1000000;
case 'g':
return num * 1024 * 1024 * 1024;
case 'G':
return num * 1000000000;
default:
fprintf(stderr, "unrecognized multiplier\n");
return -1;
}
}
}
#define EBUFF_SZ 256
int main(int argc, char * argv[])
{
int sg_fd, k;
unsigned char turCmdBlk [TUR_CMD_LEN] =
{0x00, 0, 0, 0, 0, 0};
sg_io_hdr_t io_hdr;
char * file_name = 0;
char ebuff[EBUFF_SZ];
unsigned char sense_buffer[32];
int num_turs = 1;
int num_errs = 0;
int do_time = 0;
struct timeval start_tm, end_tm;
for (k = 1; k < argc; ++k) {
if (0 == strncmp("-n=", argv[k], 3)) {
num_turs = get_num(argv[k] + 3);
if (num_turs < 0) {
printf("Couldn't decode number after '-n' switch\n");
file_name = 0;
break;
}
}
else if (0 == strcmp("-t", argv[k]))
do_time = 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) || (num_turs <= 0)) {
printf("Usage: 'sg_turs [-t] [-n=<num_of_test_unit_readys>] "
"<sg_device>'\n"
" where '-n=<num>' number of test_unit_ready commands "
"(def: 1)\n"
" can take k, K, m, M postfix multipliers\n"
" '-t' outputs total duration and commands per "
"second\n");
return 1;
}
if ((sg_fd = open(file_name, O_RDONLY)) < 0) {
snprintf(ebuff, EBUFF_SZ,
"sg_turs: error opening file: %s", file_name);
perror(ebuff);
return 1;
}
/* Just to be safe, check we have a new sg driver by trying an ioctl */
if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
printf("sg_turs: %s isn't an sg device (or the sg driver is old)\n",
file_name);
close(sg_fd);
return 1;
}
/* 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 (do_time) {
start_tm.tv_sec = 0;
start_tm.tv_usec = 0;
gettimeofday(&start_tm, NULL);
}
for (k = 0; k < num_turs; ++k) {
io_hdr.pack_id = k;
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
perror("sg_turs: Test Unit Ready SG_IO ioctl error");
close(sg_fd);
return 1;
}
if (io_hdr.info & SG_INFO_OK_MASK) {
++num_errs;
if (1 == num_turs) { /* then print out the error message */
if (SG_ERR_CAT_CLEAN != sg_err_category3(&io_hdr))
sg_chk_n_print3("tur", &io_hdr);
}
}
}
if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
struct timeval res_tm;
double a, b;
gettimeofday(&end_tm, NULL);
res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
if (res_tm.tv_usec < 0) {
--res_tm.tv_sec;
res_tm.tv_usec += 1000000;
}
a = res_tm.tv_sec;
a += (0.000001 * res_tm.tv_usec);
b = (double)num_turs;
printf("time to perform commands was %d.%06d secs",
(int)res_tm.tv_sec, (int)res_tm.tv_usec);
if (a > 0.00001)
printf("; %.2f operations/sec\n", b / a);
else
printf("\n");
}
printf("Completed %d Test Unit Ready commands with %d errors\n",
num_turs, num_errs);
close(sg_fd);
return 0;
}