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