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