1171568Sscottl/*- 2211095Sdes * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il> 3171568Sscottl * All rights reserved. 4171568Sscottl * 5171568Sscottl * Redistribution and use in source and binary forms, with or without 6171568Sscottl * modification, are permitted provided that the following conditions 7171568Sscottl * are met: 8171568Sscottl * 1. Redistributions of source code must retain the above copyright 9171568Sscottl * notice, this list of conditions and the following disclaimer. 10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11171568Sscottl * notice, this list of conditions and the following disclaimer in the 12171568Sscottl * documentation and/or other materials provided with the distribution. 13171568Sscottl * 14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17171568Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24171568Sscottl * SUCH DAMAGE. 25171568Sscottl * 26171568Sscottl */ 27171568Sscottl 28171568Sscottl/* 29171568Sscottl | $Id: fsm.c,v 2.8 2007/05/19 16:34:21 danny Exp danny $ 30171568Sscottl */ 31171568Sscottl 32171568Sscottl#include <sys/cdefs.h> 33171568Sscottl__FBSDID("$FreeBSD$"); 34171568Sscottl 35171568Sscottl#include <sys/param.h> 36171568Sscottl#include <sys/types.h> 37171568Sscottl#include <sys/socket.h> 38171568Sscottl#include <sys/sysctl.h> 39171568Sscottl 40171568Sscottl#include <netinet/in.h> 41171568Sscottl#include <netinet/tcp.h> 42171568Sscottl#include <arpa/inet.h> 43171568Sscottl#include <sys/ioctl.h> 44171568Sscottl#include <netdb.h> 45171568Sscottl#include <stdlib.h> 46171568Sscottl#include <unistd.h> 47171568Sscottl#include <stdio.h> 48171568Sscottl#include <string.h> 49171568Sscottl#include <errno.h> 50171568Sscottl#include <fcntl.h> 51171568Sscottl#include <time.h> 52171568Sscottl#include <syslog.h> 53171568Sscottl#include <stdarg.h> 54171568Sscottl#include <camlib.h> 55171568Sscottl 56211095Sdes#include <dev/iscsi/initiator/iscsi.h> 57171568Sscottl#include "iscontrol.h" 58171568Sscottl 59171568Sscottltypedef enum { 60171568Sscottl T1 = 1, 61171568Sscottl T2, /*T3,*/ T4, T5, /*T6,*/ T7, T8, T9, 62171568Sscottl T10, T11, T12, T13, T14, T15, T16, T18 63171568Sscottl} trans_t; 64171568Sscottl 65185289Sscottl/* 66185289Sscottl | now supports IPV6 67185289Sscottl | thanks to: 68185289Sscottl | Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan 69185289Sscottl | ume@mahoroba.org ume@{,jp.}FreeBSD.org 70185289Sscottl | http://www.imasy.org/~ume/ 71185289Sscottl */ 72171568Sscottlstatic trans_t 73171568SscottltcpConnect(isess_t *sess) 74171568Sscottl{ 75171568Sscottl isc_opt_t *op = sess->op; 76185289Sscottl int val, sv_errno, soc; 77185289Sscottl struct addrinfo *res, *res0, hints; 78185289Sscottl char pbuf[10]; 79171568Sscottl 80171568Sscottl debug_called(3); 81171568Sscottl if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) { 82171568Sscottl syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT) 83171568Sscottl ? "Reconnect": "Redirected"); 84171568Sscottl 85185289Sscottl debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected"); 86171568Sscottl shutdown(sess->soc, SHUT_RDWR); 87171568Sscottl //close(sess->soc); 88171568Sscottl sess->soc = -1; 89171568Sscottl 90171568Sscottl sess->flags &= ~SESS_CONNECTED; 91171568Sscottl if(sess->flags & SESS_REDIRECT) { 92185289Sscottl sess->redirect_cnt++; 93171568Sscottl sess->flags |= SESS_RECONNECT; 94185289Sscottl } else 95185289Sscottl sleep(2); // XXX: actually should be ? 96185289Sscottl#ifdef notyet 97185289Sscottl { 98185289Sscottl time_t sec; 99211095Sdes // make sure we are not in a loop 100211095Sdes // XXX: this code has to be tested 101211095Sdes sec = time(0) - sess->reconnect_time; 102211095Sdes if(sec > (5*60)) { 103211095Sdes // if we've been connected for more that 5 minutes 104211095Sdes // then just reconnect 105211095Sdes sess->reconnect_time = sec; 106211095Sdes sess->reconnect_cnt1 = 0; 107171568Sscottl } 108211095Sdes else { 109211095Sdes // 110211095Sdes sess->reconnect_cnt1++; 111211095Sdes if((sec / sess->reconnect_cnt1) < 2) { 112211095Sdes // if less that 2 seconds from the last reconnect 113211095Sdes // we are most probably looping 114211095Sdes syslog(LOG_CRIT, "too many reconnects %d", sess->reconnect_cnt1); 115211095Sdes return 0; 116211095Sdes } 117211095Sdes } 118171568Sscottl } 119185289Sscottl#endif 120171568Sscottl sess->reconnect_cnt++; 121171568Sscottl } 122171568Sscottl 123185289Sscottl snprintf(pbuf, sizeof(pbuf), "%d", op->port); 124171568Sscottl memset(&hints, 0, sizeof(hints)); 125185289Sscottl hints.ai_family = PF_UNSPEC; 126171568Sscottl hints.ai_socktype = SOCK_STREAM; 127185289Sscottl debug(1, "targetAddress=%s port=%d", op->targetAddress, op->port); 128185289Sscottl if((val = getaddrinfo(op->targetAddress, pbuf, &hints, &res0)) != 0) { 129171568Sscottl fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val)); 130171568Sscottl return 0; 131171568Sscottl } 132185289Sscottl sess->flags &= ~SESS_CONNECTED; 133185289Sscottl sv_errno = 0; 134185289Sscottl soc = -1; 135185289Sscottl for(res = res0; res; res = res->ai_next) { 136185289Sscottl soc = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 137185289Sscottl if (soc == -1) 138185289Sscottl continue; 139171568Sscottl 140211095Sdes // from Patrick.Guelat@imp.ch: 141211095Sdes // iscontrol can be called without waiting for the socket entry to time out 142211095Sdes val = 1; 143185289Sscottl if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) { 144211095Sdes fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n", 145211095Sdes errno, strerror(errno)); 146211095Sdes } 147171568Sscottl 148185289Sscottl if(connect(soc, res->ai_addr, res->ai_addrlen) == 0) 149185289Sscottl break; 150185289Sscottl sv_errno = errno; 151185289Sscottl close(soc); 152185289Sscottl soc = -1; 153185289Sscottl } 154185289Sscottl freeaddrinfo(res0); 155185289Sscottl if(soc != -1) { 156185289Sscottl sess->soc = soc; 157171568Sscottl 158171568Sscottl#if 0 159171568Sscottl struct timeval timeout; 160171568Sscottl 161171568Sscottl val = 1; 162171568Sscottl if(setsockopt(sess->soc, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) 163171568Sscottl fprintf(stderr, "Cannot set socket KEEPALIVE option err=%d %s\n", 164171568Sscottl errno, strerror(errno)); 165171568Sscottl 166171568Sscottl if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0) 167171568Sscottl fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n", 168171568Sscottl errno, strerror(errno)); 169171568Sscottl 170171568Sscottl timeout.tv_sec = 10; 171171568Sscottl timeout.tv_usec = 0; 172171568Sscottl if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) 173171568Sscottl || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)) { 174171568Sscottl fprintf(stderr, "Cannot set socket timeout to %ld err=%d %s\n", 175171568Sscottl timeout.tv_sec, errno, strerror(errno)); 176171568Sscottl } 177171568Sscottl#endif 178171568Sscottl#ifdef CURIOUS 179171568Sscottl { 180171568Sscottl int len = sizeof(val); 181171568Sscottl if(getsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0) 182171568Sscottl fprintf(stderr, "was: SO_SNDBUF=%dK\n", val/1024); 183171568Sscottl } 184171568Sscottl#endif 185171568Sscottl if(sess->op->sockbufsize) { 186171568Sscottl val = sess->op->sockbufsize * 1024; 187171568Sscottl if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0) 188171568Sscottl || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)) { 189171568Sscottl fprintf(stderr, "Cannot set socket sndbuf & rcvbuf to %d err=%d %s\n", 190171568Sscottl val, errno, strerror(errno)); 191171568Sscottl return 0; 192171568Sscottl } 193171568Sscottl } 194171568Sscottl sess->flags |= SESS_CONNECTED; 195171568Sscottl return T1; 196211095Sdes } 197171568Sscottl 198171568Sscottl fprintf(stderr, "errno=%d\n", sv_errno); 199171568Sscottl perror("connect"); 200171568Sscottl switch(sv_errno) { 201171568Sscottl case ECONNREFUSED: 202171568Sscottl case ENETUNREACH: 203171568Sscottl case ETIMEDOUT: 204185289Sscottl if((sess->flags & SESS_REDIRECT) == 0) { 205185289Sscottl if(strcmp(op->targetAddress, sess->target.address) != 0) { 206185289Sscottl syslog(LOG_INFO, "reconnecting to original target address"); 207185289Sscottl free(op->targetAddress); 208185289Sscottl op->targetAddress = sess->target.address; 209185289Sscottl op->port = sess->target.port; 210185289Sscottl op->targetPortalGroupTag = sess->target.pgt; 211185289Sscottl return T1; 212185289Sscottl } 213185289Sscottl } 214171568Sscottl sleep(5); // for now ... 215171568Sscottl return T1; 216171568Sscottl default: 217171568Sscottl return 0; // terminal error 218171568Sscottl } 219171568Sscottl} 220171568Sscottl 221171568Sscottlint 222171568SscottlsetOptions(isess_t *sess, int flag) 223171568Sscottl{ 224171568Sscottl isc_opt_t oop; 225171568Sscottl char *sep; 226171568Sscottl 227171568Sscottl debug_called(3); 228171568Sscottl 229171568Sscottl bzero(&oop, sizeof(isc_opt_t)); 230171568Sscottl 231171568Sscottl if((flag & SESS_FULLFEATURE) == 0) { 232171568Sscottl oop.initiatorName = sess->op->initiatorName; 233171568Sscottl oop.targetAddress = sess->op->targetAddress; 234171568Sscottl if(sess->op->targetName != 0) 235171568Sscottl oop.targetName = sess->op->targetName; 236171568Sscottl 237171568Sscottl oop.maxRecvDataSegmentLength = sess->op->maxRecvDataSegmentLength; 238171568Sscottl oop.maxXmitDataSegmentLength = sess->op->maxXmitDataSegmentLength; // XXX: 239171568Sscottl oop.maxBurstLength = sess->op->maxBurstLength; 240171568Sscottl oop.maxluns = sess->op->maxluns; 241171568Sscottl } 242171568Sscottl else { 243171568Sscottl /* 244171568Sscottl | turn on digestion only after login 245171568Sscottl */ 246171568Sscottl if(sess->op->headerDigest != NULL) { 247171568Sscottl sep = strchr(sess->op->headerDigest, ','); 248171568Sscottl if(sep == NULL) 249171568Sscottl oop.headerDigest = sess->op->headerDigest; 250171568Sscottl debug(1, "oop.headerDigest=%s", oop.headerDigest); 251171568Sscottl } 252171568Sscottl if(sess->op->dataDigest != NULL) { 253171568Sscottl sep = strchr(sess->op->dataDigest, ','); 254171568Sscottl if(sep == NULL) 255171568Sscottl oop.dataDigest = sess->op->dataDigest; 256171568Sscottl debug(1, "oop.dataDigest=%s", oop.dataDigest); 257171568Sscottl } 258171568Sscottl } 259171568Sscottl 260171568Sscottl if(ioctl(sess->fd, ISCSISETOPT, &oop)) { 261171568Sscottl perror("ISCSISETOPT"); 262171568Sscottl return -1; 263171568Sscottl } 264171568Sscottl return 0; 265171568Sscottl} 266171568Sscottl 267171568Sscottlstatic trans_t 268171568SscottlstartSession(isess_t *sess) 269171568Sscottl{ 270171568Sscottl 271171568Sscottl int n, fd, nfd; 272171568Sscottl char *dev; 273171568Sscottl 274171568Sscottl debug_called(3); 275171568Sscottl 276171568Sscottl if((sess->flags & SESS_CONNECTED) == 0) { 277171568Sscottl return T2; 278171568Sscottl } 279171568Sscottl if(sess->fd == -1) { 280171568Sscottl fd = open(iscsidev, O_RDWR); 281171568Sscottl if(fd < 0) { 282171568Sscottl perror(iscsidev); 283171568Sscottl return 0; 284171568Sscottl } 285171568Sscottl { 286171568Sscottl // XXX: this has to go 287171568Sscottl size_t n; 288171568Sscottl n = sizeof(sess->isid); 289211095Sdes if(sysctlbyname("net.iscsi_initiator.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0) 290171568Sscottl perror("sysctlbyname"); 291171568Sscottl } 292171568Sscottl if(ioctl(fd, ISCSISETSES, &n)) { 293171568Sscottl perror("ISCSISETSES"); 294171568Sscottl return 0; 295171568Sscottl } 296171568Sscottl asprintf(&dev, "%s%d", iscsidev, n); 297171568Sscottl nfd = open(dev, O_RDWR); 298171568Sscottl if(nfd < 0) { 299171568Sscottl perror(dev); 300171568Sscottl free(dev); 301171568Sscottl return 0; 302171568Sscottl } 303171568Sscottl free(dev); 304171568Sscottl close(fd); 305171568Sscottl sess->fd = nfd; 306171568Sscottl 307171568Sscottl if(setOptions(sess, 0) != 0) 308171568Sscottl return -1; 309171568Sscottl } 310171568Sscottl 311171568Sscottl if(ioctl(sess->fd, ISCSISETSOC, &sess->soc)) { 312171568Sscottl perror("ISCSISETSOC"); 313171568Sscottl return 0; 314171568Sscottl } 315171568Sscottl 316171568Sscottl return T4; 317171568Sscottl} 318171568Sscottl 319171568Sscottlisess_t *currsess; 320171568Sscottl 321171568Sscottlstatic void 322171568Sscottltrap(int sig) 323171568Sscottl{ 324171568Sscottl syslog(LOG_NOTICE, "trapped signal %d", sig); 325171568Sscottl fprintf(stderr, "trapped signal %d\n", sig); 326171568Sscottl 327171568Sscottl switch(sig) { 328171568Sscottl case SIGHUP: 329171568Sscottl currsess->flags |= SESS_DISCONNECT; 330171568Sscottl break; 331171568Sscottl 332171568Sscottl case SIGUSR1: 333171568Sscottl currsess->flags |= SESS_RECONNECT; 334171568Sscottl break; 335171568Sscottl 336171568Sscottl case SIGINT: 337171568Sscottl case SIGTERM: 338171568Sscottl default: 339171568Sscottl return; // ignore 340171568Sscottl } 341171568Sscottl} 342171568Sscottl 343211095Sdesstatic int 344171568SscottldoCAM(isess_t *sess) 345171568Sscottl{ 346171568Sscottl char pathstr[1024]; 347171568Sscottl union ccb *ccb; 348211095Sdes int i, n; 349171568Sscottl 350171568Sscottl if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) { 351171568Sscottl syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno); 352211095Sdes return 0; 353171568Sscottl } 354211095Sdes debug(1, "nluns=%d", sess->cam.target_nluns); 355171568Sscottl /* 356171568Sscottl | for now will do this for each lun ... 357171568Sscottl */ 358211095Sdes for(n = i = 0; i < sess->cam.target_nluns; i++) { 359217859Scracauer debug(2, "CAM path_id=%d target_id=%d", 360217859Scracauer sess->cam.path_id, sess->cam.target_id); 361171568Sscottl 362171568Sscottl sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id, 363211095Sdes i, O_RDWR, NULL); 364171568Sscottl if(sess->camdev == NULL) { 365211095Sdes //syslog(LOG_WARNING, "%s", cam_errbuf); 366171568Sscottl debug(3, "%s", cam_errbuf); 367171568Sscottl continue; 368171568Sscottl } 369171568Sscottl 370171568Sscottl cam_path_string(sess->camdev, pathstr, sizeof(pathstr)); 371171568Sscottl debug(2, "pathstr=%s", pathstr); 372171568Sscottl 373171568Sscottl ccb = cam_getccb(sess->camdev); 374171568Sscottl bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr)); 375171568Sscottl ccb->ccb_h.func_code = XPT_REL_SIMQ; 376171568Sscottl ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; 377171568Sscottl ccb->crs.openings = sess->op->tags; 378171568Sscottl if(cam_send_ccb(sess->camdev, ccb) < 0) 379211095Sdes debug(2, "%s", cam_errbuf); 380171568Sscottl else 381171568Sscottl if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 382171568Sscottl syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed"); 383171568Sscottl // cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 384171568Sscottl } 385211095Sdes else { 386211095Sdes n++; 387171568Sscottl syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings); 388211095Sdes } 389171568Sscottl cam_freeccb(ccb); 390171568Sscottl cam_close_device(sess->camdev); 391171568Sscottl } 392211095Sdes return n; 393171568Sscottl} 394171568Sscottl 395171568Sscottlstatic trans_t 396171568Sscottlsupervise(isess_t *sess) 397171568Sscottl{ 398171568Sscottl int sig, val; 399171568Sscottl 400171568Sscottl debug_called(3); 401171568Sscottl 402171568Sscottl if(strcmp(sess->op->sessionType, "Discovery") == 0) { 403171568Sscottl sess->flags |= SESS_DISCONNECT; 404171568Sscottl return T9; 405171568Sscottl } 406171568Sscottl 407171568Sscottl if(vflag) 408171568Sscottl printf("ready to go scsi\n"); 409171568Sscottl 410171568Sscottl if(setOptions(sess, SESS_FULLFEATURE) != 0) 411171568Sscottl return 0; // failure 412171568Sscottl 413171568Sscottl if((sess->flags & SESS_FULLFEATURE) == 0) { 414171568Sscottl if(daemon(0, 1) != 0) { 415171568Sscottl perror("daemon"); 416171568Sscottl exit(1); 417171568Sscottl } 418211095Sdes if(sess->op->pidfile != NULL) { 419211095Sdes FILE *pidf; 420171568Sscottl 421211095Sdes pidf = fopen(sess->op->pidfile, "w"); 422211095Sdes if(pidf != NULL) { 423211095Sdes fprintf(pidf, "%d\n", getpid()); 424211095Sdes fclose(pidf); 425211095Sdes } 426211095Sdes } 427171568Sscottl openlog("iscontrol", LOG_CONS|LOG_PERROR|LOG_PID|LOG_NDELAY, LOG_KERN); 428171568Sscottl syslog(LOG_INFO, "running"); 429171568Sscottl 430171568Sscottl currsess = sess; 431171568Sscottl if(ioctl(sess->fd, ISCSISTART)) { 432171568Sscottl perror("ISCSISTART"); 433171568Sscottl return -1; 434171568Sscottl } 435211095Sdes if(doCAM(sess) == 0) { 436211095Sdes syslog(LOG_WARNING, "no device found"); 437211095Sdes ioctl(sess->fd, ISCSISTOP); 438211095Sdes return T15; 439211095Sdes } 440171568Sscottl 441171568Sscottl } 442171568Sscottl else { 443171568Sscottl if(ioctl(sess->fd, ISCSIRESTART)) { 444171568Sscottl perror("ISCSIRESTART"); 445171568Sscottl return -1; 446171568Sscottl } 447171568Sscottl } 448171568Sscottl 449171568Sscottl signal(SIGINT, trap); 450171568Sscottl signal(SIGHUP, trap); 451171568Sscottl signal(SIGTERM, trap); 452171568Sscottl 453171568Sscottl sig = SIGUSR1; 454171568Sscottl signal(sig, trap); 455171568Sscottl if(ioctl(sess->fd, ISCSISIGNAL, &sig)) { 456171568Sscottl perror("ISCSISIGNAL"); 457171568Sscottl return -1; 458171568Sscottl } 459171568Sscottl sess->flags |= SESS_FULLFEATURE; 460171568Sscottl 461171568Sscottl sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT); 462211095Sdes if(vflag) 463211095Sdes printf("iscontrol: supervise starting main loop\n"); 464171568Sscottl /* 465171568Sscottl | the main loop - actually do nothing 466171568Sscottl | all the work is done inside the kernel 467171568Sscottl */ 468171568Sscottl while((sess->flags & (SESS_REDIRECT|SESS_RECONNECT|SESS_DISCONNECT)) == 0) { 469171568Sscottl // do something? 470171568Sscottl // like sending a nop_out? 471171568Sscottl sleep(60); 472171568Sscottl } 473171568Sscottl printf("iscontrol: supervise going down\n"); 474171568Sscottl syslog(LOG_INFO, "sess flags=%x", sess->flags); 475171568Sscottl 476171568Sscottl sig = 0; 477171568Sscottl if(ioctl(sess->fd, ISCSISIGNAL, &sig)) { 478171568Sscottl perror("ISCSISIGNAL"); 479171568Sscottl } 480171568Sscottl 481171568Sscottl if(sess->flags & SESS_DISCONNECT) { 482211095Sdes sess->flags &= ~SESS_FULLFEATURE; 483211095Sdes return T9; 484211095Sdes } 485211095Sdes else { 486171568Sscottl val = 0; 487171568Sscottl if(ioctl(sess->fd, ISCSISTOP, &val)) { 488171568Sscottl perror("ISCSISTOP"); 489171568Sscottl } 490171568Sscottl sess->flags |= SESS_INITIALLOGIN1; 491171568Sscottl } 492171568Sscottl return T8; 493171568Sscottl} 494171568Sscottl 495171568Sscottlstatic int 496171568SscottlhandledDiscoveryResp(isess_t *sess, pdu_t *pp) 497171568Sscottl{ 498171568Sscottl u_char *ptr; 499171568Sscottl int len, n; 500171568Sscottl 501171568Sscottl debug_called(3); 502171568Sscottl 503171568Sscottl len = pp->ds_len; 504211095Sdes ptr = pp->ds_addr; 505171568Sscottl while(len > 0) { 506171568Sscottl if(*ptr != 0) 507171568Sscottl printf("%s\n", ptr); 508171568Sscottl n = strlen((char *)ptr) + 1; 509171568Sscottl len -= n; 510171568Sscottl ptr += n; 511171568Sscottl } 512171568Sscottl return 0; 513171568Sscottl} 514171568Sscottl 515171568Sscottlstatic int 516171568SscottldoDiscovery(isess_t *sess) 517171568Sscottl{ 518171568Sscottl pdu_t spp; 519171568Sscottl text_req_t *tp = (text_req_t *)&spp.ipdu.bhs; 520171568Sscottl 521171568Sscottl debug_called(3); 522171568Sscottl 523171568Sscottl bzero(&spp, sizeof(pdu_t)); 524171568Sscottl tp->cmd = ISCSI_TEXT_CMD /*| 0x40 */; // because of a bug in openiscsi-target 525171568Sscottl tp->F = 1; 526171568Sscottl tp->ttt = 0xffffffff; 527171568Sscottl addText(&spp, "SendTargets=All"); 528171568Sscottl return sendPDU(sess, &spp, handledDiscoveryResp); 529171568Sscottl} 530171568Sscottl 531171568Sscottlstatic trans_t 532171568SscottldoLogin(isess_t *sess) 533171568Sscottl{ 534171568Sscottl isc_opt_t *op = sess->op; 535171568Sscottl int status, count; 536171568Sscottl 537171568Sscottl debug_called(3); 538171568Sscottl 539171568Sscottl if(op->chapSecret == NULL && op->tgtChapSecret == NULL) 540171568Sscottl /* 541171568Sscottl | don't need any security negotiation 542171568Sscottl | or in other words: we don't have any secrets to exchange 543171568Sscottl */ 544171568Sscottl sess->csg = LON_PHASE; 545171568Sscottl else 546171568Sscottl sess->csg = SN_PHASE; 547171568Sscottl 548171568Sscottl if(sess->tsih) { 549171568Sscottl sess->tsih = 0; // XXX: no 'reconnect' yet 550171568Sscottl sess->flags &= ~SESS_NEGODONE; // XXX: KLUDGE 551171568Sscottl } 552171568Sscottl count = 10; // should be more than enough 553171568Sscottl do { 554171568Sscottl debug(3, "count=%d csg=%d", count, sess->csg); 555171568Sscottl status = loginPhase(sess); 556171568Sscottl if(count-- == 0) 557171568Sscottl // just in case we get into a loop 558171568Sscottl status = -1; 559171568Sscottl } while(status == 0 && (sess->csg != FF_PHASE)); 560171568Sscottl 561171568Sscottl sess->flags &= ~SESS_INITIALLOGIN; 562171568Sscottl debug(3, "status=%d", status); 563171568Sscottl 564171568Sscottl switch(status) { 565171568Sscottl case 0: // all is ok ... 566171568Sscottl sess->flags |= SESS_LOGGEDIN; 567171568Sscottl if(strcmp(sess->op->sessionType, "Discovery") == 0) 568171568Sscottl doDiscovery(sess); 569171568Sscottl return T5; 570171568Sscottl 571171568Sscottl case 1: // redirect - temporary/permanent 572171568Sscottl /* 573171568Sscottl | start from scratch? 574171568Sscottl */ 575171568Sscottl sess->flags &= ~SESS_NEGODONE; 576171568Sscottl sess->flags |= (SESS_REDIRECT | SESS_INITIALLOGIN1); 577171568Sscottl syslog(LOG_DEBUG, "target sent REDIRECT"); 578171568Sscottl return T7; 579171568Sscottl 580171568Sscottl case 2: // initiator terminal error 581185289Sscottl return 0; 582171568Sscottl case 3: // target terminal error -- could retry ... 583185289Sscottl sleep(5); 584185289Sscottl return T7; // lets try 585171568Sscottl default: 586171568Sscottl return 0; 587171568Sscottl } 588171568Sscottl} 589171568Sscottl 590171568Sscottlstatic int 591171568SscottlhandleLogoutResp(isess_t *sess, pdu_t *pp) 592171568Sscottl{ 593211095Sdes if(sess->flags & SESS_DISCONNECT) { 594211095Sdes int val = 0; 595211095Sdes if(ioctl(sess->fd, ISCSISTOP, &val)) { 596211095Sdes perror("ISCSISTOP"); 597211095Sdes } 598171568Sscottl return 0; 599211095Sdes } 600171568Sscottl return T13; 601171568Sscottl} 602171568Sscottl 603171568Sscottlstatic trans_t 604171568SscottlstartLogout(isess_t *sess) 605171568Sscottl{ 606171568Sscottl pdu_t spp; 607171568Sscottl logout_req_t *p = (logout_req_t *)&spp.ipdu.bhs; 608171568Sscottl 609171568Sscottl bzero(&spp, sizeof(pdu_t)); 610171568Sscottl p->cmd = ISCSI_LOGOUT_CMD| 0x40; 611171568Sscottl p->reason = BIT(7) | 0; 612171568Sscottl p->CID = htons(1); 613171568Sscottl 614171568Sscottl return sendPDU(sess, &spp, handleLogoutResp); 615171568Sscottl} 616171568Sscottl 617171568Sscottlstatic trans_t 618171568SscottlinLogout(isess_t *sess) 619171568Sscottl{ 620171568Sscottl if(sess->flags & SESS_RECONNECT) 621171568Sscottl return T18; 622171568Sscottl return 0; 623171568Sscottl} 624171568Sscottl 625171568Sscottltypedef enum { 626171568Sscottl S1, S2, /*S3,*/ S4, S5, S6, S7, S8 627171568Sscottl} state_t; 628171568Sscottl 629211095Sdes/** 630171568Sscottl S1: FREE 631171568Sscottl S2: XPT_WAIT 632171568Sscottl S4: IN_LOGIN 633171568Sscottl S5: LOGGED_IN 634171568Sscottl S6: IN_LOGOUT 635171568Sscottl S7: LOGOUT_REQUESTED 636171568Sscottl S8: CLEANUP_WAIT 637171568Sscottl 638171568Sscottl -------<-------------+ 639171568Sscottl +--------->/ S1 \<----+ | 640171568Sscottl T13| +->\ /<-+ \ | 641171568Sscottl | / ---+--- \ \ | 642171568Sscottl | / | T2 \ | | 643171568Sscottl | T8 | |T1 | | | 644171568Sscottl | | | / |T7 | 645171568Sscottl | | | / | | 646171568Sscottl | | | / | | 647171568Sscottl | | V / / | 648171568Sscottl | | ------- / / | 649171568Sscottl | | / S2 \ / | 650171568Sscottl | | \ / / | 651171568Sscottl | | ---+--- / | 652171568Sscottl | | |T4 / | 653171568Sscottl | | V / | T18 654171568Sscottl | | ------- / | 655171568Sscottl | | / S4 \ | 656171568Sscottl | | \ / | 657171568Sscottl | | ---+--- | T15 658171568Sscottl | | |T5 +--------+---------+ 659171568Sscottl | | | /T16+-----+------+ | 660171568Sscottl | | | / -+-----+--+ | | 661171568Sscottl | | | / / S7 \ |T12| | 662171568Sscottl | | | / +->\ /<-+ V V 663171568Sscottl | | | / / -+----- ------- 664171568Sscottl | | | / /T11 |T10 / S8 \ 665171568Sscottl | | V / / V +----+ \ / 666171568Sscottl | | ---+-+- ----+-- | ------- 667171568Sscottl | | / S5 \T9 / S6 \<+ ^ 668171568Sscottl | +-----\ /--->\ / T14 | 669171568Sscottl | ------- --+----+------+T17 670171568Sscottl +---------------------------+ 671211095Sdes*/ 672171568Sscottl 673171568Sscottlint 674171568Sscottlfsm(isc_opt_t *op) 675171568Sscottl{ 676171568Sscottl state_t state; 677171568Sscottl isess_t *sess; 678171568Sscottl 679171568Sscottl if((sess = calloc(1, sizeof(isess_t))) == NULL) { 680171568Sscottl // boy, is this a bad start ... 681171568Sscottl fprintf(stderr, "no memory!\n"); 682171568Sscottl return -1; 683171568Sscottl } 684171568Sscottl 685171568Sscottl state = S1; 686171568Sscottl sess->op = op; 687171568Sscottl sess->fd = -1; 688171568Sscottl sess->soc = -1; 689185289Sscottl sess->target.address = strdup(op->targetAddress); 690185289Sscottl sess->target.port = op->port; 691185289Sscottl sess->target.pgt = op->targetPortalGroupTag; 692171568Sscottl 693171568Sscottl sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1; 694171568Sscottl 695171568Sscottl do { 696171568Sscottl switch(state) { 697171568Sscottl 698171568Sscottl case S1: 699171568Sscottl switch(tcpConnect(sess)) { 700171568Sscottl case T1: state = S2; break; 701171568Sscottl default: state = S8; break; 702171568Sscottl } 703171568Sscottl break; 704171568Sscottl 705171568Sscottl case S2: 706171568Sscottl switch(startSession(sess)) { 707171568Sscottl case T2: state = S1; break; 708171568Sscottl case T4: state = S4; break; 709171568Sscottl default: state = S8; break; 710171568Sscottl } 711171568Sscottl break; 712171568Sscottl 713171568Sscottl case S4: 714171568Sscottl switch(doLogin(sess)) { 715171568Sscottl case T7: state = S1; break; 716171568Sscottl case T5: state = S5; break; 717171568Sscottl default: state = S8; break; 718171568Sscottl } 719171568Sscottl break; 720171568Sscottl 721171568Sscottl case S5: 722171568Sscottl switch(supervise(sess)) { 723171568Sscottl case T8: state = S1; break; 724171568Sscottl case T9: state = S6; break; 725171568Sscottl case T11: state = S7; break; 726171568Sscottl case T15: state = S8; break; 727171568Sscottl default: state = S8; break; 728171568Sscottl } 729171568Sscottl break; 730171568Sscottl 731171568Sscottl case S6: 732171568Sscottl switch(startLogout(sess)) { 733171568Sscottl case T13: state = S1; break; 734171568Sscottl case T14: state = S6; break; 735171568Sscottl case T16: state = S8; break; 736171568Sscottl default: state = S8; break; 737171568Sscottl } 738171568Sscottl break; 739171568Sscottl 740171568Sscottl case S7: 741171568Sscottl switch(inLogout(sess)) { 742171568Sscottl case T18: state = S1; break; 743171568Sscottl case T10: state = S6; break; 744171568Sscottl case T12: state = S7; break; 745171568Sscottl case T16: state = S8; break; 746171568Sscottl default: state = S8; break; 747171568Sscottl } 748171568Sscottl break; 749171568Sscottl 750171568Sscottl case S8: 751171568Sscottl // maybe do some clean up? 752171568Sscottl syslog(LOG_INFO, "terminated"); 753171568Sscottl return 0; 754171568Sscottl } 755171568Sscottl } while(1); 756171568Sscottl} 757