rename the nfs_2 loadfile from .load to .txt
[amitay/dbench.git] / iscsi.c
1 /* 
2    Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2009
3    
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.
8    
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.
13    
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/>.
16 */
17 #include "dbench.h"
18
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <stdint.h>
23 #include <arpa/inet.h>
24
25 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
26
27 #ifndef SG_DXFER_NONE
28 #define SG_DXFER_NONE -1
29 #endif
30 #ifndef SG_DXFER_TO_DEV
31 #define SG_DXFER_TO_DEV -2
32 #endif
33 #ifndef SG_DXFER_FROM_DEV
34 #define SG_DXFER_FROM_DEV -3
35 #endif
36 #define PARAMETERS_SIZE 24
37 #define PROUT_CMD 0x5F
38 #define PROUT_SCOPE_LU_SCOPE 0x0
39
40 struct iscsi_device {
41        const char *portal;
42        const char *target;
43        int s;
44        uint64_t isid;
45        uint64_t blocks;
46        uint32_t itt;
47        uint32_t cmd_sn;
48        uint32_t exp_stat_sn;
49 };
50
51
52 void set_nonblocking(int fd)
53 {
54         unsigned v;
55         v = fcntl(fd, F_GETFL, 0);
56         fcntl(fd, F_SETFL, v | O_NONBLOCK);
57 }
58
59
60 struct login_param {
61        struct login_param *next;
62        char *arg;
63        char *value;
64 };
65 struct login_param *login_params;
66
67 static void add_login_param(char *arg, char *value)
68 {
69         struct login_param *new_param;
70
71         new_param = malloc(sizeof(struct login_param));
72         if (new_param == NULL) {
73                 printf("Failed to allocate login param struct\n");
74                 exit(10);
75         }
76         new_param->arg   = strdup(arg);
77         new_param->value = strdup(value);
78         new_param->next  = login_params;
79         login_params     = new_param;
80 }
81
82 static int send_iscsi_pdu(struct iscsi_device *sd, char *ish, char *data, int len)
83 {
84         char *buf, *ptr;
85         ssize_t remaining, count;
86
87         /* itt */
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;
92
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;
98
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;
104
105         buf=malloc(48+len+4);
106         if (buf == NULL) {
107                 printf("Failed to allocate buffer for PDU of size %d bytes\n", 48+len);
108                 return -1;
109         }
110
111         memcpy(buf, ish, 48);
112         if (len > 0) {
113                 memcpy(buf+48, data, len);
114         }
115         remaining = 48 + len;
116         remaining = (remaining+3)&0xfffffc;
117         ptr = buf;
118         while(remaining > 0) {
119                 count = write(sd->s, ptr, remaining);
120                 if (count == -1) {
121                         printf("Write to socket failed with errno %d(%s)\n", errno, strerror(errno));
122                         free(buf);
123                         return -1;
124                 }
125                 remaining-= count;
126         }
127
128         free(buf);
129         return 0;
130 }
131
132 static int wait_for_pdu(struct iscsi_device *sd, char *ish, char *data, unsigned int *data_size)
133 {
134         char *buf, *ptr;
135         ssize_t total, remaining, count;
136         unsigned int itt, dsl;
137         uint32_t ecsn, ssn;
138
139         remaining = 48;
140         ptr = ish;
141         while (remaining > 0) {
142                 count = read(sd->s, ptr, remaining);
143                 if (count == -1) {
144                         printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
145                         return -1;
146                 }
147                 remaining-= count;
148                 ptr += count;
149         }
150
151         /* verify the itt */
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);
158                 exit(10);
159         } 
160
161         /* data segment length */
162         dsl  = (ish[5]&0xff)<<16;
163         dsl |= (ish[6]&0xff)<<8;
164         dsl |= (ish[7]&0xff);
165
166         total = (dsl+3)&0xfffffffc;
167         remaining = total;
168         buf = malloc(remaining);
169         if (buf == NULL) {
170                 printf("Failed to alloc buf to read data into\n");
171                 return -1;
172         }
173         ptr = buf;
174         while (remaining > 0) {
175                 count = read(sd->s, ptr, remaining);
176
177                 if (count == -1) {
178                         printf("Read from socket failed with errno %d(%s)\n", errno, strerror(errno));
179                         return -1;
180                 }
181                 remaining-= count;
182                 ptr += count;
183         }
184
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;
191
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);
197         sd->cmd_sn = ecsn;
198
199         if (ish[0]&0x3f) {
200                 unsigned long int buffer_offset;
201
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);
206
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) {
211                                         *data_size = total;
212                                 }
213                                 if (data) {
214                                         memcpy(data, buf, *data_size);
215                                 }
216                         }
217                 }
218         }
219
220         free(buf);
221         return 0;
222 }
223
224 static int iscsi_login(struct child_struct *child, struct iscsi_device *sd)
225 {
226         char name[256];
227         char alias[256];
228         char ish[48];
229         int len;
230         struct login_param *login_param;
231         char *data, *ptr;
232
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);
251
252
253         bzero(ish, 48);
254         /* opcode : LOGIN REQUEST (I) */
255         ish[0] = 0x43;
256
257         /* T CSG:op NSG:full feature */
258         ish[1] = 0x87;
259
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);
263                 len += 1;
264                 len += strlen(login_param->value);
265                 len += 1;
266         }
267         /* data segment length */
268         ish[5] = (len>>16)&0xff;
269         ish[6] = (len>> 8)&0xff;
270         ish[7] = (len    )&0xff;
271
272
273         /* isid */
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;
280         
281         data = malloc(len);
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);
285                 *ptr='=';
286                 ptr++;
287                 strcpy(ptr,login_param->value);
288                 ptr+=strlen(login_param->value);
289                 *ptr=0;
290                 ptr++;
291         }
292
293         if (send_iscsi_pdu(sd, ish, data, len) != 0) {
294                 printf("Failed to send iscsi pdu\n");
295                 return -1;
296         }
297
298         if (wait_for_pdu(sd, ish, NULL, NULL) != 0) {
299                 printf("Failed to send iscsi pdu\n");
300                 return -1;
301         }
302
303
304
305         free(data);
306         return 0;
307 }
308
309
310
311
312
313
314
315
316
317
318
319 /* XXX merge with scsi.c */
320 static int check_sense(unsigned char sc, const char *expected)
321 {
322         if (strcmp(expected, "*") == 0){
323                 return 1;
324         }
325         if (strncmp(expected, "0x", 2) == 0) {
326                 return sc == strtol(expected, NULL, 16);
327         }
328         return 0;
329 }
330 static void failed(struct child_struct *child)
331 {
332         child->failed = 1;
333         printf("ERROR: child %d failed at line %d\n", child->id, child->line);
334         exit(1);
335 }
336
337
338
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)
340 {
341         char ish[48];
342         int data_in_len=0, data_out_len=0;
343
344         bzero(ish, 48);
345
346         /* opcode : SCSI command */
347         ish[0] = 0x01;
348
349         /* flags */
350         ish[1] = 0x81; /* F + SIMPLE */
351         if (xfer_dir == SG_DXFER_FROM_DEV) {
352                 ish[1] |= 0x40;
353                 data_in_len= *data_size;
354                 data_out_len=0;
355         }
356         if (xfer_dir == SG_DXFER_TO_DEV) {
357                 ish[1] |= 0x20;
358
359                 /* data segment length */
360                 ish[5] = ((*data_size)>>16)&0xff;
361                 ish[6] = ((*data_size)>> 8)&0xff;
362                 ish[7] = ((*data_size)    )&0xff;
363
364                 data_in_len=0;
365                 data_out_len=*data_size;
366         }
367
368         /* lun */
369         ish[9] = options.iscsi_lun;
370
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;
376
377         /* cdb */
378         memcpy(ish+32, cdb, cdb_size);
379
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");
383                 return -1;
384         }
385
386 need_more_data:
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");
390                 return -1;
391         }
392
393         switch (ish[0]&0x3f) {
394         case 0x21: /* SCSI response */
395                 if (ish[2] != 0) {
396                         printf("SCSI Response %d\n", ish[2]);
397                         sd->itt++;
398                         return -1;
399                 }
400                 if (ish[3] == 0) {
401                         *sc = 0;
402                         sd->itt++;
403                         return 0;
404                 }
405                 if (ish[3] == 2) {
406                         *sc = 2;
407                         sd->itt++;
408                         return 0;
409                 }
410                 if (ish[3] == 0x18) {
411                         /* reservation conflict */
412                         *sc = 0x18;
413                         sd->itt++;
414                         return 0;
415                 }
416                 break;
417         case 0x25: /* SCSI Data-In */
418                 if (ish[1]&0x01) {
419                         *sc = ish[3];
420                         sd->itt++;
421                         return 0;
422                 }
423                 /* no sbit, it means there is more data to read */
424                 goto need_more_data;
425                 break;
426         default:
427                 printf("got unsupported PDU:0x%02x\n", ish[0]&0x3f);
428         }
429
430         *sc = 0;
431         sd->itt++;
432         return 0;
433 }
434
435 static void iscsi_testunitready(struct dbench_op *op)
436 {
437         struct iscsi_device *sd;
438         unsigned char cdb[]={0,0,0,0,0,0};
439         int res;
440         unsigned char sc;
441         unsigned int data_size=0;
442
443         sd = op->child->private;
444
445         res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_NONE, &data_size, NULL, &sc);
446         if(res){
447                 printf("SCSI_IO failed\n");
448                 failed(op->child);
449         }
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);
453                 failed(op->child);
454         }
455         return;
456 }
457
458 static void iscsi_read10(struct dbench_op *op)
459 {
460         struct iscsi_device *sd=op->child->private;
461         unsigned char cdb[]={0x28,0,0,0,0,0,0,0,0,0};
462         int res;
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];
469         unsigned char sc;
470
471         lba = (lba / xferlen) * xferlen;
472
473         /* make sure we wrap properly instead of failing if the loadfile
474            is bigger than our device
475         */
476         if (sd->blocks <= lba) {
477                 lba = lba%sd->blocks;
478         }
479         if (sd->blocks <= lba+xferlen) {
480                 xferlen=1;
481         }
482
483         cdb[1] = rd;
484
485         cdb[2] = (lba>>24)&0xff;
486         cdb[3] = (lba>>16)&0xff;
487         cdb[4] = (lba>> 8)&0xff;
488         cdb[5] = (lba    )&0xff;
489
490         cdb[6] = grp&0x1f;
491
492         cdb[7] = (xferlen>>8)&0xff;
493         cdb[8] = xferlen&0xff;
494         data_size = xferlen*512;
495
496         res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
497         if(res){
498                 printf("SCSI_IO failed\n");
499                 failed(op->child);
500         }
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);
504                 failed(op->child);
505         }
506
507         op->child->bytes += xferlen*512;
508 }
509
510
511 static void iscsi_write10(struct dbench_op *op)
512 {
513         struct iscsi_device *sd=op->child->private;
514         unsigned char cdb[]={0x2a,0,0,0,0,0,0,0,0,0};
515         int res;
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];
522         unsigned char sc;
523
524         if (!options.allow_scsi_writes) {
525                 printf("WRITE10 command in loadfile but --allow-scsi-writes not specified. Aborting.\n");
526                 failed(op->child);
527         }
528
529         lba = (lba / xferlen) * xferlen;
530
531         /* make sure we wrap properly instead of failing if the loadfile
532            is bigger than our device
533         */
534         if (sd->blocks <= lba) {
535                 lba = lba%sd->blocks;
536         }
537         if (sd->blocks <= lba+xferlen) {
538                 xferlen=1;
539         }
540
541         cdb[1] = fua;
542
543         cdb[2] = (lba>>24)&0xff;
544         cdb[3] = (lba>>16)&0xff;
545         cdb[4] = (lba>> 8)&0xff;
546         cdb[5] = (lba    )&0xff;
547
548         cdb[6] = grp&0x1f;
549
550         cdb[7] = (xferlen>>8)&0xff;
551         cdb[8] = xferlen&0xff;
552         data_size = xferlen*512;
553
554         res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size, data, &sc);
555         if(res){
556                 printf("SCSI_IO failed\n");
557                 failed(op->child);
558         }
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);
562                 failed(op->child);
563         }
564
565         op->child->bytes += xferlen*512;
566 }
567
568
569 static void local_iscsi_readcapacity10(struct dbench_op *op, uint64_t *blocks)
570 {
571         struct iscsi_device *sd;
572         unsigned char cdb[]={0x25,0,0,0,0,0,0,0,0,0};
573         int res;
574         int lba = op->params[0];
575         int pmi = op->params[1];
576         unsigned int data_size=8;
577         char data[data_size];
578         unsigned char sc;
579
580         cdb[2] = (lba>>24)&0xff;
581         cdb[3] = (lba>>16)&0xff;
582         cdb[4] = (lba>> 8)&0xff;
583         cdb[5] = (lba    )&0xff;
584
585         cdb[8] = (pmi?1:0);
586
587         sd = op->child->private;
588
589         res=do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_FROM_DEV, &data_size, data, &sc);
590         if(res){
591                 printf("SCSI_IO failed\n");
592                 failed(op->child);
593         }
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);
597                 failed(op->child);
598         }
599
600         if (blocks) {
601                 *blocks  = (data[0]&0xff)<<24;
602                 *blocks |= (data[1]&0xff)<<16;
603                 *blocks |= (data[2]&0xff)<<8;
604                 *blocks |= (data[3]&0xff);
605         }
606 }
607
608 /* <service action> <type> <key> <sa-key>*/
609 static void iscsi_prout(struct dbench_op *op)
610 {
611         struct iscsi_device *sd;
612         unsigned char sc;
613         unsigned char cdb[10];
614         char parameters[PARAMETERS_SIZE];
615         int i;
616         unsigned int data_size = PARAMETERS_SIZE;
617         u_int64_t sa, type, key, sakey;
618
619         sa = op->params[0];
620         type = op->params[1];
621         key = op->params[2];
622         sakey = op->params[3];
623
624         bzero(parameters, PARAMETERS_SIZE);
625         bzero(cdb, 10);
626
627         /* Persistent Reserve OUT */
628         cdb[0] = PROUT_CMD;
629         /* Registering a key */
630         cdb[1] |= sa & 0x1f;
631
632         cdb[2] |= (PROUT_SCOPE_LU_SCOPE<<4) & 0xf0;
633         cdb[2] |= type & 0x0f;
634
635         /* Parameters size */
636         cdb[8] = PARAMETERS_SIZE;
637
638         /* splitting 64 bits in 8 blocks of 8 */
639         for (i = 0; i <= 7; i++) {
640                 parameters[i] = (char) ((key >> 56) & 0xff);
641                 key <<= 8;
642
643                 parameters[i+8] = (char) ((sakey >> 56) & 0xff);
644                 sakey <<= 8;
645         }
646
647         sd = op->child->private;
648
649         i = do_iscsi_io(sd, cdb, sizeof(cdb), SG_DXFER_TO_DEV, &data_size,
650                            parameters, &sc);
651         if (i) {
652                 printf("SCSI_IO failed\n");
653                 failed(op->child);
654         }
655
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);
659                         failed(op->child);
660         }
661 }
662
663 static void iscsi_readcapacity10(struct dbench_op *op)
664 {
665         return local_iscsi_readcapacity10(op, NULL);
666 }
667
668 static void iscsi_setup(struct child_struct *child)
669 {
670         struct iscsi_device *sd;
671         struct sockaddr_in sin;
672         struct dbench_op fake_op;
673
674         sd = malloc(sizeof(struct iscsi_device));
675         if (sd == NULL) {
676                 printf("Failed to allocate iscsi device structure\n");
677                 exit(10);
678         }
679         child->private=sd;
680
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);
685         if (sd->s == -1) {
686                 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
687                 exit(10);
688         }
689
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);
694                 exit(10);
695         }
696
697         if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
698                 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
699                 exit(10);
700         }
701
702         sd->itt=0x000a0000;
703         sd->cmd_sn=0;
704         sd->exp_stat_sn=0;
705         if (iscsi_login(child, sd) != 0) {
706                 printf("Failed to log in to target.\n");
707                 exit(10);
708         }
709
710         fake_op.child=child;
711         fake_op.status="*";
712         iscsi_testunitready(&fake_op);
713
714         fake_op.params[0]=0;
715         fake_op.params[1]=0;
716         fake_op.status="*";
717         local_iscsi_readcapacity10(&fake_op, &sd->blocks);
718 }
719
720        
721 static void iscsi_cleanup(struct child_struct *child)
722 {
723         struct iscsi_device *sd;
724
725         sd=child->private;
726         close(sd->s);
727         sd->s=-1;
728         free(sd);
729 }
730
731 static int iscsi_init(void)
732 {
733         struct iscsi_device *sd;
734         struct sockaddr_in sin;
735         struct dbench_op fake_op;
736         struct child_struct child;
737
738         sd = malloc(sizeof(struct iscsi_device));
739         if (sd == NULL) {
740                 printf("Failed to allocate iscsi device structure\n");
741                 return 1;
742         }
743         child.private=sd;
744         child.id=99999;
745
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);
750         if (sd->s == -1) {
751                 printf("could not open socket() errno:%d(%s)\n", errno, strerror(errno));
752                 return 1;
753         }
754
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);
759                 return 1;
760         }
761
762         if (connect(sd->s, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
763                 printf("connect failed with errno:%d(%s)\n", errno, strerror(errno));
764                 return 1;
765         }
766
767         sd->itt=0x000a0000;
768         sd->cmd_sn=0;
769         sd->exp_stat_sn=0;
770         if (iscsi_login(&child, sd) != 0) {
771                 printf("Failed to log in to target.\n");
772                 return 1;
773         }
774
775         fake_op.child=&child;
776         fake_op.status="*";
777         iscsi_testunitready(&fake_op);
778
779         fake_op.params[0]=0;
780         fake_op.params[1]=0;
781         fake_op.status="*";
782         local_iscsi_readcapacity10(&fake_op, &sd->blocks);
783
784         close(sd->s);
785         free(sd);
786
787         return 0;
788 }
789
790
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 },
797         { NULL, NULL}
798 };
799
800 struct nb_operations iscsi_ops = {
801         .backend_name = "iscsibench",
802         .init         = iscsi_init,
803         .setup        = iscsi_setup,
804         .cleanup      = iscsi_cleanup,
805         .ops          = ops
806 };
807
808