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/>.
22 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <arpa/inet.h>
28 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
31 #define SG_DXFER_NONE -1
33 #ifndef SG_DXFER_TO_DEV
34 #define SG_DXFER_TO_DEV -2
36 #ifndef SG_DXFER_FROM_DEV
37 #define SG_DXFER_FROM_DEV -3
52 void set_nonblocking(int fd)
55 v = fcntl(fd, F_GETFL, 0);
56 fcntl(fd, F_SETFL, v | O_NONBLOCK);
61 struct login_param *next;
65 struct login_param *login_params;
67 static void add_login_param(char *arg, char *value)
69 struct login_param *new_param;
71 new_param = malloc(sizeof(struct login_param));
72 if (new_param == NULL) {
73 printf("Failed to allocate login param struct\n");
76 new_param->arg = strdup(arg);
77 new_param->value = strdup(value);
78 new_param->next = login_params;
79 login_params = new_param;
82 static int send_iscsi_pdu(struct iscsi_device *sd, char *ish, char *data, int len)
85 ssize_t remaining, count;
88 ish[16] = (sd->itt>>24)&0xff;
89 ish[17] = (sd->itt>>16)&0xff;
90 ish[18] = (sd->itt>> 8)&0xff;
91 ish[19] = (sd->itt )&0xff;
93 /* command sequence number */
94 ish[24] = (sd->cmd_sn>>24)&0xff;
95 ish[25] = (sd->cmd_sn>>16)&0xff;
96 ish[26] = (sd->cmd_sn>> 8)&0xff;
97 ish[27] = (sd->cmd_sn )&0xff;
99 /* expected stat sequence number */
100 ish[28] = (sd->exp_stat_sn>>24)&0xff;
101 ish[29] = (sd->exp_stat_sn>>16)&0xff;
102 ish[30] = (sd->exp_stat_sn>> 8)&0xff;
103 ish[31] = (sd->exp_stat_sn )&0xff;
105 buf=malloc(48+len+4);
107 printf("Failed to allocate buffer for PDU of size %d bytes\n", 48+len);
111 memcpy(buf, ish, 48);
113 memcpy(buf+48, data, len);
115 remaining = 48 + len;
116 remaining = (remaining+3)&0xfffffc;
118 while(remaining > 0) {
119 count = write(sd->s, ptr, remaining);
121 printf("Write to socket failed with errno %d(%s)\n", errno, strerror(errno));
132 static int wait_for_pdu(struct iscsi_device *sd, char *ish, char *data, unsigned int *data_size)
135 ssize_t total, remaining, count;
136 unsigned int itt, dsl;
141 while (remaining > 0) {
142 count = read(sd->s, ptr, remaining);
144 printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
152 itt = (ish[16]&0xff)<<24;
153 itt |= (ish[17]&0xff)<<16;
154 itt |= (ish[18]&0xff)<< 8;
155 itt |= (ish[19]&0xff);
156 if (itt != sd->itt) {
157 printf("Wrong ITT in PDU. Expected 0x%08x, got 0x%08x\n", sd->itt, itt);
161 /* data segment length */
162 dsl = (ish[5]&0xff)<<16;
163 dsl |= (ish[6]&0xff)<<8;
164 dsl |= (ish[7]&0xff);
166 total = (dsl+3)&0xfffffffc;
168 buf = malloc(remaining);
170 printf("Failed to alloc buf to read data into\n");
174 while (remaining > 0) {
175 count = read(sd->s, ptr, remaining);
178 printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
185 /* stat sequence number */
186 ssn = (ish[24]&0xff)<<24;
187 ssn |= (ish[25]&0xff)<<16;
188 ssn |= (ish[26]&0xff)<<8;
189 ssn |= (ish[27]&0xff);
190 sd->exp_stat_sn = ssn+1;
192 /* expected command sequence number */
193 ecsn = (ish[28]&0xff)<<24;
194 ecsn |= (ish[29]&0xff)<<16;
195 ecsn |= (ish[30]&0xff)<<8;
196 ecsn |= (ish[31]&0xff);
200 unsigned long int buffer_offset;
202 buffer_offset = (ish[40]&0xff)<<24;
203 buffer_offset |= (ish[41]&0xff)<<16;
204 buffer_offset |= (ish[42]&0xff)<<8;
205 buffer_offset |= (ish[43]&0xff);
207 if (buffer_offset == 0) {
208 /* we only return the data from the first data-in pdu */
209 if (data_size && *data_size > 0) {
210 if ((ssize_t)*data_size > total) {
214 memcpy(data, buf, *data_size);
224 static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
230 struct login_param *login_param;
233 add_login_param("SessionType", "Normal");
234 add_login_param("HeaderDigest", "None");
235 add_login_param("DataDigest", "None");
236 add_login_param("DefaultTime2Wait", "0");
237 add_login_param("DefaultTime2Retain", "0");
238 add_login_param("InitialR2T", "Yes");
239 add_login_param("ImmediateData", "Yes");
240 add_login_param("MaxBurstLength", "16776192");
241 add_login_param("FirstBurstLength", "16776192");
242 add_login_param("MaxOutstandingR2T", "1");
243 add_login_param("MaxRecvDataSegmentLength", "16776192");
244 add_login_param("DataPDUInOrder", "Yes");
245 add_login_param("MaxConnections", "1");
246 add_login_param("TargetName", discard_const(sd->target));
247 sprintf(alias, "dbench:%d", child->id);
248 add_login_param("InitiatorAlias", alias);
249 sprintf(name, "iqn.2009-09.dbench:%d", child->id);
250 add_login_param("InitiatorName", name);
254 /* opcode : LOGIN REQUEST (I) */
257 /* T CSG:op NSG:full feature */
260 /* data segment length */
261 for(login_param=login_params, len=0; login_param; login_param=login_param->next) {
262 len += strlen(login_param->arg);
264 len += strlen(login_param->value);
267 /* data segment length */
268 ish[5] = (len>>16)&0xff;
269 ish[6] = (len>> 8)&0xff;
270 ish[7] = (len )&0xff;
274 ish[8] = (sd->isid>>40)&0xff;
275 ish[9] = (sd->isid>>32)&0xff;
276 ish[10] = (sd->isid>>24)&0xff;
277 ish[11] = (sd->isid>>16)&0xff;
278 ish[12] = (sd->isid>> 8)&0xff;
279 ish[13] = (sd->isid )&0xff;
282 for(login_param=login_params, ptr=data; login_param; login_param=login_param->next) {
283 strcpy(ptr,login_param->arg);
284 ptr+=strlen(login_param->arg);
287 strcpy(ptr,login_param->value);
288 ptr+=strlen(login_param->value);
293 if (send_iscsi_pdu(sd, ish, data, len) != 0) {
294 printf("Failed to send iscsi pdu\n");
298 if (wait_for_pdu(sd, ish, NULL, NULL) != 0) {
299 printf("Failed to send iscsi pdu\n");
319 /* XXX merge with scsi.c */
320 static int check_sense(unsigned char sc, const char *expected)
322 if (strcmp(expected, "*") == 0){
325 if (strncmp(expected, "0x", 2) == 0) {
326 return sc == strtol(expected, NULL, 16);
330 static void failed(struct child_struct *child)
333 printf("ERROR: child %d failed at line %d\n", child->id, child->line);
339 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)
342 int data_in_len=0, data_out_len=0;
346 /* opcode : SCSI command */
350 ish[1] = 0x81; /* F + SIMPLE */
351 if (xfer_dir == SG_DXFER_FROM_DEV) {
353 data_in_len= *data_size;
356 if (xfer_dir == SG_DXFER_TO_DEV) {
359 /* data segment length */
360 ish[5] = ((*data_size)>>16)&0xff;
361 ish[6] = ((*data_size)>> 8)&0xff;
362 ish[7] = ((*data_size) )&0xff;
365 data_out_len=*data_size;
369 ish[9] = options.iscsi_lun;
371 /* expected data xfer len */
372 ish[20] = ((*data_size)>>24)&0xff;
373 ish[21] = ((*data_size)>>16)&0xff;
374 ish[22] = ((*data_size)>> 8)&0xff;
375 ish[23] = ((*data_size) )&0xff;
378 memcpy(ish+32, cdb, cdb_size);
380 *data_size=data_out_len;
381 if (send_iscsi_pdu(sd, ish, data, *data_size) != 0) {
382 printf("Failed to send iscsi pdu\n");
387 *data_size=data_in_len;
388 if (wait_for_pdu(sd, ish, data, data_size) != 0) {
389 printf("Failed to receive iscsi pdu\n");
393 switch (ish[0]&0x3f) {
394 case 0x21: /* SCSI response */
396 printf("SCSI Response %d\n", ish[2]);
411 case 0x25: /* SCSI Data-In */
417 /* no sbit, it means there is more data to read */
421 printf("got unsupported PDU:0x%02x\n", ish[0]&0x3f);
429 static void iscsi_testunitready(struct dbench_op *op)
431 struct iscsi_device *sd;
432 unsigned char cdb[]={0,0,0,0,0,0};
435 unsigned int data_size=0;
437 sd = op->child->private;
439 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc);
441 printf("SCSI_IO failed\n");
444 if (!check_sense(sc, op->status)) {
445 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
446 op->child->line, op->fname, sc, op->status);
452 static void iscsi_read10(struct dbench_op *op)
454 struct iscsi_device *sd=op->child->private;
455 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
457 uint32_t lba = op->params[0];
458 uint32_t xferlen = op->params[1];
459 int rd = op->params[2];
460 int grp = op->params[3];
461 unsigned int data_size=1024*1024;
462 char data[data_size];
465 lba = (lba / xferlen) * xferlen;
467 /* make sure we wrap properly instead of failing if the loadfile
468 is bigger than our device
470 if (sd->blocks <= lba) {
471 lba = lba%sd->blocks;
473 if (sd->blocks <= lba+xferlen) {
479 cdb[2] = (lba>>24)&0xff;
480 cdb[3] = (lba>>16)&0xff;
481 cdb[4] = (lba>> 8)&0xff;
482 cdb[5] = (lba )&0xff;
486 cdb[7] = (xferlen>>8)&0xff;
487 cdb[8] = xferlen&0xff;
488 data_size = xferlen*512;
490 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
492 printf("SCSI_IO failed\n");
495 if (!check_sense(sc, op->status)) {
496 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
497 op->child->line, op->fname, sc, op->status);
501 op->child->bytes += xferlen*512;
506 static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
508 struct iscsi_device *sd;
509 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
511 int lba = op->params[0];
512 int pmi = op->params[1];
513 unsigned int data_size=8;
514 char data[data_size];
517 cdb[2] = (lba>>24)&0xff;
518 cdb[3] = (lba>>16)&0xff;
519 cdb[4] = (lba>> 8)&0xff;
520 cdb[5] = (lba )&0xff;
524 sd = op->child->private;
526 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
528 printf("SCSI_IO failed\n");
531 if (!check_sense(sc, op->status)) {
532 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
533 op->child->line, op->fname, sc, op->status);
538 *blocks = (data[0]&0xff)<<24;
539 *blocks |= (data[1]&0xff)<<16;
540 *blocks |= (data[2]&0xff)<<8;
541 *blocks |= (data[3]&0xff);
545 static void iscsi_readcapacity10(struct dbench_op *op)
547 return local_iscsi_readcapacity10(op, NULL);
550 static void iscsi_setup(struct child_struct *child)
552 struct iscsi_device *sd;
553 struct sockaddr_in sin;
554 struct dbench_op fake_op;
556 sd = malloc(sizeof(struct iscsi_device));
558 printf("Failed to allocate iscsi device structure\n");
563 sd->portal=options.iscsi_portal;
564 sd->target=options.iscsi_target;
565 sd->isid =0x0000800000000000ULL | child->id;
566 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
568 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
572 sin.sin_family = AF_INET;
573 sin.sin_port = htons(options.iscsi_port);
574 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
575 printf("Failed to convert \"%s\" into an address\n", sd->portal);
579 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
580 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
587 if (iscsi_login(child, sd) != 0) {
588 printf("Failed to log in to target.\n");
594 iscsi_testunitready(&fake_op);
599 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
603 static void iscsi_cleanup(struct child_struct *child)
605 struct iscsi_device *sd;
613 static int iscsi_init(void)
615 struct iscsi_device *sd;
616 struct sockaddr_in sin;
617 struct dbench_op fake_op;
618 struct child_struct child;
620 sd = malloc(sizeof(struct iscsi_device));
622 printf("Failed to allocate iscsi device structure\n");
628 sd->portal=options.iscsi_portal;
629 sd->target=options.iscsi_target;
630 sd->isid =0x0000800000000000ULL | child.id;
631 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
633 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
637 sin.sin_family = AF_INET;
638 sin.sin_port = htons(options.iscsi_port);
639 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
640 printf("Failed to convert \"%s\" into an address\n", sd->portal);
644 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
645 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
652 if (iscsi_login(&child, sd) != 0) {
653 printf("Failed to log in to target.\n");
657 fake_op.child=&child;
659 iscsi_testunitready(&fake_op);
664 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
673 static struct backend_op ops[] = {
674 { "TESTUNITREADY", iscsi_testunitready },
675 { "READ10", iscsi_read10 },
676 { "READCAPACITY10", iscsi_readcapacity10 },
680 struct nb_operations iscsi_ops = {
681 .backend_name = "iscsibench",
683 .setup = iscsi_setup,
684 .cleanup = iscsi_cleanup,