1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/ioctl.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10
11 /* If the following fails the Linux kernel is probably too old */
12 #include <linux/bsg.h>
13
14
15 #include "sg_lib.h"
16 #include "sg_io_linux.h"
17 #include "sg_linux_inc.h"
18
19 /* This program was used to test SCSI mid level queue ordering.
20 The default behaviour is to "queue at head" which is useful for
21 error processing but not for streaming READ and WRITE commands.
22
23 * Copyright (C) 2010-2016 D. Gilbert
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License as published by
26 * the Free Software Foundation; either version 2, or (at your option)
27 * any later version.
28
29 Invocation: bsg_queue_tst [-t] <bsg_device>
30 -t queue at tail
31
32 Version 0.90 (20100324)
33
34 */
35
36 #define INQ_REPLY_LEN 96
37 #define INQ_CMD_LEN 6
38 #define SDIAG_CMD_LEN 6
39 #define SENSE_BUFFER_LEN 96
40
41 #define EBUFF_SZ 256
42
43 #ifndef BSG_FLAG_Q_AT_TAIL
44 #define BSG_FLAG_Q_AT_TAIL 0x10
45 #endif
46
47 #ifndef BSG_FLAG_Q_AT_HEAD
48 #define BSG_FLAG_Q_AT_HEAD 0x20
49 #endif
50
51
main(int argc,char * argv[])52 int main(int argc, char * argv[])
53 {
54 int bsg_fd, k, ok;
55 unsigned char inqCmdBlk[INQ_CMD_LEN] =
56 {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
57 unsigned char sdiagCmdBlk[SDIAG_CMD_LEN] =
58 {0x1d, 0, 0, 0, 0, 0};
59 unsigned char inqBuff[16][INQ_REPLY_LEN];
60 struct sg_io_v4 io_hdr[16];
61 struct sg_io_v4 rio_hdr;
62 char * file_name = 0;
63 char ebuff[EBUFF_SZ];
64 unsigned char sense_buffer[16][SENSE_BUFFER_LEN];
65 int q_at_tail = 0;
66
67 for (k = 1; k < argc; ++k) {
68 if (0 == memcmp("-t", argv[k], 2))
69 ++q_at_tail;
70 else if (*argv[k] == '-') {
71 printf("Unrecognized switch: %s\n", argv[k]);
72 file_name = 0;
73 break;
74 }
75 else if (0 == file_name)
76 file_name = argv[k];
77 else {
78 printf("too many arguments\n");
79 file_name = 0;
80 break;
81 }
82 }
83 if (0 == file_name) {
84 printf("Usage: 'bsg_queue_tst [-t] <bsg_device>'\n"
85 "where:\n -t queue_at_tail (def: q_at_head)\n");
86 return 1;
87 }
88
89 /* An access mode of O_RDWR is required for write()/read() interface */
90 if ((bsg_fd = open(file_name, O_RDWR)) < 0) {
91 snprintf(ebuff, EBUFF_SZ,
92 "bsg_queue_tst: error opening file: %s", file_name);
93 perror(ebuff);
94 return 1;
95 }
96
97 for (k = 0; k < 16; ++k) {
98 /* Prepare INQUIRY command */
99 memset(&io_hdr[k], 0, sizeof(struct sg_io_v4));
100 io_hdr[k].guard = 'Q';
101 /* io_hdr[k].iovec_count = 0; */ /* memset takes care of this */
102 if (0 == (k % 3)) {
103 io_hdr[k].request_len = sizeof(sdiagCmdBlk);
104 io_hdr[k].request = (uint64_t)(long)sdiagCmdBlk;
105 } else {
106 io_hdr[k].request_len = sizeof(inqCmdBlk);
107 io_hdr[k].request = (uint64_t)(long)inqCmdBlk;
108 io_hdr[k].din_xfer_len = INQ_REPLY_LEN;
109 io_hdr[k].din_xferp = (uint64_t)(long)inqBuff[k];
110 }
111 io_hdr[k].response = (uint64_t)(long)sense_buffer[k];
112 io_hdr[k].max_response_len = SENSE_BUFFER_LEN;
113 io_hdr[k].timeout = 20000; /* 20000 millisecs == 20 seconds */
114 io_hdr[k].usr_ptr = k;
115 /* default is to queue at head (in SCSI mid level) */
116 if (q_at_tail)
117 io_hdr[k].flags |= BSG_FLAG_Q_AT_TAIL;
118 else
119 io_hdr[k].flags |= BSG_FLAG_Q_AT_HEAD;
120
121 if (write(bsg_fd, &io_hdr[k], sizeof(struct sg_io_v4)) < 0) {
122 perror("bsg_queue_tst: bsg write error");
123 close(bsg_fd);
124 return 1;
125 }
126 }
127 /* sleep(3); */
128 for (k = 0; k < 16; ++k) {
129 memset(&rio_hdr, 0, sizeof(struct sg_io_v4));
130 rio_hdr.guard = 'Q';
131 if (read(bsg_fd, &rio_hdr, sizeof(struct sg_io_v4)) < 0) {
132 perror("bsg_queue_tst: bsg read error");
133 close(bsg_fd);
134 return 1;
135 }
136 /* now for the error processing */
137 ok = 0;
138 if (0 == rio_hdr.device_status)
139 ok = 1;
140 else {
141 switch (sg_err_category_sense((unsigned char *)(long)
142 rio_hdr.response, rio_hdr.response_len)) {
143 case SG_LIB_CAT_CLEAN:
144 ok = 1;
145 break;
146 case SG_LIB_CAT_RECOVERED:
147 printf("Recovered error, continuing\n");
148 ok = 1;
149 break;
150 default: /* won't bother decoding other categories */
151 fprintf(stderr, "command error:\n");
152 sg_print_sense(NULL, (unsigned char *)(long)rio_hdr.response,
153 rio_hdr.response_len, 1);
154 break;
155 }
156 }
157
158 if (ok) { /* output result if it is available */
159 /* if (0 == rio_hdr.pack_id) */
160 if (0 == (rio_hdr.usr_ptr % 3))
161 printf("SEND DIAGNOSTIC %d duration=%u\n",
162 (int)rio_hdr.usr_ptr, rio_hdr.duration);
163 else
164 printf("INQUIRY %d duration=%u\n", (int)rio_hdr.usr_ptr,
165 rio_hdr.duration);
166 }
167 }
168
169 close(bsg_fd);
170 return 0;
171 }
172