1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "sg_lib.h"
#include "sg_io_linux.h"
#include "sg_linux_inc.h"
/* This program was used to test SCSI mid level queue ordering.
The default behaviour is to "queue at head" which is useful for
error processing but not for streaming READ and WRITE commands.
* Copyright (C) 2010 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_queue_tst [-t] <sg_device>
-t queue at tail
Version 0.91 (20160528)
*/
#define INQ_REPLY_LEN 96
#define INQ_CMD_LEN 6
#define SDIAG_CMD_LEN 6
#define SENSE_BUFFER_LEN 96
#define EBUFF_SZ 256
#ifndef SG_FLAG_Q_AT_TAIL
#define SG_FLAG_Q_AT_TAIL 0x10
#endif
#ifndef SG_FLAG_Q_AT_HEAD
#define SG_FLAG_Q_AT_HEAD 0x20
#endif
int main(int argc, char * argv[])
{
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, 0, 0, 0, 0, 0};
uint8_t inqBuff[16][INQ_REPLY_LEN];
sg_io_hdr_t io_hdr[16];
sg_io_hdr_t rio_hdr;
char * file_name = 0;
char ebuff[EBUFF_SZ];
uint8_t sense_buffer[16][SENSE_BUFFER_LEN];
int q_at_tail = 0;
for (k = 1; k < argc; ++k) {
if (0 == memcmp("-t", argv[k], 2))
++q_at_tail;
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 [-t] <sg_device>'\n"
"where:\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;
}
for (k = 0; k < 16; ++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 < 16; ++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\n", rio_hdr.pack_id,
rio_hdr.duration);
else
printf("INQUIRY %d duration=%u\n", rio_hdr.pack_id,
rio_hdr.duration);
}
}
close(sg_fd);
return 0;
}
|