fsm.c revision 171568
142421Syokota/*-
242421Syokota * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
342421Syokota * All rights reserved.
442421Syokota *
542421Syokota * Redistribution and use in source and binary forms, with or without
642421Syokota * modification, are permitted provided that the following conditions
742421Syokota * are met:
842421Syokota * 1. Redistributions of source code must retain the above copyright
942421Syokota *    notice, this list of conditions and the following disclaimer.
1042421Syokota * 2. Redistributions in binary form must reproduce the above copyright
1142421Syokota *    notice, this list of conditions and the following disclaimer in the
1242421Syokota *    documentation and/or other materials provided with the distribution.
1342421Syokota *
1442421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1542421Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1642421Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1742421Syokota * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1842421Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1942421Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2042421Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2142421Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2242421Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2342421Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2442421Syokota * SUCH DAMAGE.
2542421Syokota *
2650477Speter */
2742421Syokota
2842421Syokota/*
2942421Syokota | $Id: fsm.c,v 2.8 2007/05/19 16:34:21 danny Exp danny $
3044628Syokota */
3142421Syokota
3242421Syokota#include <sys/cdefs.h>
3342421Syokota__FBSDID("$FreeBSD: head/sbin/iscontrol/fsm.c 171568 2007-07-24 15:35:02Z scottl $");
3442421Syokota
3547336Syokota#include <sys/param.h>
3642421Syokota#include <sys/types.h>
3742421Syokota#include <sys/socket.h>
3842421Syokota#include <sys/sysctl.h>
3958271Syokota
4058271Syokota#include <netinet/in.h>
4158271Syokota#include <netinet/tcp.h>
4255731Syokota#include <arpa/inet.h>
4355731Syokota#if __FreeBSD_version < 500000
4455731Syokota#include <sys/time.h>
4555731Syokota#endif
4655731Syokota#include <sys/ioctl.h>
4755731Syokota#include <netdb.h>
4855731Syokota#include <stdlib.h>
4955731Syokota#include <unistd.h>
5055731Syokota#include <stdio.h>
5155731Syokota#include <string.h>
5242421Syokota#include <errno.h>
5342421Syokota#include <fcntl.h>
5442421Syokota#include <time.h>
5542421Syokota#include <syslog.h>
5642831Syokota#include <stdarg.h>
5742831Syokota#include <camlib.h>
5842421Syokota
5942421Syokota#include "iscsi.h"
6042421Syokota#include "iscontrol.h"
6158271Syokota#include "pdu.h"
6242421Syokota
6342421Syokotatypedef enum {
6442421Syokota     T1 = 1,
6544628Syokota     T2, /*T3,*/ T4, T5, /*T6,*/ T7, T8, T9,
6642421Syokota     T10, T11, T12, T13, T14, T15, T16, T18
6742421Syokota} trans_t;
6842421Syokota
6942421Syokotastatic trans_t
7042421SyokotatcpConnect(isess_t *sess)
7158271Syokota{
7242421Syokota     isc_opt_t *op = sess->op;
7344628Syokota     int	val, sv_errno;
7444628Syokota     struct     addrinfo *res, hints;
7544628Syokota     struct	sockaddr_in sn;
7644628Syokota     struct	in_addr ipn;
7742421Syokota     time_t	sec;
7842421Syokota
7942421Syokota     debug_called(3);
8058271Syokota     if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) {
8142421Syokota	  syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT)
8242421Syokota		 ? "Reconnect": "Redirected");
8344628Syokota
8442421Syokota	  debug(3, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected");
8542421Syokota	  shutdown(sess->soc, SHUT_RDWR);
8642421Syokota	  //close(sess->soc);
8742421Syokota	  sleep(5); // XXX: actually should be ?
8842421Syokota	  sess->soc = -1;
8942421Syokota
9042421Syokota	  sess->flags &= ~SESS_CONNECTED;
9158271Syokota	  if(sess->flags & SESS_REDIRECT) {
9244628Syokota	       if(sess->redirect_cnt++ > MAXREDIRECTS) {
9350154Syokota		    syslog(LOG_WARNING, "too many redirects > %d", MAXREDIRECTS);
9444628Syokota		    return 0;
9542421Syokota	       }
9644628Syokota	       sess->flags |= SESS_RECONNECT;
9750154Syokota	  }
9844628Syokota	  if((sess->flags & SESS_RECONNECT) == 0)
9944628Syokota	       return 0;
10050154Syokota
10142421Syokota	  // make sure we are not in a loop
10242421Syokota	  // XXX: this code has to be tested
10342421Syokota	  sec = time(0) - sess->reconnect_time;
10450154Syokota	  if(sec > (5*60)) {
10542421Syokota	       // if we've been connected for more that 5 minutes
10642421Syokota	       // then just reconnect
10742421Syokota	       sess->reconnect_time = sec;
10842421Syokota	       sess->reconnect_cnt1 = 0;
10942421Syokota	  }
11042421Syokota	  else {
11142421Syokota	       //
11242421Syokota	       sess->reconnect_cnt1++;
11350154Syokota	       if((sec / sess->reconnect_cnt1) < 2) {
11442421Syokota		    // if less that 2 seconds from the last reconnect
11542421Syokota		    // we are most probably looping
11650154Syokota		    syslog(LOG_CRIT, "too many reconnects %d", sess->reconnect_cnt1);
11742421Syokota		    return 0;
11842421Syokota	       }
11942421Syokota	  }
12042421Syokota	  sess->reconnect_cnt++;
12142421Syokota	  // sess->flags &= ~(SESS_RECONNECT|SESS_REDIRECT);
12242421Syokota     }
12342421Syokota
12442421Syokota     if((sess->soc = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
12542421Syokota	  fprintf(stderr, "tcpConnect: socket: %m");
12656334Syokota	  return 0;
12756334Syokota     }
12856334Syokota
12956334Syokota     memset(&hints, 0, sizeof(hints));
13042421Syokota     hints.ai_family	= PF_INET;
13142421Syokota     hints.ai_socktype	= SOCK_STREAM;
13242421Syokota
13356334Syokota     debug(3, "targetAddress=%s port=%d", op->targetAddress, op->port);
13456334Syokota     if(inet_aton(op->targetAddress, &ipn))
13556334Syokota	  hints.ai_flags |= AI_NUMERICHOST;
13656334Syokota     if((val = getaddrinfo(op->targetAddress, NULL, &hints, &res)) != 0) {
13756334Syokota          fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val));
13856334Syokota          return 0;
13956334Syokota     }
14042421Syokota     memcpy(&sn, res->ai_addr, sizeof(struct sockaddr_in));
14142421Syokota     sn.sin_port = htons(op->port);
14256334Syokota     freeaddrinfo(res);
14356334Syokota
14456334Syokota     // from Patrick.Guelat@imp.ch:
14556334Syokota     // iscontrol can be called without waiting for the socket entry to time out
14656334Syokota     val = 1;
14756334Syokota     if(setsockopt(sess->soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) {
14856334Syokota	  fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n",
14956334Syokota		  errno, strerror(errno));
15042421Syokota     }
15142421Syokota
15242421Syokota     sess->flags &= ~SESS_CONNECTED;
15342421Syokota
15442421Syokota     if(connect(sess->soc, (struct sockaddr *)&sn, sizeof(struct sockaddr_in)) != -1) {
15542421Syokota#if 0
15642421Syokota	  struct	timeval timeout;
15742421Syokota
15842421Syokota	  val = 1;
15942421Syokota	  if(setsockopt(sess->soc, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0)
16042421Syokota	       fprintf(stderr, "Cannot set socket KEEPALIVE option err=%d %s\n",
16144628Syokota		       errno, strerror(errno));
16242421Syokota
16342421Syokota	  if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0)
16442421Syokota	       fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n",
16542421Syokota		       errno, strerror(errno));
16642421Syokota
16742421Syokota	  timeout.tv_sec = 10;
16842421Syokota	  timeout.tv_usec = 0;
16942421Syokota	  if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
17042421Syokota	     || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)) {
17142421Syokota	       fprintf(stderr, "Cannot set socket timeout to %ld err=%d %s\n",
17242421Syokota		       timeout.tv_sec, errno, strerror(errno));
17342421Syokota	  }
17442421Syokota#endif
17542421Syokota#ifdef CURIOUS
17642421Syokota	  {
17742421Syokota	       int len = sizeof(val);
17842421Syokota	       if(getsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0)
17942421Syokota		    fprintf(stderr, "was: SO_SNDBUF=%dK\n", val/1024);
18042421Syokota	  }
18142421Syokota#endif
18242421Syokota	  if(sess->op->sockbufsize) {
18344628Syokota	       val = sess->op->sockbufsize * 1024;
18442421Syokota	       if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0)
18542421Syokota		  || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)) {
18642421Syokota		    fprintf(stderr, "Cannot set socket sndbuf & rcvbuf to %d err=%d %s\n",
18742421Syokota			    val, errno, strerror(errno));
18842421Syokota		    return 0;
18942421Syokota	       }
19042421Syokota	  }
19142421Syokota	  sess->flags |= SESS_CONNECTED;
19242421Syokota	  return T1;
19342421Syokota
19442421Syokota     }
19542421Syokota     sv_errno = errno;
19642421Syokota     fprintf(stderr, "errno=%d\n", sv_errno);
19742421Syokota     perror("connect");
19842421Syokota     switch(sv_errno) {
19942421Syokota     case ECONNREFUSED:
20042421Syokota     case ENETUNREACH:
20142421Syokota     case ETIMEDOUT:
20242421Syokota	  sleep(5); // for now ...
20342421Syokota	  return T1;
20442421Syokota     default:
20542421Syokota	  return 0; // terminal error
20642421Syokota     }
20742421Syokota
20844628Syokota}
20942421Syokota
21042421Syokotaint
21142421SyokotasetOptions(isess_t *sess, int flag)
21242421Syokota{
21342421Syokota     isc_opt_t	oop;
21442421Syokota     char	*sep;
21542421Syokota
21642421Syokota     debug_called(3);
21742421Syokota
21842421Syokota     bzero(&oop, sizeof(isc_opt_t));
21942421Syokota
22042421Syokota     if((flag & SESS_FULLFEATURE) == 0) {
22142421Syokota	  oop.initiatorName	= sess->op->initiatorName;
22242421Syokota	  oop.targetAddress	= sess->op->targetAddress;
22342421Syokota	  if(sess->op->targetName != 0)
22442421Syokota	       oop.targetName = sess->op->targetName;
22542421Syokota
22642421Syokota	  oop.maxRecvDataSegmentLength = sess->op->maxRecvDataSegmentLength;
22742421Syokota	  oop.maxXmitDataSegmentLength = sess->op->maxXmitDataSegmentLength; // XXX:
22844628Syokota	  oop.maxBurstLength = sess->op->maxBurstLength;
22942421Syokota	  oop.maxluns = sess->op->maxluns;
23042421Syokota     }
23142421Syokota     else {
23242421Syokota	  /*
23342421Syokota	   | turn on digestion only after login
23442421Syokota	   */
23555731Syokota	  if(sess->op->headerDigest != NULL) {
23642421Syokota	       sep = strchr(sess->op->headerDigest, ',');
23742421Syokota	       if(sep == NULL)
23842421Syokota		    oop.headerDigest = sess->op->headerDigest;
23942421Syokota	       debug(1, "oop.headerDigest=%s", oop.headerDigest);
24042421Syokota	  }
24142421Syokota	  if(sess->op->dataDigest != NULL) {
24244628Syokota	       sep = strchr(sess->op->dataDigest, ',');
24354543Syokota	       if(sep == NULL)
24454543Syokota		    oop.dataDigest = sess->op->dataDigest;
24542421Syokota	       debug(1, "oop.dataDigest=%s", oop.dataDigest);
24642421Syokota	  }
24742421Syokota     }
24842421Syokota
24944628Syokota     if(ioctl(sess->fd, ISCSISETOPT, &oop)) {
25044628Syokota	  perror("ISCSISETOPT");
25144628Syokota	  return -1;
25244628Syokota     }
25342831Syokota     return 0;
25442421Syokota}
25542421Syokota
25642421Syokotastatic trans_t
25742421SyokotastartSession(isess_t *sess)
25842421Syokota{
25942421Syokota
26042421Syokota     int	n, fd, nfd;
26142421Syokota     char	*dev;
26242421Syokota
26342421Syokota     debug_called(3);
26442421Syokota
26542421Syokota     if((sess->flags & SESS_CONNECTED) == 0) {
26642421Syokota	  return T2;
26742421Syokota     }
26842421Syokota     if(sess->fd == -1) {
26942421Syokota	  fd = open(iscsidev, O_RDWR);
27042421Syokota	  if(fd < 0) {
27142421Syokota	       perror(iscsidev);
27242421Syokota	       return 0;
27342421Syokota	  }
27442421Syokota	  {
27542421Syokota	       // XXX: this has to go
27644628Syokota	       size_t	n;
27742421Syokota	       n = sizeof(sess->isid);
27848878Syokota	       if(sysctlbyname("net.iscsi.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0)
27948878Syokota		    perror("sysctlbyname");
28048878Syokota	  }
28146764Syokota	  if(ioctl(fd, ISCSISETSES, &n)) {
28246764Syokota	       perror("ISCSISETSES");
28346764Syokota	       return 0;
28446764Syokota	  }
28546764Syokota	  asprintf(&dev, "%s%d", iscsidev, n);
28646764Syokota	  nfd = open(dev, O_RDWR);
28746764Syokota	  if(nfd < 0) {
28846764Syokota	       perror(dev);
28944628Syokota	       free(dev);
29048878Syokota	       return 0;
29144628Syokota	  }
29245720Speter	  free(dev);
29346764Syokota	  close(fd);
29446764Syokota	  sess->fd = nfd;
29546764Syokota
29646764Syokota	  if(setOptions(sess, 0) != 0)
29742421Syokota	       return -1;
29842421Syokota     }
29942421Syokota
30044628Syokota     if(ioctl(sess->fd, ISCSISETSOC, &sess->soc)) {
30144628Syokota	  perror("ISCSISETSOC");
30242421Syokota	  return 0;
30344628Syokota     }
30444628Syokota
30542421Syokota     return T4;
30644628Syokota}
30744628Syokota
30844628Syokotaisess_t *currsess;
30944628Syokota
31044628Syokotastatic void
31144628Syokotatrap(int sig)
31244628Syokota{
31344628Syokota     syslog(LOG_NOTICE, "trapped signal %d", sig);
31444628Syokota     fprintf(stderr, "trapped signal %d\n", sig);
31544628Syokota
31644628Syokota     switch(sig) {
31758271Syokota     case SIGHUP:
31844628Syokota	  currsess->flags |= SESS_DISCONNECT;
31944628Syokota	  break;
32044628Syokota
32144628Syokota     case SIGUSR1:
32242421Syokota	  currsess->flags |= SESS_RECONNECT;
32342421Syokota	  break;
32442421Syokota
32558271Syokota     case SIGINT:
32644628Syokota     case SIGTERM:
32744628Syokota     default:
32844628Syokota	  return; // ignore
32944628Syokota     }
33044628Syokota}
33142421Syokota
33244628Syokotastatic void
33342421SyokotadoCAM(isess_t *sess)
33442421Syokota{
33544628Syokota     char	pathstr[1024];
33642421Syokota     union ccb	*ccb;
33744628Syokota     int	i;
33842421Syokota
33942421Syokota     if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) {
34042421Syokota	  syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno);
34142421Syokota	  return;
34242421Syokota     }
34342421Syokota     debug(2, "nluns=%d", sess->cam.target_nluns);
34442421Syokota     /*
34555731Syokota      | for now will do this for each lun ...
34658271Syokota      */
34742421Syokota     for(i = 0; i < sess->cam.target_nluns; i++) {
34842421Syokota	  debug(2, "CAM path_id=%d target_id=%d target_lun=%d",
34942421Syokota		sess->cam.path_id, sess->cam.target_id, sess->cam.target_lun[i]);
35042421Syokota
35144628Syokota	  sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id,
35242421Syokota				      sess->cam.target_lun[i], O_RDWR, NULL);
35342421Syokota	  if(sess->camdev == NULL) {
35442421Syokota	       syslog(LOG_WARNING, "%s", cam_errbuf);
35542421Syokota	       debug(3, "%s", cam_errbuf);
35642421Syokota	       continue;
35742421Syokota	  }
35842421Syokota
35942421Syokota	  cam_path_string(sess->camdev, pathstr, sizeof(pathstr));
36042421Syokota	  debug(2, "pathstr=%s", pathstr);
36142421Syokota
36242421Syokota	  ccb = cam_getccb(sess->camdev);
36342421Syokota	  bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
36442421Syokota	  ccb->ccb_h.func_code = XPT_REL_SIMQ;
36542421Syokota	  ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
36642421Syokota	  ccb->crs.openings = sess->op->tags;
36742421Syokota
36842421Syokota	  if(cam_send_ccb(sess->camdev, ccb) < 0)
36942421Syokota	       syslog(LOG_WARNING, "%s", cam_errbuf);
37042421Syokota	  else
37142421Syokota	  if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
37242421Syokota	       syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed");
37342421Syokota	       // cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
37442421Syokota	  }
37542421Syokota	  else
37642421Syokota	       syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings);
37742421Syokota
37842421Syokota	  cam_freeccb(ccb);
37942421Syokota	  cam_close_device(sess->camdev);
38042421Syokota     }
38142421Syokota}
38242421Syokota
38344628Syokotastatic trans_t
38442421Syokotasupervise(isess_t *sess)
38542421Syokota{
38642421Syokota     int	sig, val;
38742421Syokota
38842421Syokota     debug_called(3);
38942421Syokota
39042421Syokota     if(strcmp(sess->op->sessionType, "Discovery") == 0) {
39142421Syokota	  sess->flags |= SESS_DISCONNECT;
39242421Syokota	  return T9;
39342421Syokota     }
39442421Syokota
39544628Syokota     if(vflag)
39658271Syokota	  printf("ready to go scsi\n");
39744628Syokota
39842421Syokota     if(setOptions(sess, SESS_FULLFEATURE) != 0)
39944628Syokota	  return 0; // failure
40058271Syokota
40144628Syokota     if((sess->flags & SESS_FULLFEATURE) == 0) {
40244628Syokota	  if(daemon(0, 1) != 0) {
40344628Syokota	       perror("daemon");
40444628Syokota	       exit(1);
40544628Syokota	  }
40644628Syokota
40744628Syokota	  openlog("iscontrol", LOG_CONS|LOG_PERROR|LOG_PID|LOG_NDELAY, LOG_KERN);
40844628Syokota	  syslog(LOG_INFO, "running");
40944628Syokota
41044628Syokota	  currsess = sess;
41144628Syokota	  if(ioctl(sess->fd, ISCSISTART)) {
41244628Syokota	       perror("ISCSISTART");
41344628Syokota	       return -1;
41444628Syokota	  }
41544628Syokota	  doCAM(sess);
41644628Syokota
41744628Syokota     }
41844628Syokota     else {
41944628Syokota
42044628Syokota	  if(ioctl(sess->fd, ISCSIRESTART)) {
42142421Syokota	       perror("ISCSIRESTART");
42244628Syokota	       return -1;
42349820Syokota	  }
42442421Syokota     }
42544628Syokota
42644628Syokota     signal(SIGINT, trap);
42742421Syokota     signal(SIGHUP, trap);
42844628Syokota     signal(SIGTERM, trap);
42955731Syokota
43055731Syokota     sig = SIGUSR1;
43155731Syokota     signal(sig, trap);
43255731Syokota     if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
43342421Syokota	  perror("ISCSISIGNAL");
43442421Syokota	  return -1;
43542421Syokota     }
43642421Syokota     sess->flags |= SESS_FULLFEATURE;
43742421Syokota
43842421Syokota     sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT);
43942421Syokota     printf("iscontrol: supervise starting main loop\n");
44042421Syokota     /*
44142421Syokota      | the main loop - actually do nothing
44242421Syokota      | all the work is done inside the kernel
44342421Syokota      */
44442421Syokota     while((sess->flags & (SESS_REDIRECT|SESS_RECONNECT|SESS_DISCONNECT)) == 0) {
44542421Syokota	  // do something?
44642421Syokota	  // like sending a nop_out?
44742421Syokota	  sleep(60);
44842421Syokota     }
44942421Syokota     printf("iscontrol: supervise going down\n");
45042421Syokota     syslog(LOG_INFO, "sess flags=%x", sess->flags);
45142421Syokota
45242421Syokota     sig = 0;
45342421Syokota     if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
45444628Syokota	  perror("ISCSISIGNAL");
45542421Syokota     }
45642421Syokota
45755731Syokota     if(sess->flags & SESS_DISCONNECT) {
45842421Syokota	  val = 0;
45942421Syokota	  if(ioctl(sess->fd, ISCSISTOP, &val)) {
46042421Syokota	       perror("ISCSISTOP");
46142421Syokota	  }
46242421Syokota	  sess->flags &= ~SESS_FULLFEATURE;
46342421Syokota	  return T9;
46442421Syokota     }
46542421Syokota     else {
46642421Syokota	  sess->flags |= SESS_INITIALLOGIN1;
46742421Syokota     }
46842421Syokota     return T8;
46942421Syokota}
47042421Syokota
47142421Syokotastatic int
47242421SyokotahandledDiscoveryResp(isess_t *sess, pdu_t *pp)
47342421Syokota{
47442421Syokota     u_char	*ptr;
47542421Syokota     int	len, n;
47642421Syokota
47742421Syokota     debug_called(3);
47842421Syokota
47955731Syokota     len = pp->ds_len;
48055731Syokota     ptr = pp->ds;
48155731Syokota     while(len > 0) {
48255731Syokota	  if(*ptr != 0)
48342421Syokota	       printf("%s\n", ptr);
48442421Syokota	  n = strlen((char *)ptr) + 1;
48542421Syokota	  len -= n;
48642421Syokota	  ptr += n;
48742421Syokota     }
48842421Syokota     return 0;
48942421Syokota}
49042421Syokota
49142421Syokotastatic int
49242421SyokotadoDiscovery(isess_t *sess)
49342421Syokota{
49442421Syokota     pdu_t	spp;
49542421Syokota     text_req_t	*tp = (text_req_t *)&spp.ipdu.bhs;
49642421Syokota
49742421Syokota     debug_called(3);
49842421Syokota
49942421Syokota     bzero(&spp, sizeof(pdu_t));
50042421Syokota     tp->cmd = ISCSI_TEXT_CMD /*| 0x40 */; // because of a bug in openiscsi-target
50142421Syokota     tp->F = 1;
50242421Syokota     tp->ttt = 0xffffffff;
50342421Syokota     addText(&spp, "SendTargets=All");
50442421Syokota     return sendPDU(sess, &spp, handledDiscoveryResp);
50542421Syokota}
50642421Syokota
50742421Syokotastatic trans_t
50842421SyokotadoLogin(isess_t *sess)
50942421Syokota{
51042421Syokota     isc_opt_t	*op = sess->op;
51142421Syokota     int	status, count;
51242421Syokota
51342421Syokota     debug_called(3);
51442421Syokota
51542421Syokota     if(op->chapSecret == NULL && op->tgtChapSecret == NULL)
51642421Syokota	  /*
51742421Syokota	   | don't need any security negotiation
51842421Syokota	   | or in other words: we don't have any secrets to exchange
51942421Syokota	   */
52042421Syokota	  sess->csg = LON_PHASE;
52142421Syokota     else
52242421Syokota	  sess->csg = SN_PHASE;
52342421Syokota
52442421Syokota     if(sess->tsih) {
52542421Syokota	  sess->tsih = 0;	// XXX: no 'reconnect' yet
52642421Syokota	  sess->flags &= ~SESS_NEGODONE; // XXX: KLUDGE
52742421Syokota     }
52842421Syokota     count = 10; // should be more than enough
52942421Syokota     do {
53042421Syokota	  debug(3, "count=%d csg=%d", count, sess->csg);
53142421Syokota	  status = loginPhase(sess);
53242421Syokota	  if(count-- == 0)
53342421Syokota	       // just in case we get into a loop
53442421Syokota	       status = -1;
53542421Syokota     } while(status == 0 && (sess->csg != FF_PHASE));
53642421Syokota
53742421Syokota     sess->flags &= ~SESS_INITIALLOGIN;
53842421Syokota     debug(3, "status=%d", status);
53942421Syokota
54042421Syokota     switch(status) {
54142421Syokota     case 0: // all is ok ...
54242421Syokota	  sess->flags |= SESS_LOGGEDIN;
54342421Syokota	  if(strcmp(sess->op->sessionType, "Discovery") == 0)
54442421Syokota	       doDiscovery(sess);
54554382Syokota	  return T5;
54654382Syokota
54742421Syokota     case 1:	// redirect - temporary/permanent
54842421Syokota	  /*
54942421Syokota	   | start from scratch?
55042421Syokota	   */
55142421Syokota	  sess->flags &= ~SESS_NEGODONE;
55242421Syokota	  sess->flags |= (SESS_REDIRECT | SESS_INITIALLOGIN1);
55342421Syokota	  syslog(LOG_DEBUG, "target sent REDIRECT");
55442421Syokota	  return T7;
55542421Syokota
55642421Syokota     case 2: // initiator terminal error
55742421Syokota     case 3: // target terminal error -- could retry ...
55842421Syokota     default:
55942421Syokota	  return 0;
56042421Syokota     }
56142421Syokota}
56242421Syokota
56342421Syokotastatic int
56442421SyokotahandleLogoutResp(isess_t *sess, pdu_t *pp)
56542421Syokota{
56642421Syokota     if(sess->flags & SESS_DISCONNECT)
56742421Syokota	  return 0;
56842421Syokota     return T13;
56942421Syokota}
57042421Syokota
57142421Syokotastatic trans_t
57242421SyokotastartLogout(isess_t *sess)
57342421Syokota{
57442421Syokota     pdu_t	spp;
57542421Syokota     logout_req_t *p = (logout_req_t *)&spp.ipdu.bhs;
57642421Syokota
57742421Syokota     bzero(&spp, sizeof(pdu_t));
57842421Syokota     p->cmd = ISCSI_LOGOUT_CMD| 0x40;
57942421Syokota     p->reason = BIT(7) | 0;
58042421Syokota     p->CID = htons(1);
58142421Syokota
58242421Syokota     return sendPDU(sess, &spp, handleLogoutResp);
58342421Syokota}
58442421Syokota
58542421Syokotastatic trans_t
58642421SyokotainLogout(isess_t *sess)
58742421Syokota{
58842421Syokota     if(sess->flags & SESS_RECONNECT)
58954382Syokota	  return T18;
59042421Syokota     return 0;
59154382Syokota}
59254382Syokota
59354382Syokotatypedef enum {
59454382Syokota     S1, S2, /*S3,*/ S4, S5, S6, S7, S8
59542421Syokota} state_t;
59642421Syokota
59742421Syokota#if 0
59842421Syokota      S1: FREE
59942421Syokota      S2: XPT_WAIT
60042421Syokota      S4: IN_LOGIN
60142421Syokota      S5: LOGGED_IN
60242421Syokota      S6: IN_LOGOUT
60342421Syokota      S7: LOGOUT_REQUESTED
60442421Syokota      S8: CLEANUP_WAIT
60542421Syokota
60642421Syokota                     -------<-------------+
60742421Syokota         +--------->/ S1    \<----+       |
60842421Syokota      T13|       +->\       /<-+   \      |
60942421Syokota         |      /    ---+---    \   \     |
61042421Syokota         |     /        |     T2 \   |    |
61142421Syokota         |  T8 |        |T1       |  |    |
61242421Syokota         |     |        |        /   |T7  |
61342421Syokota         |     |        |       /    |    |
61442421Syokota         |     |        |      /     |    |
61542421Syokota         |     |        V     /     /     |
61642421Syokota         |     |     ------- /     /      |
61742421Syokota         |     |    / S2    \     /       |
61842421Syokota         |     |    \       /    /        |
61942421Syokota         |     |     ---+---    /         |
62042421Syokota         |     |        |T4    /          |
62142421Syokota         |     |        V     /           | T18
62242421Syokota         |     |     ------- /            |
62342421Syokota         |     |    / S4    \             |
62442421Syokota         |     |    \       /             |
62542421Syokota         |     |     ---+---              |         T15
62642421Syokota         |     |        |T5      +--------+---------+
62742421Syokota         |     |        |       /T16+-----+------+  |
62842421Syokota         |     |        |      /   -+-----+--+   |  |
62942421Syokota         |     |        |     /   /  S7   \  |T12|  |
63042421Syokota         |     |        |    / +->\       /<-+   V  V
63142421Syokota         |     |        |   / /    -+-----       -------
63242421Syokota         |     |        |  / /T11   |T10        /  S8   \
63342421Syokota         |     |        V / /       V  +----+   \       /
63442421Syokota         |     |      ---+-+-      ----+--  |    -------
63542421Syokota         |     |     / S5    \T9  / S6    \<+    ^
63642421Syokota         |     +-----\       /--->\       / T14  |
63742421Syokota         |            -------      --+----+------+T17
63842421Syokota         +---------------------------+
63942421Syokota#endif
64042421Syokota
64143337Syokotaint
64243337Syokotafsm(isc_opt_t *op)
64343337Syokota{
64442421Syokota     state_t	state;
64542421Syokota     isess_t	*sess;
64642421Syokota
64742421Syokota     if((sess = calloc(1, sizeof(isess_t))) == NULL) {
64842421Syokota	  // boy, is this a bad start ...
64942421Syokota	  fprintf(stderr, "no memory!\n");
65042421Syokota	  return -1;
65142421Syokota     }
65242421Syokota
65342421Syokota     state = S1;
65442421Syokota     sess->op = op;
65542421Syokota     sess->fd = -1;
65642421Syokota     sess->soc = -1;
65742421Syokota
65842421Syokota     sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1;
65942421Syokota
66042421Syokota     do {
66142421Syokota	  switch(state) {
66242421Syokota
66342421Syokota	  case S1:
66442421Syokota	       switch(tcpConnect(sess)) {
66542421Syokota	       case T1: state = S2; break;
66642421Syokota	       default: state = S8; break;
66742421Syokota	       }
66842421Syokota	       break;
66942421Syokota
67042421Syokota	  case S2:
67142421Syokota	       switch(startSession(sess)) {
67242421Syokota	       case T2: state = S1; break;
67342421Syokota	       case T4: state = S4; break;
67442421Syokota	       default: state = S8; break;
67542421Syokota	       }
67642421Syokota	       break;
67742421Syokota
67842421Syokota	  case S4:
67942421Syokota	       switch(doLogin(sess)) {
68042421Syokota	       case T7:  state = S1; break;
68142421Syokota	       case T5:  state = S5; break;
68242421Syokota	       default: state = S8; break;
68342421Syokota	       }
68442421Syokota	       break;
68542421Syokota
68642421Syokota	  case S5:
68742421Syokota	       switch(supervise(sess)) {
68842421Syokota	       case T8:  state = S1; break;
68943337Syokota	       case T9:  state = S6; break;
69043337Syokota	       case T11: state = S7; break;
69143337Syokota	       case T15: state = S8; break;
69243337Syokota	       default: state = S8; break;
69343337Syokota	       }
69443337Syokota	       break;
69542421Syokota
69642421Syokota	  case S6:
69742421Syokota	       switch(startLogout(sess)) {
69842421Syokota	       case T13: state = S1; break;
69942421Syokota	       case T14: state = S6; break;
70042421Syokota	       case T16: state = S8; break;
70142421Syokota	       default: state = S8; break;
70242421Syokota	       }
70343337Syokota	       break;
70442421Syokota
70542421Syokota	  case S7:
70642421Syokota	       switch(inLogout(sess)) {
70742421Syokota	       case T18: state = S1; break;
70843337Syokota	       case T10: state = S6; break;
70943337Syokota	       case T12: state = S7; break;
71043337Syokota	       case T16: state = S8; break;
71143337Syokota	       default: state = S8; break;
71243337Syokota	       }
71343337Syokota	       break;
71443337Syokota
71543337Syokota	  case S8:
71643337Syokota	       // maybe do some clean up?
71743337Syokota	       syslog(LOG_INFO, "terminated");
71843337Syokota	       return 0;
71943337Syokota	  }
72043337Syokota     } while(1);
72143337Syokota}
72243337Syokota