fsm.c revision 185289
1171568Sscottl/*- 2185289Sscottl * Copyright (c) 2005-2008 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: head/sbin/iscontrol/fsm.c 185289 2008-11-25 07:17:11Z scottl $"); 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#if __FreeBSD_version < 500000 44171568Sscottl#include <sys/time.h> 45171568Sscottl#endif 46171568Sscottl#include <sys/ioctl.h> 47171568Sscottl#include <netdb.h> 48171568Sscottl#include <stdlib.h> 49171568Sscottl#include <unistd.h> 50171568Sscottl#include <stdio.h> 51171568Sscottl#include <string.h> 52171568Sscottl#include <errno.h> 53171568Sscottl#include <fcntl.h> 54171568Sscottl#include <time.h> 55171568Sscottl#include <syslog.h> 56171568Sscottl#include <stdarg.h> 57171568Sscottl#include <camlib.h> 58171568Sscottl 59171568Sscottl#include "iscsi.h" 60171568Sscottl#include "iscontrol.h" 61171568Sscottl 62171568Sscottltypedef enum { 63171568Sscottl T1 = 1, 64171568Sscottl T2, /*T3,*/ T4, T5, /*T6,*/ T7, T8, T9, 65171568Sscottl T10, T11, T12, T13, T14, T15, T16, T18 66171568Sscottl} trans_t; 67171568Sscottl 68185289Sscottl/* 69185289Sscottl | now supports IPV6 70185289Sscottl | thanks to: 71185289Sscottl | Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan 72185289Sscottl | ume@mahoroba.org ume@{,jp.}FreeBSD.org 73185289Sscottl | http://www.imasy.org/~ume/ 74185289Sscottl */ 75171568Sscottlstatic trans_t 76171568SscottltcpConnect(isess_t *sess) 77171568Sscottl{ 78171568Sscottl isc_opt_t *op = sess->op; 79185289Sscottl int val, sv_errno, soc; 80185289Sscottl struct addrinfo *res, *res0, hints; 81185289Sscottl char pbuf[10]; 82171568Sscottl 83171568Sscottl debug_called(3); 84171568Sscottl if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) { 85171568Sscottl syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT) 86171568Sscottl ? "Reconnect": "Redirected"); 87171568Sscottl 88185289Sscottl debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected"); 89171568Sscottl shutdown(sess->soc, SHUT_RDWR); 90171568Sscottl //close(sess->soc); 91171568Sscottl sess->soc = -1; 92171568Sscottl 93171568Sscottl sess->flags &= ~SESS_CONNECTED; 94171568Sscottl if(sess->flags & SESS_REDIRECT) { 95185289Sscottl sess->redirect_cnt++; 96171568Sscottl sess->flags |= SESS_RECONNECT; 97185289Sscottl } else 98185289Sscottl sleep(2); // XXX: actually should be ? 99185289Sscottl#ifdef notyet 100185289Sscottl { 101185289Sscottl time_t sec; 102171568Sscottl // make sure we are not in a loop 103171568Sscottl // XXX: this code has to be tested 104171568Sscottl sec = time(0) - sess->reconnect_time; 105171568Sscottl if(sec > (5*60)) { 106171568Sscottl // if we've been connected for more that 5 minutes 107171568Sscottl // then just reconnect 108171568Sscottl sess->reconnect_time = sec; 109171568Sscottl sess->reconnect_cnt1 = 0; 110171568Sscottl } 111171568Sscottl else { 112171568Sscottl // 113171568Sscottl sess->reconnect_cnt1++; 114171568Sscottl if((sec / sess->reconnect_cnt1) < 2) { 115171568Sscottl // if less that 2 seconds from the last reconnect 116171568Sscottl // we are most probably looping 117171568Sscottl syslog(LOG_CRIT, "too many reconnects %d", sess->reconnect_cnt1); 118171568Sscottl return 0; 119171568Sscottl } 120171568Sscottl } 121185289Sscottl } 122185289Sscottl#endif 123171568Sscottl sess->reconnect_cnt++; 124171568Sscottl } 125171568Sscottl 126185289Sscottl snprintf(pbuf, sizeof(pbuf), "%d", op->port); 127171568Sscottl memset(&hints, 0, sizeof(hints)); 128185289Sscottl hints.ai_family = PF_UNSPEC; 129171568Sscottl hints.ai_socktype = SOCK_STREAM; 130185289Sscottl debug(1, "targetAddress=%s port=%d", op->targetAddress, op->port); 131185289Sscottl if((val = getaddrinfo(op->targetAddress, pbuf, &hints, &res0)) != 0) { 132171568Sscottl fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val)); 133171568Sscottl return 0; 134171568Sscottl } 135185289Sscottl sess->flags &= ~SESS_CONNECTED; 136185289Sscottl sv_errno = 0; 137185289Sscottl soc = -1; 138185289Sscottl for(res = res0; res; res = res->ai_next) { 139185289Sscottl soc = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 140185289Sscottl if (soc == -1) 141185289Sscottl continue; 142171568Sscottl 143171568Sscottl // from Patrick.Guelat@imp.ch: 144171568Sscottl // iscontrol can be called without waiting for the socket entry to time out 145171568Sscottl val = 1; 146185289Sscottl if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) { 147171568Sscottl fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n", 148171568Sscottl errno, strerror(errno)); 149171568Sscottl } 150171568Sscottl 151185289Sscottl if(connect(soc, res->ai_addr, res->ai_addrlen) == 0) 152185289Sscottl break; 153185289Sscottl sv_errno = errno; 154185289Sscottl close(soc); 155185289Sscottl soc = -1; 156185289Sscottl } 157185289Sscottl freeaddrinfo(res0); 158185289Sscottl if(soc != -1) { 159185289Sscottl sess->soc = soc; 160171568Sscottl 161171568Sscottl#if 0 162171568Sscottl struct timeval timeout; 163171568Sscottl 164171568Sscottl val = 1; 165171568Sscottl if(setsockopt(sess->soc, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) 166171568Sscottl fprintf(stderr, "Cannot set socket KEEPALIVE option err=%d %s\n", 167171568Sscottl errno, strerror(errno)); 168171568Sscottl 169171568Sscottl if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0) 170171568Sscottl fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n", 171171568Sscottl errno, strerror(errno)); 172171568Sscottl 173171568Sscottl timeout.tv_sec = 10; 174171568Sscottl timeout.tv_usec = 0; 175171568Sscottl if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) 176171568Sscottl || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)) { 177171568Sscottl fprintf(stderr, "Cannot set socket timeout to %ld err=%d %s\n", 178171568Sscottl timeout.tv_sec, errno, strerror(errno)); 179171568Sscottl } 180171568Sscottl#endif 181171568Sscottl#ifdef CURIOUS 182171568Sscottl { 183171568Sscottl int len = sizeof(val); 184171568Sscottl if(getsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0) 185171568Sscottl fprintf(stderr, "was: SO_SNDBUF=%dK\n", val/1024); 186171568Sscottl } 187171568Sscottl#endif 188171568Sscottl if(sess->op->sockbufsize) { 189171568Sscottl val = sess->op->sockbufsize * 1024; 190171568Sscottl if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0) 191171568Sscottl || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)) { 192171568Sscottl fprintf(stderr, "Cannot set socket sndbuf & rcvbuf to %d err=%d %s\n", 193171568Sscottl val, errno, strerror(errno)); 194171568Sscottl return 0; 195171568Sscottl } 196171568Sscottl } 197171568Sscottl sess->flags |= SESS_CONNECTED; 198171568Sscottl return T1; 199185289Sscottl } 200171568Sscottl 201171568Sscottl fprintf(stderr, "errno=%d\n", sv_errno); 202171568Sscottl perror("connect"); 203171568Sscottl switch(sv_errno) { 204171568Sscottl case ECONNREFUSED: 205171568Sscottl case ENETUNREACH: 206171568Sscottl case ETIMEDOUT: 207185289Sscottl if((sess->flags & SESS_REDIRECT) == 0) { 208185289Sscottl if(strcmp(op->targetAddress, sess->target.address) != 0) { 209185289Sscottl syslog(LOG_INFO, "reconnecting to original target address"); 210185289Sscottl free(op->targetAddress); 211185289Sscottl op->targetAddress = sess->target.address; 212185289Sscottl op->port = sess->target.port; 213185289Sscottl op->targetPortalGroupTag = sess->target.pgt; 214185289Sscottl return T1; 215185289Sscottl } 216185289Sscottl } 217171568Sscottl sleep(5); // for now ... 218171568Sscottl return T1; 219171568Sscottl default: 220171568Sscottl return 0; // terminal error 221171568Sscottl } 222171568Sscottl} 223171568Sscottl 224171568Sscottlint 225171568SscottlsetOptions(isess_t *sess, int flag) 226171568Sscottl{ 227171568Sscottl isc_opt_t oop; 228171568Sscottl char *sep; 229171568Sscottl 230171568Sscottl debug_called(3); 231171568Sscottl 232171568Sscottl bzero(&oop, sizeof(isc_opt_t)); 233171568Sscottl 234171568Sscottl if((flag & SESS_FULLFEATURE) == 0) { 235171568Sscottl oop.initiatorName = sess->op->initiatorName; 236171568Sscottl oop.targetAddress = sess->op->targetAddress; 237171568Sscottl if(sess->op->targetName != 0) 238171568Sscottl oop.targetName = sess->op->targetName; 239171568Sscottl 240171568Sscottl oop.maxRecvDataSegmentLength = sess->op->maxRecvDataSegmentLength; 241171568Sscottl oop.maxXmitDataSegmentLength = sess->op->maxXmitDataSegmentLength; // XXX: 242171568Sscottl oop.maxBurstLength = sess->op->maxBurstLength; 243171568Sscottl oop.maxluns = sess->op->maxluns; 244171568Sscottl } 245171568Sscottl else { 246171568Sscottl /* 247171568Sscottl | turn on digestion only after login 248171568Sscottl */ 249171568Sscottl if(sess->op->headerDigest != NULL) { 250171568Sscottl sep = strchr(sess->op->headerDigest, ','); 251171568Sscottl if(sep == NULL) 252171568Sscottl oop.headerDigest = sess->op->headerDigest; 253171568Sscottl debug(1, "oop.headerDigest=%s", oop.headerDigest); 254171568Sscottl } 255171568Sscottl if(sess->op->dataDigest != NULL) { 256171568Sscottl sep = strchr(sess->op->dataDigest, ','); 257171568Sscottl if(sep == NULL) 258171568Sscottl oop.dataDigest = sess->op->dataDigest; 259171568Sscottl debug(1, "oop.dataDigest=%s", oop.dataDigest); 260171568Sscottl } 261171568Sscottl } 262171568Sscottl 263171568Sscottl if(ioctl(sess->fd, ISCSISETOPT, &oop)) { 264171568Sscottl perror("ISCSISETOPT"); 265171568Sscottl return -1; 266171568Sscottl } 267171568Sscottl return 0; 268171568Sscottl} 269171568Sscottl 270171568Sscottlstatic trans_t 271171568SscottlstartSession(isess_t *sess) 272171568Sscottl{ 273171568Sscottl 274171568Sscottl int n, fd, nfd; 275171568Sscottl char *dev; 276171568Sscottl 277171568Sscottl debug_called(3); 278171568Sscottl 279171568Sscottl if((sess->flags & SESS_CONNECTED) == 0) { 280171568Sscottl return T2; 281171568Sscottl } 282171568Sscottl if(sess->fd == -1) { 283171568Sscottl fd = open(iscsidev, O_RDWR); 284171568Sscottl if(fd < 0) { 285171568Sscottl perror(iscsidev); 286171568Sscottl return 0; 287171568Sscottl } 288171568Sscottl { 289171568Sscottl // XXX: this has to go 290171568Sscottl size_t n; 291171568Sscottl n = sizeof(sess->isid); 292171568Sscottl if(sysctlbyname("net.iscsi.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0) 293171568Sscottl perror("sysctlbyname"); 294171568Sscottl } 295171568Sscottl if(ioctl(fd, ISCSISETSES, &n)) { 296171568Sscottl perror("ISCSISETSES"); 297171568Sscottl return 0; 298171568Sscottl } 299171568Sscottl asprintf(&dev, "%s%d", iscsidev, n); 300171568Sscottl nfd = open(dev, O_RDWR); 301171568Sscottl if(nfd < 0) { 302171568Sscottl perror(dev); 303171568Sscottl free(dev); 304171568Sscottl return 0; 305171568Sscottl } 306171568Sscottl free(dev); 307171568Sscottl close(fd); 308171568Sscottl sess->fd = nfd; 309171568Sscottl 310171568Sscottl if(setOptions(sess, 0) != 0) 311171568Sscottl return -1; 312171568Sscottl } 313171568Sscottl 314171568Sscottl if(ioctl(sess->fd, ISCSISETSOC, &sess->soc)) { 315171568Sscottl perror("ISCSISETSOC"); 316171568Sscottl return 0; 317171568Sscottl } 318171568Sscottl 319171568Sscottl return T4; 320171568Sscottl} 321171568Sscottl 322171568Sscottlisess_t *currsess; 323171568Sscottl 324171568Sscottlstatic void 325171568Sscottltrap(int sig) 326171568Sscottl{ 327171568Sscottl syslog(LOG_NOTICE, "trapped signal %d", sig); 328171568Sscottl fprintf(stderr, "trapped signal %d\n", sig); 329171568Sscottl 330171568Sscottl switch(sig) { 331171568Sscottl case SIGHUP: 332171568Sscottl currsess->flags |= SESS_DISCONNECT; 333171568Sscottl break; 334171568Sscottl 335171568Sscottl case SIGUSR1: 336171568Sscottl currsess->flags |= SESS_RECONNECT; 337171568Sscottl break; 338171568Sscottl 339171568Sscottl case SIGINT: 340171568Sscottl case SIGTERM: 341171568Sscottl default: 342171568Sscottl return; // ignore 343171568Sscottl } 344171568Sscottl} 345171568Sscottl 346171568Sscottlstatic void 347171568SscottldoCAM(isess_t *sess) 348171568Sscottl{ 349171568Sscottl char pathstr[1024]; 350171568Sscottl union ccb *ccb; 351171568Sscottl int i; 352171568Sscottl 353171568Sscottl if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) { 354171568Sscottl syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno); 355171568Sscottl return; 356171568Sscottl } 357171568Sscottl debug(2, "nluns=%d", sess->cam.target_nluns); 358171568Sscottl /* 359171568Sscottl | for now will do this for each lun ... 360171568Sscottl */ 361171568Sscottl for(i = 0; i < sess->cam.target_nluns; i++) { 362171568Sscottl debug(2, "CAM path_id=%d target_id=%d target_lun=%d", 363171568Sscottl sess->cam.path_id, sess->cam.target_id, sess->cam.target_lun[i]); 364171568Sscottl 365171568Sscottl sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id, 366171568Sscottl sess->cam.target_lun[i], O_RDWR, NULL); 367171568Sscottl if(sess->camdev == NULL) { 368171568Sscottl syslog(LOG_WARNING, "%s", cam_errbuf); 369171568Sscottl debug(3, "%s", cam_errbuf); 370171568Sscottl continue; 371171568Sscottl } 372171568Sscottl 373171568Sscottl cam_path_string(sess->camdev, pathstr, sizeof(pathstr)); 374171568Sscottl debug(2, "pathstr=%s", pathstr); 375171568Sscottl 376171568Sscottl ccb = cam_getccb(sess->camdev); 377171568Sscottl bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr)); 378171568Sscottl ccb->ccb_h.func_code = XPT_REL_SIMQ; 379171568Sscottl ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS; 380171568Sscottl ccb->crs.openings = sess->op->tags; 381171568Sscottl 382171568Sscottl if(cam_send_ccb(sess->camdev, ccb) < 0) 383171568Sscottl syslog(LOG_WARNING, "%s", cam_errbuf); 384171568Sscottl else 385171568Sscottl if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 386171568Sscottl syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed"); 387171568Sscottl // cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 388171568Sscottl } 389171568Sscottl else 390171568Sscottl syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings); 391171568Sscottl 392171568Sscottl cam_freeccb(ccb); 393171568Sscottl cam_close_device(sess->camdev); 394171568Sscottl } 395171568Sscottl} 396171568Sscottl 397171568Sscottlstatic trans_t 398171568Sscottlsupervise(isess_t *sess) 399171568Sscottl{ 400171568Sscottl int sig, val; 401171568Sscottl 402171568Sscottl debug_called(3); 403171568Sscottl 404171568Sscottl if(strcmp(sess->op->sessionType, "Discovery") == 0) { 405171568Sscottl sess->flags |= SESS_DISCONNECT; 406171568Sscottl return T9; 407171568Sscottl } 408171568Sscottl 409171568Sscottl if(vflag) 410171568Sscottl printf("ready to go scsi\n"); 411171568Sscottl 412171568Sscottl if(setOptions(sess, SESS_FULLFEATURE) != 0) 413171568Sscottl return 0; // failure 414171568Sscottl 415171568Sscottl if((sess->flags & SESS_FULLFEATURE) == 0) { 416171568Sscottl if(daemon(0, 1) != 0) { 417171568Sscottl perror("daemon"); 418171568Sscottl exit(1); 419171568Sscottl } 420171568Sscottl 421171568Sscottl openlog("iscontrol", LOG_CONS|LOG_PERROR|LOG_PID|LOG_NDELAY, LOG_KERN); 422171568Sscottl syslog(LOG_INFO, "running"); 423171568Sscottl 424171568Sscottl currsess = sess; 425171568Sscottl if(ioctl(sess->fd, ISCSISTART)) { 426171568Sscottl perror("ISCSISTART"); 427171568Sscottl return -1; 428171568Sscottl } 429171568Sscottl doCAM(sess); 430171568Sscottl 431171568Sscottl } 432171568Sscottl else { 433171568Sscottl if(ioctl(sess->fd, ISCSIRESTART)) { 434171568Sscottl perror("ISCSIRESTART"); 435171568Sscottl return -1; 436171568Sscottl } 437171568Sscottl } 438171568Sscottl 439171568Sscottl signal(SIGINT, trap); 440171568Sscottl signal(SIGHUP, trap); 441171568Sscottl signal(SIGTERM, trap); 442171568Sscottl 443171568Sscottl sig = SIGUSR1; 444171568Sscottl signal(sig, trap); 445171568Sscottl if(ioctl(sess->fd, ISCSISIGNAL, &sig)) { 446171568Sscottl perror("ISCSISIGNAL"); 447171568Sscottl return -1; 448171568Sscottl } 449171568Sscottl sess->flags |= SESS_FULLFEATURE; 450171568Sscottl 451171568Sscottl sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT); 452171568Sscottl printf("iscontrol: supervise starting main loop\n"); 453171568Sscottl /* 454171568Sscottl | the main loop - actually do nothing 455171568Sscottl | all the work is done inside the kernel 456171568Sscottl */ 457171568Sscottl while((sess->flags & (SESS_REDIRECT|SESS_RECONNECT|SESS_DISCONNECT)) == 0) { 458171568Sscottl // do something? 459171568Sscottl // like sending a nop_out? 460171568Sscottl sleep(60); 461171568Sscottl } 462171568Sscottl printf("iscontrol: supervise going down\n"); 463171568Sscottl syslog(LOG_INFO, "sess flags=%x", sess->flags); 464171568Sscottl 465171568Sscottl sig = 0; 466171568Sscottl if(ioctl(sess->fd, ISCSISIGNAL, &sig)) { 467171568Sscottl perror("ISCSISIGNAL"); 468171568Sscottl } 469171568Sscottl 470171568Sscottl if(sess->flags & SESS_DISCONNECT) { 471171568Sscottl val = 0; 472171568Sscottl if(ioctl(sess->fd, ISCSISTOP, &val)) { 473171568Sscottl perror("ISCSISTOP"); 474171568Sscottl } 475171568Sscottl sess->flags &= ~SESS_FULLFEATURE; 476171568Sscottl return T9; 477171568Sscottl } 478171568Sscottl else { 479171568Sscottl sess->flags |= SESS_INITIALLOGIN1; 480171568Sscottl } 481171568Sscottl return T8; 482171568Sscottl} 483171568Sscottl 484171568Sscottlstatic int 485171568SscottlhandledDiscoveryResp(isess_t *sess, pdu_t *pp) 486171568Sscottl{ 487171568Sscottl u_char *ptr; 488171568Sscottl int len, n; 489171568Sscottl 490171568Sscottl debug_called(3); 491171568Sscottl 492171568Sscottl len = pp->ds_len; 493171568Sscottl ptr = pp->ds; 494171568Sscottl while(len > 0) { 495171568Sscottl if(*ptr != 0) 496171568Sscottl printf("%s\n", ptr); 497171568Sscottl n = strlen((char *)ptr) + 1; 498171568Sscottl len -= n; 499171568Sscottl ptr += n; 500171568Sscottl } 501171568Sscottl return 0; 502171568Sscottl} 503171568Sscottl 504171568Sscottlstatic int 505171568SscottldoDiscovery(isess_t *sess) 506171568Sscottl{ 507171568Sscottl pdu_t spp; 508171568Sscottl text_req_t *tp = (text_req_t *)&spp.ipdu.bhs; 509171568Sscottl 510171568Sscottl debug_called(3); 511171568Sscottl 512171568Sscottl bzero(&spp, sizeof(pdu_t)); 513171568Sscottl tp->cmd = ISCSI_TEXT_CMD /*| 0x40 */; // because of a bug in openiscsi-target 514171568Sscottl tp->F = 1; 515171568Sscottl tp->ttt = 0xffffffff; 516171568Sscottl addText(&spp, "SendTargets=All"); 517171568Sscottl return sendPDU(sess, &spp, handledDiscoveryResp); 518171568Sscottl} 519171568Sscottl 520171568Sscottlstatic trans_t 521171568SscottldoLogin(isess_t *sess) 522171568Sscottl{ 523171568Sscottl isc_opt_t *op = sess->op; 524171568Sscottl int status, count; 525171568Sscottl 526171568Sscottl debug_called(3); 527171568Sscottl 528171568Sscottl if(op->chapSecret == NULL && op->tgtChapSecret == NULL) 529171568Sscottl /* 530171568Sscottl | don't need any security negotiation 531171568Sscottl | or in other words: we don't have any secrets to exchange 532171568Sscottl */ 533171568Sscottl sess->csg = LON_PHASE; 534171568Sscottl else 535171568Sscottl sess->csg = SN_PHASE; 536171568Sscottl 537171568Sscottl if(sess->tsih) { 538171568Sscottl sess->tsih = 0; // XXX: no 'reconnect' yet 539171568Sscottl sess->flags &= ~SESS_NEGODONE; // XXX: KLUDGE 540171568Sscottl } 541171568Sscottl count = 10; // should be more than enough 542171568Sscottl do { 543171568Sscottl debug(3, "count=%d csg=%d", count, sess->csg); 544171568Sscottl status = loginPhase(sess); 545171568Sscottl if(count-- == 0) 546171568Sscottl // just in case we get into a loop 547171568Sscottl status = -1; 548171568Sscottl } while(status == 0 && (sess->csg != FF_PHASE)); 549171568Sscottl 550171568Sscottl sess->flags &= ~SESS_INITIALLOGIN; 551171568Sscottl debug(3, "status=%d", status); 552171568Sscottl 553171568Sscottl switch(status) { 554171568Sscottl case 0: // all is ok ... 555171568Sscottl sess->flags |= SESS_LOGGEDIN; 556171568Sscottl if(strcmp(sess->op->sessionType, "Discovery") == 0) 557171568Sscottl doDiscovery(sess); 558171568Sscottl return T5; 559171568Sscottl 560171568Sscottl case 1: // redirect - temporary/permanent 561171568Sscottl /* 562171568Sscottl | start from scratch? 563171568Sscottl */ 564171568Sscottl sess->flags &= ~SESS_NEGODONE; 565171568Sscottl sess->flags |= (SESS_REDIRECT | SESS_INITIALLOGIN1); 566171568Sscottl syslog(LOG_DEBUG, "target sent REDIRECT"); 567171568Sscottl return T7; 568171568Sscottl 569171568Sscottl case 2: // initiator terminal error 570185289Sscottl return 0; 571171568Sscottl case 3: // target terminal error -- could retry ... 572185289Sscottl sleep(5); 573185289Sscottl return T7; // lets try 574171568Sscottl default: 575171568Sscottl return 0; 576171568Sscottl } 577171568Sscottl} 578171568Sscottl 579171568Sscottlstatic int 580171568SscottlhandleLogoutResp(isess_t *sess, pdu_t *pp) 581171568Sscottl{ 582171568Sscottl if(sess->flags & SESS_DISCONNECT) 583171568Sscottl return 0; 584171568Sscottl return T13; 585171568Sscottl} 586171568Sscottl 587171568Sscottlstatic trans_t 588171568SscottlstartLogout(isess_t *sess) 589171568Sscottl{ 590171568Sscottl pdu_t spp; 591171568Sscottl logout_req_t *p = (logout_req_t *)&spp.ipdu.bhs; 592171568Sscottl 593171568Sscottl bzero(&spp, sizeof(pdu_t)); 594171568Sscottl p->cmd = ISCSI_LOGOUT_CMD| 0x40; 595171568Sscottl p->reason = BIT(7) | 0; 596171568Sscottl p->CID = htons(1); 597171568Sscottl 598171568Sscottl return sendPDU(sess, &spp, handleLogoutResp); 599171568Sscottl} 600171568Sscottl 601171568Sscottlstatic trans_t 602171568SscottlinLogout(isess_t *sess) 603171568Sscottl{ 604171568Sscottl if(sess->flags & SESS_RECONNECT) 605171568Sscottl return T18; 606171568Sscottl return 0; 607171568Sscottl} 608171568Sscottl 609171568Sscottltypedef enum { 610171568Sscottl S1, S2, /*S3,*/ S4, S5, S6, S7, S8 611171568Sscottl} state_t; 612171568Sscottl 613171568Sscottl#if 0 614171568Sscottl S1: FREE 615171568Sscottl S2: XPT_WAIT 616171568Sscottl S4: IN_LOGIN 617171568Sscottl S5: LOGGED_IN 618171568Sscottl S6: IN_LOGOUT 619171568Sscottl S7: LOGOUT_REQUESTED 620171568Sscottl S8: CLEANUP_WAIT 621171568Sscottl 622171568Sscottl -------<-------------+ 623171568Sscottl +--------->/ S1 \<----+ | 624171568Sscottl T13| +->\ /<-+ \ | 625171568Sscottl | / ---+--- \ \ | 626171568Sscottl | / | T2 \ | | 627171568Sscottl | T8 | |T1 | | | 628171568Sscottl | | | / |T7 | 629171568Sscottl | | | / | | 630171568Sscottl | | | / | | 631171568Sscottl | | V / / | 632171568Sscottl | | ------- / / | 633171568Sscottl | | / S2 \ / | 634171568Sscottl | | \ / / | 635171568Sscottl | | ---+--- / | 636171568Sscottl | | |T4 / | 637171568Sscottl | | V / | T18 638171568Sscottl | | ------- / | 639171568Sscottl | | / S4 \ | 640171568Sscottl | | \ / | 641171568Sscottl | | ---+--- | T15 642171568Sscottl | | |T5 +--------+---------+ 643171568Sscottl | | | /T16+-----+------+ | 644171568Sscottl | | | / -+-----+--+ | | 645171568Sscottl | | | / / S7 \ |T12| | 646171568Sscottl | | | / +->\ /<-+ V V 647171568Sscottl | | | / / -+----- ------- 648171568Sscottl | | | / /T11 |T10 / S8 \ 649171568Sscottl | | V / / V +----+ \ / 650171568Sscottl | | ---+-+- ----+-- | ------- 651171568Sscottl | | / S5 \T9 / S6 \<+ ^ 652171568Sscottl | +-----\ /--->\ / T14 | 653171568Sscottl | ------- --+----+------+T17 654171568Sscottl +---------------------------+ 655171568Sscottl#endif 656171568Sscottl 657171568Sscottlint 658171568Sscottlfsm(isc_opt_t *op) 659171568Sscottl{ 660171568Sscottl state_t state; 661171568Sscottl isess_t *sess; 662171568Sscottl 663171568Sscottl if((sess = calloc(1, sizeof(isess_t))) == NULL) { 664171568Sscottl // boy, is this a bad start ... 665171568Sscottl fprintf(stderr, "no memory!\n"); 666171568Sscottl return -1; 667171568Sscottl } 668171568Sscottl 669171568Sscottl state = S1; 670171568Sscottl sess->op = op; 671171568Sscottl sess->fd = -1; 672171568Sscottl sess->soc = -1; 673185289Sscottl sess->target.address = strdup(op->targetAddress); 674185289Sscottl sess->target.port = op->port; 675185289Sscottl sess->target.pgt = op->targetPortalGroupTag; 676171568Sscottl 677171568Sscottl sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1; 678171568Sscottl 679171568Sscottl do { 680171568Sscottl switch(state) { 681171568Sscottl 682171568Sscottl case S1: 683171568Sscottl switch(tcpConnect(sess)) { 684171568Sscottl case T1: state = S2; break; 685171568Sscottl default: state = S8; break; 686171568Sscottl } 687171568Sscottl break; 688171568Sscottl 689171568Sscottl case S2: 690171568Sscottl switch(startSession(sess)) { 691171568Sscottl case T2: state = S1; break; 692171568Sscottl case T4: state = S4; break; 693171568Sscottl default: state = S8; break; 694171568Sscottl } 695171568Sscottl break; 696171568Sscottl 697171568Sscottl case S4: 698171568Sscottl switch(doLogin(sess)) { 699171568Sscottl case T7: state = S1; break; 700171568Sscottl case T5: state = S5; break; 701171568Sscottl default: state = S8; break; 702171568Sscottl } 703171568Sscottl break; 704171568Sscottl 705171568Sscottl case S5: 706171568Sscottl switch(supervise(sess)) { 707171568Sscottl case T8: state = S1; break; 708171568Sscottl case T9: state = S6; break; 709171568Sscottl case T11: state = S7; break; 710171568Sscottl case T15: state = S8; break; 711171568Sscottl default: state = S8; break; 712171568Sscottl } 713171568Sscottl break; 714171568Sscottl 715171568Sscottl case S6: 716171568Sscottl switch(startLogout(sess)) { 717171568Sscottl case T13: state = S1; break; 718171568Sscottl case T14: state = S6; break; 719171568Sscottl case T16: state = S8; break; 720171568Sscottl default: state = S8; break; 721171568Sscottl } 722171568Sscottl break; 723171568Sscottl 724171568Sscottl case S7: 725171568Sscottl switch(inLogout(sess)) { 726171568Sscottl case T18: state = S1; break; 727171568Sscottl case T10: state = S6; break; 728171568Sscottl case T12: state = S7; break; 729171568Sscottl case T16: state = S8; break; 730171568Sscottl default: state = S8; break; 731171568Sscottl } 732171568Sscottl break; 733171568Sscottl 734171568Sscottl case S8: 735171568Sscottl // maybe do some clean up? 736171568Sscottl syslog(LOG_INFO, "terminated"); 737171568Sscottl return 0; 738171568Sscottl } 739171568Sscottl } while(1); 740171568Sscottl} 741