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>
31 #define SCSI_TIMEOUT 5000 /* ms */
33 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
40 static int check_sense(unsigned char sc, const char *expected);
41 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);
43 static void num_device_blocks(struct scsi_device *sd)
45 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
47 unsigned int data_size=8;
51 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
53 printf("SCSI_IO failed when reading disk capacity\n");
56 if (!check_sense(sc, "0x00")) {
57 printf("READCAPACITY10 failed (0x%02x) - expected 0x00\n", sc);
61 sd->blocks = (0xff & data[0]);
62 sd->blocks = (sd->blocks<<8) | (0xff & data[1]);
63 sd->blocks = (sd->blocks<<8) | (0xff & data[2]);
64 sd->blocks = (sd->blocks<<8) | (0xff & data[3]);
69 static void scsi_setup(struct child_struct *child)
72 struct scsi_device *sd;
74 sd = malloc(sizeof(struct scsi_device));
76 printf("Failed to allocate scsi device structure\n");
80 if((sd->fd=open(options.scsi_dev, O_RDWR))<0){
81 printf("Failed to open scsi device node : %s\n", options.scsi_dev);
85 if ((ioctl(sd->fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
86 printf("%s is not a SCSI device node\n", options.scsi_dev);
92 /* read disk capacity */
93 num_device_blocks(sd);
96 static void scsi_cleanup(struct child_struct *child)
98 struct scsi_device *sd;
107 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)
110 unsigned int sense_len=32;
111 unsigned char sense[sense_len];
115 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
116 io_hdr.interface_id = 'S';
120 io_hdr.cmd_len = cdb_size;
122 /* Where to store the sense_data, if there was an error */
124 io_hdr.mx_sb_len = sense_len;
127 /* Transfer direction, either in or out. Linux does not yet
128 support bidirectional SCSI transfers ?
130 io_hdr.dxfer_direction = xfer_dir;
132 /* Where to store the DATA IN/OUT from the device and how big the
135 io_hdr.dxferp = data;
136 io_hdr.dxfer_len = *data_size;
138 /* SCSI timeout in ms */
139 io_hdr.timeout = SCSI_TIMEOUT;
142 if(ioctl(fd, SG_IO, &io_hdr) < 0){
143 perror("SG_IO ioctl failed");
147 /* now for the error processing */
148 if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
149 if(io_hdr.sb_len_wr > 0){
150 sense_len=io_hdr.sb_len_wr;
155 if(io_hdr.masked_status){
156 printf("SCSI status=0x%x\n", io_hdr.status);
157 printf("SCSI masked_status=0x%x\n", io_hdr.masked_status);
160 if(io_hdr.host_status){
161 printf("SCSI host_status=0x%x\n", io_hdr.host_status);
164 if(io_hdr.driver_status){
165 printf("driver_status=0x%x\n", io_hdr.driver_status);
173 static int check_sense(unsigned char sc, const char *expected)
175 if (strcmp(expected, "*") == 0){
178 if (strncmp(expected, "0x", 2) == 0) {
179 return sc == strtol(expected, NULL, 16);
184 static void failed(struct child_struct *child)
187 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
191 static void scsi_testunitready(struct dbench_op *op)
193 struct scsi_device *sd;
194 unsigned char cdb[]={0,0,0,0,0,0};
197 unsigned int data_size=200;
198 char data[data_size];
200 sd = op->child->private;
202 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
204 printf("SCSI_IO failed\n");
207 if (!check_sense(sc, op->status)) {
208 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
209 op->child->line, op->fname, sc, op->status);
217 static void scsi_read6(struct dbench_op *op)
219 struct scsi_device *sd=op->child->private;
220 unsigned char cdb[]={0x08,0,0,0,0,0};
222 uint32_t lba = op->params[0];
223 uint32_t xferlen = op->params[1];
224 unsigned int data_size=1024*1024;
225 char data[data_size];
228 if (lba == 0xffffffff) {
230 lba = (lba / xferlen) * xferlen;
233 /* we only have 24 bit addresses in read 6 */
234 if (lba > 0x00ffffff) {
238 /* make sure we wrap properly instead of failing if the loadfile
239 is bigger than our device
241 if (sd->blocks <= lba) {
242 lba = lba%sd->blocks;
244 if (sd->blocks <= lba+xferlen) {
248 cdb[1] = (lba>>16)&0x1f;
249 cdb[2] = (lba>> 8)&0xff;
250 cdb[3] = (lba )&0xff;
252 cdb[4] = xferlen&0xff;
253 data_size = xferlen*512;
255 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
257 printf("SCSI_IO failed\n");
260 if (!check_sense(sc, op->status)) {
261 printf("[%d] READ6 \"%s\" failed (0x%02x) - expected %s\n",
262 op->child->line, op->fname, sc, op->status);
266 op->child->bytes += xferlen*512;
269 static void scsi_read10(struct dbench_op *op)
271 struct scsi_device *sd=op->child->private;
272 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
274 uint32_t lba = op->params[0];
275 uint32_t xferlen = op->params[1];
276 int rd = op->params[2];
277 int grp = op->params[3];
278 unsigned int data_size=1024*1024;
279 char data[data_size];
282 if (lba == 0xffffffff) {
284 lba = (lba / xferlen) * xferlen;
287 /* make sure we wrap properly instead of failing if the loadfile
288 is bigger than our device
290 if (sd->blocks <= lba) {
291 lba = lba%sd->blocks;
293 if (sd->blocks <= lba+xferlen) {
299 cdb[2] = (lba>>24)&0xff;
300 cdb[3] = (lba>>16)&0xff;
301 cdb[4] = (lba>> 8)&0xff;
302 cdb[5] = (lba )&0xff;
306 cdb[7] = (xferlen>>8)&0xff;
307 cdb[8] = xferlen&0xff;
308 data_size = xferlen*512;
310 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
312 printf("SCSI_IO failed\n");
315 if (!check_sense(sc, op->status)) {
316 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
317 op->child->line, op->fname, sc, op->status);
321 op->child->bytes += xferlen*512;
324 static void scsi_write10(struct dbench_op *op)
326 struct scsi_device *sd=op->child->private;
327 unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
329 uint32_t lba = op->params[0];
330 uint32_t xferlen = op->params[1];
331 int rd = op->params[2];
332 int fua = op->params[3];
333 unsigned int data_size=1024*1024;
334 char data[data_size];
337 if (!options.allow_scsi_writes) {
338 printf("Ignoring SCSI write\n");
342 if (lba == 0xffffffff) {
344 lba = (lba / xferlen) * xferlen;
347 /* make sure we wrap properly instead of failing if the loadfile
348 is bigger than our device
350 if (sd->blocks <= lba) {
351 lba = lba%sd->blocks;
353 if (sd->blocks <= lba+xferlen) {
359 cdb[2] = (lba>>24)&0xff;
360 cdb[3] = (lba>>16)&0xff;
361 cdb[4] = (lba>> 8)&0xff;
362 cdb[5] = (lba )&0xff;
366 cdb[7] = (xferlen>>8)&0xff;
367 cdb[8] = xferlen&0xff;
368 data_size = xferlen*512;
370 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
372 printf("SCSI_IO failed\n");
375 if (!check_sense(sc, op->status)) {
376 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
377 op->child->line, op->fname, sc, op->status);
381 op->child->bytes += xferlen*512;
384 static void scsi_readcapacity10(struct dbench_op *op)
386 struct scsi_device *sd;
387 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
389 int lba = op->params[0];
390 int pmi = op->params[1];
391 unsigned int data_size=8;
392 char data[data_size];
395 cdb[2] = (lba>>24)&0xff;
396 cdb[3] = (lba>>16)&0xff;
397 cdb[4] = (lba>> 8)&0xff;
398 cdb[5] = (lba )&0xff;
402 sd = op->child->private;
404 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
406 printf("SCSI_IO failed\n");
409 if (!check_sense(sc, op->status)) {
410 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
411 op->child->line, op->fname, sc, op->status);
416 static struct backend_op ops[] = {
417 { "READ6", scsi_read6 },
418 { "READ10", scsi_read10 },
419 { "READCAPACITY10", scsi_readcapacity10 },
420 { "TESTUNITREADY", scsi_testunitready },
421 { "WRITE10", scsi_write10 },
425 struct nb_operations scsi_ops = {
426 .backend_name = "scsibench",
428 .cleanup = scsi_cleanup,
432 #endif /* HAVE_LINUX_SCSI_SG */