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 #include <sys/ioctl.h>
28 #define SCSI_TIMEOUT 5000 /* ms */
30 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
37 static int check_sense(unsigned char sc, const char *expected);
38 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);
40 static void num_device_blocks(struct scsi_device *sd)
42 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
44 unsigned int data_size=8;
48 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
50 printf("SCSI_IO failed when reading disk capacity\n");
53 if (!check_sense(sc, "0x00")) {
54 printf("READCAPACITY10 failed (0x%02x) - expected 0x00\n", sc);
58 sd->blocks = (0xff & data[0]);
59 sd->blocks = (sd->blocks<<8) | (0xff & data[1]);
60 sd->blocks = (sd->blocks<<8) | (0xff & data[2]);
61 sd->blocks = (sd->blocks<<8) | (0xff & data[3]);
66 static void scsi_setup(struct child_struct *child)
69 struct scsi_device *sd;
71 sd = malloc(sizeof(struct scsi_device));
73 printf("Failed to allocate scsi device structure\n");
77 if((sd->fd=open(options.scsi_dev, O_RDWR))<0){
78 printf("Failed to open scsi device node : %s\n", options.scsi_dev);
82 if ((ioctl(sd->fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
83 printf("%s is not a SCSI device node\n", options.scsi_dev);
89 /* read disk capacity */
90 num_device_blocks(sd);
93 static void scsi_cleanup(struct child_struct *child)
95 struct scsi_device *sd;
104 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)
107 unsigned int sense_len=32;
108 unsigned char sense[sense_len];
112 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
113 io_hdr.interface_id = 'S';
117 io_hdr.cmd_len = cdb_size;
119 /* Where to store the sense_data, if there was an error */
121 io_hdr.mx_sb_len = sense_len;
124 /* Transfer direction, either in or out. Linux does not yet
125 support bidirectional SCSI transfers ?
127 io_hdr.dxfer_direction = xfer_dir;
129 /* Where to store the DATA IN/OUT from the device and how big the
132 io_hdr.dxferp = data;
133 io_hdr.dxfer_len = *data_size;
135 /* SCSI timeout in ms */
136 io_hdr.timeout = SCSI_TIMEOUT;
139 if(ioctl(fd, SG_IO, &io_hdr) < 0){
140 perror("SG_IO ioctl failed");
144 /* now for the error processing */
145 if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
146 if(io_hdr.sb_len_wr > 0){
147 sense_len=io_hdr.sb_len_wr;
152 if(io_hdr.masked_status){
153 printf("SCSI status=0x%x\n", io_hdr.status);
154 printf("SCSI masked_status=0x%x\n", io_hdr.masked_status);
157 if(io_hdr.host_status){
158 printf("SCSI host_status=0x%x\n", io_hdr.host_status);
161 if(io_hdr.driver_status){
162 printf("driver_status=0x%x\n", io_hdr.driver_status);
170 static int check_sense(unsigned char sc, const char *expected)
172 if (strcmp(expected, "*") == 0){
175 if (strncmp(expected, "0x", 2) == 0) {
176 return sc == strtol(expected, NULL, 16);
181 static void failed(struct child_struct *child)
184 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
188 static void scsi_testunitready(struct dbench_op *op)
190 struct scsi_device *sd;
191 unsigned char cdb[]={0,0,0,0,0,0};
194 unsigned int data_size=200;
195 char data[data_size];
197 sd = op->child->private;
199 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
201 printf("SCSI_IO failed\n");
204 if (!check_sense(sc, op->status)) {
205 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
206 op->child->line, op->fname, sc, op->status);
213 static void scsi_synchronizecache10(struct dbench_op *op)
215 struct scsi_device *sd;
216 unsigned char cdb[]={0x35,0,0,0,0,0,0,0,0,0};
218 uint32_t lba = op->params[0];
219 uint32_t xferlen = op->params[1];
220 int syncnv = op->params[2];
221 int immed = op->params[3];
223 unsigned int data_size=200;
224 char data[data_size];
226 sd = op->child->private;
234 cdb[2] = (lba>>24)&0xff;
235 cdb[3] = (lba>>16)&0xff;
236 cdb[4] = (lba>> 8)&0xff;
237 cdb[5] = (lba )&0xff;
239 cdb[7] = (xferlen>>8)&0xff;
240 cdb[8] = xferlen&0xff;
242 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
244 printf("SCSI_IO failed\n");
247 if (!check_sense(sc, op->status)) {
248 printf("[%d] SYNCHRONIZECACHE10 \"%s\" failed (0x%02x) - expected %s\n",
249 op->child->line, op->fname, sc, op->status);
257 static void scsi_read6(struct dbench_op *op)
259 struct scsi_device *sd=op->child->private;
260 unsigned char cdb[]={0x08,0,0,0,0,0};
262 uint32_t lba = op->params[0];
263 uint32_t xferlen = op->params[1];
264 unsigned int data_size=1024*1024;
265 char data[data_size];
268 if (lba == 0xffffffff) {
270 lba = (lba / xferlen) * xferlen;
273 /* we only have 24 bit addresses in read 6 */
274 if (lba > 0x00ffffff) {
278 /* make sure we wrap properly instead of failing if the loadfile
279 is bigger than our device
281 if (sd->blocks <= lba) {
282 lba = lba%sd->blocks;
284 if (sd->blocks <= lba+xferlen) {
288 cdb[1] = (lba>>16)&0x1f;
289 cdb[2] = (lba>> 8)&0xff;
290 cdb[3] = (lba )&0xff;
292 cdb[4] = xferlen&0xff;
293 data_size = xferlen*512;
295 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
297 printf("SCSI_IO failed\n");
300 if (!check_sense(sc, op->status)) {
301 printf("[%d] READ6 \"%s\" failed (0x%02x) - expected %s\n",
302 op->child->line, op->fname, sc, op->status);
306 op->child->bytes += xferlen*512;
309 static void scsi_read10(struct dbench_op *op)
311 struct scsi_device *sd=op->child->private;
312 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
314 uint32_t lba = op->params[0];
315 uint32_t xferlen = op->params[1];
316 int rd = op->params[2];
317 int grp = op->params[3];
318 unsigned int data_size=1024*1024;
319 char data[data_size];
322 if (lba == 0xffffffff) {
324 lba = (lba / xferlen) * xferlen;
327 /* make sure we wrap properly instead of failing if the loadfile
328 is bigger than our device
330 if (sd->blocks <= lba) {
331 lba = lba%sd->blocks;
333 if (sd->blocks <= lba+xferlen) {
339 cdb[2] = (lba>>24)&0xff;
340 cdb[3] = (lba>>16)&0xff;
341 cdb[4] = (lba>> 8)&0xff;
342 cdb[5] = (lba )&0xff;
346 cdb[7] = (xferlen>>8)&0xff;
347 cdb[8] = xferlen&0xff;
348 data_size = xferlen*512;
350 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
352 printf("SCSI_IO failed\n");
355 if (!check_sense(sc, op->status)) {
356 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
357 op->child->line, op->fname, sc, op->status);
361 op->child->bytes += xferlen*512;
364 static void scsi_write10(struct dbench_op *op)
366 struct scsi_device *sd=op->child->private;
367 unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
369 uint32_t lba = op->params[0];
370 uint32_t xferlen = op->params[1];
371 int rd = op->params[2];
372 int fua = op->params[3];
373 unsigned int data_size=1024*1024;
374 char data[data_size];
377 if (!options.allow_scsi_writes) {
378 printf("Ignoring SCSI write\n");
382 if (lba == 0xffffffff) {
384 lba = (lba / xferlen) * xferlen;
387 /* make sure we wrap properly instead of failing if the loadfile
388 is bigger than our device
390 if (sd->blocks <= lba) {
391 lba = lba%sd->blocks;
393 if (sd->blocks <= lba+xferlen) {
399 cdb[2] = (lba>>24)&0xff;
400 cdb[3] = (lba>>16)&0xff;
401 cdb[4] = (lba>> 8)&0xff;
402 cdb[5] = (lba )&0xff;
406 cdb[7] = (xferlen>>8)&0xff;
407 cdb[8] = xferlen&0xff;
408 data_size = xferlen*512;
410 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
412 printf("SCSI_IO failed\n");
415 if (!check_sense(sc, op->status)) {
416 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
417 op->child->line, op->fname, sc, op->status);
421 op->child->bytes += xferlen*512;
424 static void scsi_readcapacity10(struct dbench_op *op)
426 struct scsi_device *sd;
427 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
429 int lba = op->params[0];
430 int pmi = op->params[1];
431 unsigned int data_size=8;
432 char data[data_size];
435 cdb[2] = (lba>>24)&0xff;
436 cdb[3] = (lba>>16)&0xff;
437 cdb[4] = (lba>> 8)&0xff;
438 cdb[5] = (lba )&0xff;
442 sd = op->child->private;
444 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
446 printf("SCSI_IO failed\n");
449 if (!check_sense(sc, op->status)) {
450 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
451 op->child->line, op->fname, sc, op->status);
456 static struct backend_op ops[] = {
457 { "READ6", scsi_read6 },
458 { "READ10", scsi_read10 },
459 { "READCAPACITY10", scsi_readcapacity10 },
460 { "SYNCHRONIZECACHE10", scsi_synchronizecache10 },
461 { "TESTUNITREADY", scsi_testunitready },
462 { "WRITE10", scsi_write10 },
466 struct nb_operations scsi_ops = {
467 .backend_name = "scsibench",
469 .cleanup = scsi_cleanup,