2 Copyright (C) by Ronnie Sahlberg <sahlberg@samba.org> 2008
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
24 #ifdef HAVE_LINUX_SCSI_SG
27 #include <sys/ioctl.h>
30 #define SCSI_TIMEOUT 5000 /* ms */
32 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
38 static void scsi_setup(struct child_struct *child)
41 struct scsi_device *sd;
43 sd = malloc(sizeof(struct scsi_device));
45 printf("Failed to allocate scsi device structure\n");
49 if((sd->fd=open(options.scsi_dev, O_RDWR))<0){
50 printf("Failed to open scsi device node : %s\n", options.scsi_dev);
54 if ((ioctl(sd->fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
55 printf("%s is not a SCSI device node\n", options.scsi_dev);
62 static void scsi_cleanup(struct child_struct *child)
64 struct scsi_device *sd;
73 static int scsi_io(int fd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned int *data_size, char *data, unsigned char *sc)
76 unsigned int sense_len=32;
77 unsigned char sense[sense_len];
81 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
82 io_hdr.interface_id = 'S';
86 io_hdr.cmd_len = cdb_size;
88 /* Where to store the sense_data, if there was an error */
90 io_hdr.mx_sb_len = sense_len;
93 /* Transfer direction, either in or out. Linux does not yet
94 support bidirectional SCSI transfers ?
96 io_hdr.dxfer_direction = xfer_dir;
98 /* Where to store the DATA IN/OUT from the device and how big the
101 io_hdr.dxferp = data;
102 io_hdr.dxfer_len = *data_size;
104 /* SCSI timeout in ms */
105 io_hdr.timeout = SCSI_TIMEOUT;
108 if(ioctl(fd, SG_IO, &io_hdr) < 0){
109 perror("SG_IO ioctl failed");
113 /* now for the error processing */
114 if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
115 if(io_hdr.sb_len_wr > 0){
116 sense_len=io_hdr.sb_len_wr;
121 if(io_hdr.masked_status){
122 printf("SCSI status=0x%x\n", io_hdr.status);
123 printf("SCSI masked_status=0x%x\n", io_hdr.masked_status);
126 if(io_hdr.host_status){
127 printf("SCSI host_status=0x%x\n", io_hdr.host_status);
130 if(io_hdr.driver_status){
131 printf("driver_status=0x%x\n", io_hdr.driver_status);
139 static int check_sense(unsigned char sc, const char *expected)
141 if (strcmp(expected, "*") == 0){
144 if (strncmp(expected, "0x", 2) == 0) {
145 return sc == strtol(expected, NULL, 16);
150 static void failed(struct child_struct *child)
153 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
157 static void scsi_testunitready(struct dbench_op *op)
159 struct scsi_device *sd;
160 unsigned char cdb[]={0,0,0,0,0,0};
163 unsigned int data_size=200;
164 char data[data_size];
166 sd = op->child->private;
168 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
170 printf("SCSI_IO failed\n");
173 if (!check_sense(sc, op->status)) {
174 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
175 op->child->line, op->fname, sc, op->status);
183 static void scsi_read6(struct dbench_op *op)
185 struct scsi_device *sd;
186 unsigned char cdb[]={0x08,0,0,0,0,0};
188 int lba = op->params[0];
189 int xferlen = op->params[1];
190 unsigned int data_size=1024*1024;
191 char data[data_size];
194 cdb[1] = (lba>>16)&0x1f;
195 cdb[2] = (lba>> 8)&0xff;
196 cdb[3] = (lba )&0xff;
198 cdb[4] = xferlen&0xff;
199 data_size = xferlen*512;
201 sd = op->child->private;
203 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
205 printf("SCSI_IO failed\n");
208 if (!check_sense(sc, op->status)) {
209 printf("[%d] READ6 \"%s\" failed (0x%02x) - expected %s\n",
210 op->child->line, op->fname, sc, op->status);
214 op->child->bytes += xferlen*512;
217 static void scsi_read10(struct dbench_op *op)
219 struct scsi_device *sd;
220 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
222 int lba = op->params[0];
223 int xferlen = op->params[1];
224 int rd = op->params[2];
225 int grp = op->params[3];
226 unsigned int data_size=1024*1024;
227 char data[data_size];
232 cdb[2] = (lba>>24)&0xff;
233 cdb[3] = (lba>>16)&0xff;
234 cdb[4] = (lba>> 8)&0xff;
235 cdb[5] = (lba )&0xff;
239 cdb[7] = (xferlen>>8)&0xff;
240 cdb[8] = xferlen&0xff;
241 data_size = xferlen*512;
243 sd = op->child->private;
245 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
247 printf("SCSI_IO failed\n");
250 if (!check_sense(sc, op->status)) {
251 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
252 op->child->line, op->fname, sc, op->status);
256 op->child->bytes += xferlen*512;
259 static void scsi_readcapacity10(struct dbench_op *op)
261 struct scsi_device *sd;
262 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
264 int lba = op->params[0];
265 int pmi = op->params[1];
266 unsigned int data_size=8;
267 char data[data_size];
270 cdb[2] = (lba>>24)&0xff;
271 cdb[3] = (lba>>16)&0xff;
272 cdb[4] = (lba>> 8)&0xff;
273 cdb[5] = (lba )&0xff;
277 sd = op->child->private;
279 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
281 printf("SCSI_IO failed\n");
284 if (!check_sense(sc, op->status)) {
285 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
286 op->child->line, op->fname, sc, op->status);
291 static struct backend_op ops[] = {
292 { "READ6", scsi_read6 },
293 { "READ10", scsi_read10 },
294 { "READCAPACITY10", scsi_readcapacity10 },
295 { "TESTUNITREADY", scsi_testunitready },
299 struct nb_operations scsi_ops = {
300 .backend_name = "scsibench",
302 .cleanup = scsi_cleanup,
306 #endif /* HAVE_LINUX_SCSI_SG */