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/>.
23 #ifdef HAVE_LINUX_SCSI_SG
26 #include <sys/ioctl.h>
30 #define SCSI_TIMEOUT 5000 /* ms */
32 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
39 static int check_sense(unsigned char sc, const char *expected);
40 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);
42 static void num_device_blocks(struct scsi_device *sd)
44 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
46 unsigned int data_size=8;
50 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
52 printf("SCSI_IO failed when reading disk capacity\n");
55 if (!check_sense(sc, "0x00")) {
56 printf("READCAPACITY10 failed (0x%02x) - expected 0x00\n", sc);
60 sd->blocks = (0xff & data[0]);
61 sd->blocks = (sd->blocks<<8) | (0xff & data[1]);
62 sd->blocks = (sd->blocks<<8) | (0xff & data[2]);
63 sd->blocks = (sd->blocks<<8) | (0xff & data[3]);
68 static void scsi_setup(struct child_struct *child)
71 struct scsi_device *sd;
73 sd = malloc(sizeof(struct scsi_device));
75 printf("Failed to allocate scsi device structure\n");
79 if((sd->fd=open(options.scsi_dev, O_RDWR))<0){
80 printf("Failed to open scsi device node : %s\n", options.scsi_dev);
84 if ((ioctl(sd->fd, SG_GET_VERSION_NUM, &vers) < 0) || (vers < 30000)) {
85 printf("%s is not a SCSI device node\n", options.scsi_dev);
91 /* read disk capacity */
92 num_device_blocks(sd);
95 static void scsi_cleanup(struct child_struct *child)
97 struct scsi_device *sd;
106 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)
109 unsigned int sense_len=32;
110 unsigned char sense[sense_len];
114 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
115 io_hdr.interface_id = 'S';
119 io_hdr.cmd_len = cdb_size;
121 /* Where to store the sense_data, if there was an error */
123 io_hdr.mx_sb_len = sense_len;
126 /* Transfer direction, either in or out. Linux does not yet
127 support bidirectional SCSI transfers ?
129 io_hdr.dxfer_direction = xfer_dir;
131 /* Where to store the DATA IN/OUT from the device and how big the
134 io_hdr.dxferp = data;
135 io_hdr.dxfer_len = *data_size;
137 /* SCSI timeout in ms */
138 io_hdr.timeout = SCSI_TIMEOUT;
141 if(ioctl(fd, SG_IO, &io_hdr) < 0){
142 perror("SG_IO ioctl failed");
146 /* now for the error processing */
147 if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK){
148 if(io_hdr.sb_len_wr > 0){
149 sense_len=io_hdr.sb_len_wr;
154 if(io_hdr.masked_status){
155 printf("SCSI status=0x%x\n", io_hdr.status);
156 printf("SCSI masked_status=0x%x\n", io_hdr.masked_status);
159 if(io_hdr.host_status){
160 printf("SCSI host_status=0x%x\n", io_hdr.host_status);
163 if(io_hdr.driver_status){
164 printf("driver_status=0x%x\n", io_hdr.driver_status);
172 static int check_sense(unsigned char sc, const char *expected)
174 if (strcmp(expected, "*") == 0){
177 if (strncmp(expected, "0x", 2) == 0) {
178 return sc == strtol(expected, NULL, 16);
183 static void failed(struct child_struct *child)
186 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
190 static void scsi_testunitready(struct dbench_op *op)
192 struct scsi_device *sd;
193 unsigned char cdb[]={0,0,0,0,0,0};
196 unsigned int data_size=200;
197 char data[data_size];
199 sd = op->child->private;
201 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
203 printf("SCSI_IO failed\n");
206 if (!check_sense(sc, op->status)) {
207 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
208 op->child->line, op->fname, sc, op->status);
216 static void scsi_read6(struct dbench_op *op)
218 struct scsi_device *sd=op->child->private;
219 unsigned char cdb[]={0x08,0,0,0,0,0};
221 uint32_t lba = op->params[0];
222 uint32_t xferlen = op->params[1];
223 unsigned int data_size=1024*1024;
224 char data[data_size];
227 if (lba == 0xffffffff) {
229 lba = (lba / xferlen) * xferlen;
232 /* we only have 24 bit addresses in read 6 */
233 if (lba > 0x00ffffff) {
237 /* make sure we wrap properly instead of failing if the loadfile
238 is bigger than our device
240 if (sd->blocks <= lba) {
241 lba = lba%sd->blocks;
243 if (sd->blocks <= lba+xferlen) {
247 cdb[1] = (lba>>16)&0x1f;
248 cdb[2] = (lba>> 8)&0xff;
249 cdb[3] = (lba )&0xff;
251 cdb[4] = xferlen&0xff;
252 data_size = xferlen*512;
254 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
256 printf("SCSI_IO failed\n");
259 if (!check_sense(sc, op->status)) {
260 printf("[%d] READ6 \"%s\" failed (0x%02x) - expected %s\n",
261 op->child->line, op->fname, sc, op->status);
265 op->child->bytes += xferlen*512;
268 static void scsi_read10(struct dbench_op *op)
270 struct scsi_device *sd=op->child->private;
271 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
273 uint32_t lba = op->params[0];
274 uint32_t xferlen = op->params[1];
275 int rd = op->params[2];
276 int grp = op->params[3];
277 unsigned int data_size=1024*1024;
278 char data[data_size];
281 if (lba == 0xffffffff) {
283 lba = (lba / xferlen) * xferlen;
286 /* make sure we wrap properly instead of failing if the loadfile
287 is bigger than our device
289 if (sd->blocks <= lba) {
290 lba = lba%sd->blocks;
292 if (sd->blocks <= lba+xferlen) {
298 cdb[2] = (lba>>24)&0xff;
299 cdb[3] = (lba>>16)&0xff;
300 cdb[4] = (lba>> 8)&0xff;
301 cdb[5] = (lba )&0xff;
305 cdb[7] = (xferlen>>8)&0xff;
306 cdb[8] = xferlen&0xff;
307 data_size = xferlen*512;
309 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
311 printf("SCSI_IO failed\n");
314 if (!check_sense(sc, op->status)) {
315 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
316 op->child->line, op->fname, sc, op->status);
320 op->child->bytes += xferlen*512;
323 static void scsi_write10(struct dbench_op *op)
325 struct scsi_device *sd=op->child->private;
326 unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
328 uint32_t lba = op->params[0];
329 uint32_t xferlen = op->params[1];
330 int rd = op->params[2];
331 int fua = op->params[3];
332 unsigned int data_size=1024*1024;
333 char data[data_size];
336 if (!options.allow_scsi_writes) {
337 printf("Ignoring SCSI write\n");
341 if (lba == 0xffffffff) {
343 lba = (lba / xferlen) * xferlen;
346 /* make sure we wrap properly instead of failing if the loadfile
347 is bigger than our device
349 if (sd->blocks <= lba) {
350 lba = lba%sd->blocks;
352 if (sd->blocks <= lba+xferlen) {
358 cdb[2] = (lba>>24)&0xff;
359 cdb[3] = (lba>>16)&0xff;
360 cdb[4] = (lba>> 8)&0xff;
361 cdb[5] = (lba )&0xff;
365 cdb[7] = (xferlen>>8)&0xff;
366 cdb[8] = xferlen&0xff;
367 data_size = xferlen*512;
369 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
371 printf("SCSI_IO failed\n");
374 if (!check_sense(sc, op->status)) {
375 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
376 op->child->line, op->fname, sc, op->status);
380 op->child->bytes += xferlen*512;
383 static void scsi_readcapacity10(struct dbench_op *op)
385 struct scsi_device *sd;
386 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
388 int lba = op->params[0];
389 int pmi = op->params[1];
390 unsigned int data_size=8;
391 char data[data_size];
394 cdb[2] = (lba>>24)&0xff;
395 cdb[3] = (lba>>16)&0xff;
396 cdb[4] = (lba>> 8)&0xff;
397 cdb[5] = (lba )&0xff;
401 sd = op->child->private;
403 res=scsi_io(sd->fd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
405 printf("SCSI_IO failed\n");
408 if (!check_sense(sc, op->status)) {
409 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
410 op->child->line, op->fname, sc, op->status);
415 static struct backend_op ops[] = {
416 { "READ6", scsi_read6 },
417 { "READ10", scsi_read10 },
418 { "READCAPACITY10", scsi_readcapacity10 },
419 { "TESTUNITREADY", scsi_testunitready },
420 { "WRITE10", scsi_write10 },
424 struct nb_operations scsi_ops = {
425 .backend_name = "scsibench",
427 .cleanup = scsi_cleanup,
431 #endif /* HAVE_LINUX_SCSI_SG */