2 Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2009
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/>.
20 #include <sys/types.h>
21 #include <sys/socket.h>
23 #include <arpa/inet.h>
25 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
28 #define SG_DXFER_NONE -1
30 #ifndef SG_DXFER_TO_DEV
31 #define SG_DXFER_TO_DEV -2
33 #ifndef SG_DXFER_FROM_DEV
34 #define SG_DXFER_FROM_DEV -3
49 void set_nonblocking(int fd)
52 v = fcntl(fd, F_GETFL, 0);
53 fcntl(fd, F_SETFL, v | O_NONBLOCK);
58 struct login_param *next;
62 struct login_param *login_params;
64 static void add_login_param(char *arg, char *value)
66 struct login_param *new_param;
68 new_param = malloc(sizeof(struct login_param));
69 if (new_param == NULL) {
70 printf("Failed to allocate login param struct\n");
73 new_param->arg = strdup(arg);
74 new_param->value = strdup(value);
75 new_param->next = login_params;
76 login_params = new_param;
79 static int send_iscsi_pdu(struct iscsi_device *sd, char *ish, char *data, int len)
82 ssize_t remaining, count;
85 ish[16] = (sd->itt>>24)&0xff;
86 ish[17] = (sd->itt>>16)&0xff;
87 ish[18] = (sd->itt>> 8)&0xff;
88 ish[19] = (sd->itt )&0xff;
90 /* command sequence number */
91 ish[24] = (sd->cmd_sn>>24)&0xff;
92 ish[25] = (sd->cmd_sn>>16)&0xff;
93 ish[26] = (sd->cmd_sn>> 8)&0xff;
94 ish[27] = (sd->cmd_sn )&0xff;
96 /* expected stat sequence number */
97 ish[28] = (sd->exp_stat_sn>>24)&0xff;
98 ish[29] = (sd->exp_stat_sn>>16)&0xff;
99 ish[30] = (sd->exp_stat_sn>> 8)&0xff;
100 ish[31] = (sd->exp_stat_sn )&0xff;
102 buf=malloc(48+len+4);
104 printf("Failed to allocate buffer for PDU of size %d bytes\n", 48+len);
108 memcpy(buf, ish, 48);
110 memcpy(buf+48, data, len);
112 remaining = 48 + len;
113 remaining = (remaining+3)&0xfffffc;
115 while(remaining > 0) {
116 count = write(sd->s, ptr, remaining);
118 printf("Write to socket failed with errno %d(%s)\n", errno, strerror(errno));
129 static int wait_for_pdu(struct iscsi_device *sd, char *ish, char *data, unsigned int *data_size)
132 ssize_t total, remaining, count;
133 unsigned int itt, dsl;
138 while (remaining > 0) {
139 count = read(sd->s, ptr, remaining);
141 printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
149 itt = (ish[16]&0xff)<<24;
150 itt |= (ish[17]&0xff)<<16;
151 itt |= (ish[18]&0xff)<< 8;
152 itt |= (ish[19]&0xff);
153 if (itt != sd->itt) {
154 printf("Wrong ITT in PDU. Expected 0x%08x, got 0x%08x\n", sd->itt, itt);
158 /* data segment length */
159 dsl = (ish[5]&0xff)<<16;
160 dsl |= (ish[6]&0xff)<<8;
161 dsl |= (ish[7]&0xff);
163 total = (dsl+3)&0xfffffffc;
165 buf = malloc(remaining);
167 printf("Failed to alloc buf to read data into\n");
171 while (remaining > 0) {
172 count = read(sd->s, ptr, remaining);
175 printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
182 /* stat sequence number */
183 ssn = (ish[24]&0xff)<<24;
184 ssn |= (ish[25]&0xff)<<16;
185 ssn |= (ish[26]&0xff)<<8;
186 ssn |= (ish[27]&0xff);
187 sd->exp_stat_sn = ssn+1;
189 /* expected command sequence number */
190 ecsn = (ish[28]&0xff)<<24;
191 ecsn |= (ish[29]&0xff)<<16;
192 ecsn |= (ish[30]&0xff)<<8;
193 ecsn |= (ish[31]&0xff);
197 unsigned long int buffer_offset;
199 buffer_offset = (ish[40]&0xff)<<24;
200 buffer_offset |= (ish[41]&0xff)<<16;
201 buffer_offset |= (ish[42]&0xff)<<8;
202 buffer_offset |= (ish[43]&0xff);
204 if (buffer_offset == 0) {
205 /* we only return the data from the first data-in pdu */
206 if (data_size && *data_size > 0) {
207 if ((ssize_t)*data_size > total) {
211 memcpy(data, buf, *data_size);
221 static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
227 struct login_param *login_param;
230 add_login_param("SessionType", "Normal");
231 add_login_param("HeaderDigest", "None");
232 add_login_param("DataDigest", "None");
233 add_login_param("DefaultTime2Wait", "0");
234 add_login_param("DefaultTime2Retain", "0");
235 add_login_param("InitialR2T", "Yes");
236 add_login_param("ImmediateData", "Yes");
237 add_login_param("MaxBurstLength", "16776192");
238 add_login_param("FirstBurstLength", "16776192");
239 add_login_param("MaxOutstandingR2T", "1");
240 add_login_param("MaxRecvDataSegmentLength", "16776192");
241 add_login_param("DataPDUInOrder", "Yes");
242 add_login_param("MaxConnections", "1");
243 add_login_param("TargetName", discard_const(sd->target));
244 sprintf(alias, "dbench:%d", child->id);
245 add_login_param("InitiatorAlias", alias);
246 sprintf(name, "iqn.2009-09.dbench:%d", child->id);
247 add_login_param("InitiatorName", name);
251 /* opcode : LOGIN REQUEST (I) */
254 /* T CSG:op NSG:full feature */
257 /* data segment length */
258 for(login_param=login_params, len=0; login_param; login_param=login_param->next) {
259 len += strlen(login_param->arg);
261 len += strlen(login_param->value);
264 /* data segment length */
265 ish[5] = (len>>16)&0xff;
266 ish[6] = (len>> 8)&0xff;
267 ish[7] = (len )&0xff;
271 ish[8] = (sd->isid>>40)&0xff;
272 ish[9] = (sd->isid>>32)&0xff;
273 ish[10] = (sd->isid>>24)&0xff;
274 ish[11] = (sd->isid>>16)&0xff;
275 ish[12] = (sd->isid>> 8)&0xff;
276 ish[13] = (sd->isid )&0xff;
279 for(login_param=login_params, ptr=data; login_param; login_param=login_param->next) {
280 strcpy(ptr,login_param->arg);
281 ptr+=strlen(login_param->arg);
284 strcpy(ptr,login_param->value);
285 ptr+=strlen(login_param->value);
290 if (send_iscsi_pdu(sd, ish, data, len) != 0) {
291 printf("Failed to send iscsi pdu\n");
295 if (wait_for_pdu(sd, ish, NULL, NULL) != 0) {
296 printf("Failed to send iscsi pdu\n");
316 /* XXX merge with scsi.c */
317 static int check_sense(unsigned char sc, const char *expected)
319 if (strcmp(expected, "*") == 0){
322 if (strncmp(expected, "0x", 2) == 0) {
323 return sc == strtol(expected, NULL, 16);
327 static void failed(struct child_struct *child)
330 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
336 static int do_iscsi_io(struct iscsi_device *sd, unsigned char *cdb, unsigned char cdb_size, int xfer_dir, unsigned int *data_size, char *data, unsigned char *sc)
339 int data_in_len=0, data_out_len=0;
343 /* opcode : SCSI command */
347 ish[1] = 0x81; /* F + SIMPLE */
348 if (xfer_dir == SG_DXFER_FROM_DEV) {
350 data_in_len= *data_size;
353 if (xfer_dir == SG_DXFER_TO_DEV) {
356 /* data segment length */
357 ish[5] = ((*data_size)>>16)&0xff;
358 ish[6] = ((*data_size)>> 8)&0xff;
359 ish[7] = ((*data_size) )&0xff;
362 data_out_len=*data_size;
366 ish[9] = options.iscsi_lun;
368 /* expected data xfer len */
369 ish[20] = ((*data_size)>>24)&0xff;
370 ish[21] = ((*data_size)>>16)&0xff;
371 ish[22] = ((*data_size)>> 8)&0xff;
372 ish[23] = ((*data_size) )&0xff;
375 memcpy(ish+32, cdb, cdb_size);
377 *data_size=data_out_len;
378 if (send_iscsi_pdu(sd, ish, data, *data_size) != 0) {
379 printf("Failed to send iscsi pdu\n");
384 *data_size=data_in_len;
385 if (wait_for_pdu(sd, ish, data, data_size) != 0) {
386 printf("Failed to receive iscsi pdu\n");
390 switch (ish[0]&0x3f) {
391 case 0x21: /* SCSI response */
393 printf("SCSI Response %d\n", ish[2]);
408 case 0x25: /* SCSI Data-In */
414 /* no sbit, it means there is more data to read */
418 printf("got unsupported PDU:0x%02x\n", ish[0]&0x3f);
426 static void iscsi_testunitready(struct dbench_op *op)
428 struct iscsi_device *sd;
429 unsigned char cdb[]={0,0,0,0,0,0};
432 unsigned int data_size=0;
434 sd = op->child->private;
436 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc);
438 printf("SCSI_IO failed\n");
441 if (!check_sense(sc, op->status)) {
442 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
443 op->child->line, op->fname, sc, op->status);
449 static void iscsi_read10(struct dbench_op *op)
451 struct iscsi_device *sd=op->child->private;
452 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
454 uint32_t lba = op->params[0];
455 uint32_t xferlen = op->params[1];
456 int rd = op->params[2];
457 int grp = op->params[3];
458 unsigned int data_size=1024*1024;
459 char data[data_size];
462 lba = (lba / xferlen) * xferlen;
464 /* make sure we wrap properly instead of failing if the loadfile
465 is bigger than our device
467 if (sd->blocks <= lba) {
468 lba = lba%sd->blocks;
470 if (sd->blocks <= lba+xferlen) {
476 cdb[2] = (lba>>24)&0xff;
477 cdb[3] = (lba>>16)&0xff;
478 cdb[4] = (lba>> 8)&0xff;
479 cdb[5] = (lba )&0xff;
483 cdb[7] = (xferlen>>8)&0xff;
484 cdb[8] = xferlen&0xff;
485 data_size = xferlen*512;
487 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
489 printf("SCSI_IO failed\n");
492 if (!check_sense(sc, op->status)) {
493 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
494 op->child->line, op->fname, sc, op->status);
498 op->child->bytes += xferlen*512;
503 static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
505 struct iscsi_device *sd;
506 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
508 int lba = op->params[0];
509 int pmi = op->params[1];
510 unsigned int data_size=8;
511 char data[data_size];
514 cdb[2] = (lba>>24)&0xff;
515 cdb[3] = (lba>>16)&0xff;
516 cdb[4] = (lba>> 8)&0xff;
517 cdb[5] = (lba )&0xff;
521 sd = op->child->private;
523 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
525 printf("SCSI_IO failed\n");
528 if (!check_sense(sc, op->status)) {
529 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
530 op->child->line, op->fname, sc, op->status);
535 *blocks = (data[0]&0xff)<<24;
536 *blocks |= (data[1]&0xff)<<16;
537 *blocks |= (data[2]&0xff)<<8;
538 *blocks |= (data[3]&0xff);
542 static void iscsi_readcapacity10(struct dbench_op *op)
544 return local_iscsi_readcapacity10(op, NULL);
547 static void iscsi_setup(struct child_struct *child)
549 struct iscsi_device *sd;
550 struct sockaddr_in sin;
551 struct dbench_op fake_op;
553 sd = malloc(sizeof(struct iscsi_device));
555 printf("Failed to allocate iscsi device structure\n");
560 sd->portal=options.iscsi_portal;
561 sd->target=options.iscsi_target;
562 sd->isid =0x0000800000000000ULL | child->id;
563 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
565 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
569 sin.sin_family = AF_INET;
570 sin.sin_port = htons(options.iscsi_port);
571 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
572 printf("Failed to convert \"%s\" into an address\n", sd->portal);
576 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
577 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
584 if (iscsi_login(child, sd) != 0) {
585 printf("Failed to log in to target.\n");
591 iscsi_testunitready(&fake_op);
596 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
600 static void iscsi_cleanup(struct child_struct *child)
602 struct iscsi_device *sd;
610 static int iscsi_init(void)
612 struct iscsi_device *sd;
613 struct sockaddr_in sin;
614 struct dbench_op fake_op;
615 struct child_struct child;
617 sd = malloc(sizeof(struct iscsi_device));
619 printf("Failed to allocate iscsi device structure\n");
625 sd->portal=options.iscsi_portal;
626 sd->target=options.iscsi_target;
627 sd->isid =0x0000800000000000ULL | child.id;
628 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
630 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
634 sin.sin_family = AF_INET;
635 sin.sin_port = htons(options.iscsi_port);
636 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
637 printf("Failed to convert \"%s\" into an address\n", sd->portal);
641 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
642 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
649 if (iscsi_login(&child, sd) != 0) {
650 printf("Failed to log in to target.\n");
654 fake_op.child=&child;
656 iscsi_testunitready(&fake_op);
661 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
670 static struct backend_op ops[] = {
671 { "TESTUNITREADY", iscsi_testunitready },
672 { "READ10", iscsi_read10 },
673 { "READCAPACITY10", iscsi_readcapacity10 },
677 struct nb_operations iscsi_ops = {
678 .backend_name = "iscsibench",
680 .setup = iscsi_setup,
681 .cleanup = iscsi_cleanup,