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
36 #define PARAMETERS_SIZE 24
37 #define PROUT_CMD 0x5F
38 #define PROUT_SCOPE_LU_SCOPE 0x0
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]);
410 if (ish[3] == 0x18) {
411 /* reservation conflict */
417 case 0x25: /* SCSI Data-In */
423 /* no sbit, it means there is more data to read */
427 printf("got unsupported PDU:0x%02x\n", ish[0]&0x3f);
435 static void iscsi_testunitready(struct dbench_op *op)
437 struct iscsi_device *sd;
438 unsigned char cdb[]={0,0,0,0,0,0};
441 unsigned int data_size=0;
443 sd = op->child->private;
445 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc);
447 printf("SCSI_IO failed\n");
450 if (!check_sense(sc, op->status)) {
451 printf("[%d] TESTUNITREADY \"%s\" failed (0x%02x) - expected %s\n",
452 op->child->line, op->fname, sc, op->status);
458 static void iscsi_read10(struct dbench_op *op)
460 struct iscsi_device *sd=op->child->private;
461 unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
463 uint32_t lba = op->params[0];
464 uint32_t xferlen = op->params[1];
465 int rd = op->params[2];
466 int grp = op->params[3];
467 unsigned int data_size=1024*1024;
468 char data[data_size];
471 lba = (lba / xferlen) * xferlen;
473 /* make sure we wrap properly instead of failing if the loadfile
474 is bigger than our device
476 if (sd->blocks <= lba) {
477 lba = lba%sd->blocks;
479 if (sd->blocks <= lba+xferlen) {
485 cdb[2] = (lba>>24)&0xff;
486 cdb[3] = (lba>>16)&0xff;
487 cdb[4] = (lba>> 8)&0xff;
488 cdb[5] = (lba )&0xff;
492 cdb[7] = (xferlen>>8)&0xff;
493 cdb[8] = xferlen&0xff;
494 data_size = xferlen*512;
496 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
498 printf("SCSI_IO failed\n");
501 if (!check_sense(sc, op->status)) {
502 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
503 op->child->line, op->fname, sc, op->status);
507 op->child->bytes += xferlen*512;
511 static void iscsi_write10(struct dbench_op *op)
513 struct iscsi_device *sd=op->child->private;
514 unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
516 uint32_t lba = op->params[0];
517 uint32_t xferlen = op->params[1];
518 int fua = op->params[2];
519 int grp = op->params[3];
520 unsigned int data_size=1024*1024;
521 char data[data_size];
524 if (!options.allow_scsi_writes) {
525 printf("WRITE10 command in loadfile but --allow-scsi-writes not specified. Aborting.\n");
529 lba = (lba / xferlen) * xferlen;
531 /* make sure we wrap properly instead of failing if the loadfile
532 is bigger than our device
534 if (sd->blocks <= lba) {
535 lba = lba%sd->blocks;
537 if (sd->blocks <= lba+xferlen) {
543 cdb[2] = (lba>>24)&0xff;
544 cdb[3] = (lba>>16)&0xff;
545 cdb[4] = (lba>> 8)&0xff;
546 cdb[5] = (lba )&0xff;
550 cdb[7] = (xferlen>>8)&0xff;
551 cdb[8] = xferlen&0xff;
552 data_size = xferlen*512;
554 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
556 printf("SCSI_IO failed\n");
559 if (!check_sense(sc, op->status)) {
560 printf("[%d] READ10 \"%s\" failed (0x%02x) - expected %s\n",
561 op->child->line, op->fname, sc, op->status);
565 op->child->bytes += xferlen*512;
569 static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
571 struct iscsi_device *sd;
572 unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
574 int lba = op->params[0];
575 int pmi = op->params[1];
576 unsigned int data_size=8;
577 char data[data_size];
580 cdb[2] = (lba>>24)&0xff;
581 cdb[3] = (lba>>16)&0xff;
582 cdb[4] = (lba>> 8)&0xff;
583 cdb[5] = (lba )&0xff;
587 sd = op->child->private;
589 res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
591 printf("SCSI_IO failed\n");
594 if (!check_sense(sc, op->status)) {
595 printf("[%d] READCAPACITY10 \"%s\" failed (0x%02x) - expected %s\n",
596 op->child->line, op->fname, sc, op->status);
601 *blocks = (data[0]&0xff)<<24;
602 *blocks |= (data[1]&0xff)<<16;
603 *blocks |= (data[2]&0xff)<<8;
604 *blocks |= (data[3]&0xff);
608 /* <service action> <type> <key> <sa-key>*/
609 static void iscsi_prout(struct dbench_op *op)
611 struct iscsi_device *sd;
613 unsigned char cdb[10];
614 char parameters[PARAMETERS_SIZE];
616 unsigned int data_size = PARAMETERS_SIZE;
617 u_int64_t sa, type, key, sakey;
620 type = op->params[1];
622 sakey = op->params[3];
624 bzero(parameters, PARAMETERS_SIZE);
627 /* Persistent Reserve OUT */
629 /* Registering a key */
632 cdb[2] |= (PROUT_SCOPE_LU_SCOPE<<4) & 0xf0;
633 cdb[2] |= type & 0x0f;
635 /* Parameters size */
636 cdb[8] = PARAMETERS_SIZE;
638 /* splitting 64 bits in 8 blocks of 8 */
639 for (i = 0; i <= 7; i++) {
640 parameters[i] = (char) ((key >> 56) & 0xff);
643 parameters[i+8] = (char) ((sakey >> 56) & 0xff);
647 sd = op->child->private;
649 i = do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size,
652 printf("SCSI_IO failed\n");
656 if (!check_sense(sc, op->status)) {
657 printf("[%d] PROUT \"%s\" failed (0x%02x) - expected %s\n",
658 op->child->line, op->fname, sc, op->status);
663 static void iscsi_readcapacity10(struct dbench_op *op)
665 return local_iscsi_readcapacity10(op, NULL);
668 static void iscsi_setup(struct child_struct *child)
670 struct iscsi_device *sd;
671 struct sockaddr_in sin;
672 struct dbench_op fake_op;
674 sd = malloc(sizeof(struct iscsi_device));
676 printf("Failed to allocate iscsi device structure\n");
681 sd->portal=options.iscsi_portal;
682 sd->target=options.iscsi_target;
683 sd->isid =0x0000800000000000ULL | child->id;
684 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
686 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
690 sin.sin_family = AF_INET;
691 sin.sin_port = htons(options.iscsi_port);
692 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
693 printf("Failed to convert \"%s\" into an address\n", sd->portal);
697 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
698 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
705 if (iscsi_login(child, sd) != 0) {
706 printf("Failed to log in to target.\n");
712 iscsi_testunitready(&fake_op);
717 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
721 static void iscsi_cleanup(struct child_struct *child)
723 struct iscsi_device *sd;
731 static int iscsi_init(void)
733 struct iscsi_device *sd;
734 struct sockaddr_in sin;
735 struct dbench_op fake_op;
736 struct child_struct child;
738 sd = malloc(sizeof(struct iscsi_device));
740 printf("Failed to allocate iscsi device structure\n");
746 sd->portal=options.iscsi_portal;
747 sd->target=options.iscsi_target;
748 sd->isid =0x0000800000000000ULL | child.id;
749 sd->s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
751 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
755 sin.sin_family = AF_INET;
756 sin.sin_port = htons(options.iscsi_port);
757 if (inet_pton(AF_INET, sd->portal, &sin.sin_addr) != 1) {
758 printf("Failed to convert \"%s\" into an address\n", sd->portal);
762 if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
763 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
770 if (iscsi_login(&child, sd) != 0) {
771 printf("Failed to log in to target.\n");
775 fake_op.child=&child;
777 iscsi_testunitready(&fake_op);
782 local_iscsi_readcapacity10(&fake_op, &sd->blocks);
791 static struct backend_op ops[] = {
792 { "TESTUNITREADY", iscsi_testunitready },
793 { "READ10", iscsi_read10 },
794 { "READCAPACITY10", iscsi_readcapacity10 },
795 { "PROUT", iscsi_prout },
796 { "WRITE10", iscsi_write10 },
800 struct nb_operations iscsi_ops = {
801 .backend_name = "iscsibench",
803 .setup = iscsi_setup,
804 .cleanup = iscsi_cleanup,