Retire obsolete iscsi_initiator(4)

The new iSCSI initiator iscsi(4) was introduced with FreeBSD 10.0, and
the old intiator was marked obsolete shortly thereafter (in commit
d32789d95c, MFC'd to stable/10 in ba54910169).  Remove it now.

Reviewed by:	jhb, mav
Relnotes:	yes
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D32673
This commit is contained in:
Ed Maste 2021-10-26 13:24:30 -04:00
parent 12752978d3
commit 48cb3fee25
32 changed files with 6 additions and 7509 deletions

View file

@ -40,6 +40,11 @@
# xargs -n1 | sort | uniq -d;
# done
# 20211026: retire obsolete iscsi initiator
OLD_FILES+=sbin/iscontrol
OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz
OLD_FILES+=usr/share/man/man8/iscontrol.8.gz
# 20211022
OLD_FILES+=sbin/spppcontrol
.if ${TARGET_ARCH} == "i386"

View file

@ -76,7 +76,6 @@ SUBDIR.${MK_INET6}+= rtsol
SUBDIR.${MK_IPFILTER}+= ipf
SUBDIR.${MK_IPFW}+= ipfw
SUBDIR.${MK_IPFW}+= natd
SUBDIR.${MK_ISCSI}+= iscontrol
SUBDIR.${MK_NVME}+= nvmecontrol
SUBDIR.${MK_OPENSSL}+= decryptcore
SUBDIR.${MK_PF}+= pfctl

View file

@ -1,14 +0,0 @@
# $FreeBSD$
PACKAGE=iscsilegacy
SRCS= iscontrol.c pdu.c fsm.c config.c login.c auth_subr.c misc.c
PROG= iscontrol
LIBADD= cam md
S= ${SRCTOP}/sys
WARNS?= 3
CFLAGS+= -I$S
MAN= iscontrol.8
.include <bsd.prog.mk>

View file

@ -1,21 +0,0 @@
# $FreeBSD$
# Autogenerated - do NOT edit!
DIRDEPS = \
gnu/lib/csu \
include \
include/arpa \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcam \
lib/libcompiler_rt \
lib/libmd \
lib/libsbuf \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View file

@ -1,206 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: auth_subr.c,v 2.2 2007/06/01 08:09:37 danny Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <md5.h>
#include <sha.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static int
chapMD5(char id, char *cp, char *chapSecret, unsigned char *digest)
{
MD5_CTX ctx;
char *tmp;
int len;
debug_called(3);
MD5Init(&ctx);
MD5Update(&ctx, &id, 1);
if((len = str2bin(chapSecret, &tmp)) == 0) {
// print error
return -1;
}
MD5Update(&ctx, tmp, len);
free(tmp);
if((len = str2bin(cp, &tmp)) == 0) {
// print error
return -1;
}
MD5Update(&ctx, tmp, len);
free(tmp);
MD5Final(digest, &ctx);
return 0;
}
static int
chapSHA1(char id, char *cp, char *chapSecret, unsigned char *digest)
{
SHA1_CTX ctx;
char *tmp;
int len;
debug_called(3);
SHA1_Init(&ctx);
SHA1_Update(&ctx, &id, 1);
if((len = str2bin(chapSecret, &tmp)) == 0) {
// print error
return -1;
}
SHA1_Update(&ctx, tmp, len);
free(tmp);
if((len = str2bin(cp, &tmp)) == 0) {
// print error
return -1;
}
SHA1_Update(&ctx, tmp, len);
free(tmp);
SHA1_Final(digest, &ctx);
return 0;
}
/*
| the input text format can be anything that the rfc3270 defines
| (see section 5.1 and str2bin)
| digest length for md5 is 128bits, and for sha1 is 160bits.
| digest is an ASCII string which represents the bits in
| hexadecimal or base64 according to the challenge(cp) format
*/
char *
chapDigest(char *ap, char id, char *cp, char *chapSecret)
{
int len;
unsigned char digest[20];
char encoding[3];
debug_called(3);
len = 0;
if(strcmp(ap, "5") == 0 && chapMD5(id, cp, chapSecret, digest) == 0)
len = 16;
else
if(strcmp(ap, "7") == 0 && chapSHA1(id, cp, chapSecret, digest) == 0)
len = 20;
if(len) {
sprintf(encoding, "%.2s", cp);
return bin2str(encoding, digest, len);
}
return NULL;
}
char *
genChapChallenge(char *encoding, uint len)
{
int fd;
unsigned char tmp[1024];
if(len > sizeof(tmp))
return NULL;
if((fd = open("/dev/random", O_RDONLY)) != -1) {
read(fd, tmp, len);
close(fd);
return bin2str(encoding, tmp, len);
}
perror("/dev/random");
// make up something ...
return NULL;
}
#ifdef TEST_AUTH
static void
puke(char *str, unsigned char *dg, int len)
{
printf("%3d] %s\n 0x", len, str);
while(len-- > 0)
printf("%02x", *dg++);
printf("\n");
}
main(int cc, char **vv)
{
char *p, *ap, *ip, *cp, *chapSecret, *digest;
int len;
#if 0
ap = "5";
chapSecret = "0xa5aff013dd839b1edd31ee73a1df0b1b";
// chapSecret = "abcdefghijklmnop";
len = str2bin(chapSecret, &cp);
puke(chapSecret, cp, len);
ip = "238";
cp = "0xbd456029";
if((digest = chapDigest(ap, ip, cp, chapSecret)) != NULL) {
len = str2bin(digest, &cp);
puke(digest, cp, len);
}
#else
printf("%d] %s\n", 24, genChallenge("0X", 24));
#endif
}
#endif

View file

@ -1,382 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2009 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: config.c,v 2.1 2006/11/12 08:06:51 danny Exp danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <ctype.h>
#include <camlib.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
/*
| ints
*/
#define OPT_port 1
#define OPT_tags 2
#define OPT_maxConnections 3
#define OPT_maxRecvDataSegmentLength 4
#define OPT_maxXmitDataSegmentLength 5
#define OPT_maxBurstLength 6
#define OPT_firstBurstLength 7
#define OPT_defaultTime2Wait 8
#define OPT_defaultTime2Retain 9
#define OPT_maxOutstandingR2T 10
#define OPT_errorRecoveryLevel 11
#define OPT_targetPortalGroupTag 12
#define OPT_headerDigest 13
#define OPT_dataDigest 14
/*
| Booleans
*/
#define OPT_initialR2T 16
#define OPT_immediateData 17
#define OPT_dataPDUInOrder 18
#define OPT_dataSequenceInOrder 19
/*
| strings
*/
#define OPT_sessionType 15
#define OPT_targetAddress 21
#define OPT_targetAlias 22
#define OPT_targetName 23
#define OPT_initiatorName 24
#define OPT_initiatorAlias 25
#define OPT_authMethod 26
#define OPT_chapSecret 27
#define OPT_chapIName 28
#define OPT_chapDigest 29
#define OPT_tgtChapName 30
#define OPT_tgtChapSecret 31
#define OPT_tgtChallengeLen 32
/*
| private
*/
#define OPT_maxluns 33
#define OPT_iqn 34
#define OPT_sockbufsize 35
/*
| sentinel
*/
#define OPT_end 0
#define _OFF(v) ((int)&((isc_opt_t *)NULL)->v)
#define _E(u, s, v) {.usage=u, .scope=s, .name=#v, .tokenID=OPT_##v}
textkey_t keyMap[] = {
_E(U_PR, S_PR, port),
_E(U_PR, S_PR, tags),
_E(U_PR, S_PR, maxluns),
_E(U_PR, S_PR, sockbufsize),
_E(U_PR, S_PR, iqn),
_E(U_PR, S_PR, chapSecret),
_E(U_PR, S_PR, chapIName),
_E(U_PR, S_PR, chapDigest),
_E(U_PR, S_PR, tgtChapName),
_E(U_PR, S_PR, tgtChapSecret),
_E(U_PR, S_PR, tgtChallengeLen),
_E(U_IO, S_CO, headerDigest),
_E(U_IO, S_CO, dataDigest),
_E(U_IO, S_CO, authMethod),
_E(U_LO, S_SW, maxConnections),
_E(U_IO, S_SW, targetName),
_E(U_IO, S_SW, initiatorName),
_E(U_ALL,S_SW, targetAlias),
_E(U_ALL,S_SW, initiatorAlias),
_E(U_ALL,S_SW, targetAddress),
_E(U_ALL,S_SW, targetPortalGroupTag),
_E(U_LO, S_SW, initialR2T),
_E(U_LO, S_SW, immediateData),
_E(U_ALL,S_CO, maxRecvDataSegmentLength),
_E(U_ALL,S_CO, maxXmitDataSegmentLength),
_E(U_LO, S_SW, maxBurstLength),
_E(U_LO, S_SW, firstBurstLength),
_E(U_LO, S_SW, defaultTime2Wait),
_E(U_LO, S_SW, defaultTime2Retain),
_E(U_LO, S_SW, maxOutstandingR2T),
_E(U_LO, S_SW, dataPDUInOrder),
_E(U_LO, S_SW, dataSequenceInOrder),
_E(U_LO, S_SW, errorRecoveryLevel),
_E(U_LO, S_SW, sessionType),
_E(0, 0, end)
};
#define _OPT_INT(w) strtol((char *)w, NULL, 0)
#define _OPT_STR(w) (char *)(w)
static __inline int
_OPT_BOOL(char *w)
{
if(isalpha((unsigned char)*w))
return strcasecmp(w, "TRUE") == 0;
else
return _OPT_INT(w);
}
#define _CASE(k, v) case OPT_##k: op->k = v; break
static void
setOption(isc_opt_t *op, int which, void *rval)
{
switch(which) {
_CASE(port, _OPT_INT(rval));
_CASE(tags, _OPT_INT(rval));
_CASE(maxluns, _OPT_INT(rval));
_CASE(iqn, _OPT_STR(rval));
_CASE(sockbufsize, _OPT_INT(rval));
_CASE(maxConnections, _OPT_INT(rval));
_CASE(maxRecvDataSegmentLength, _OPT_INT(rval));
_CASE(maxXmitDataSegmentLength, _OPT_INT(rval));
_CASE(maxBurstLength, _OPT_INT(rval));
_CASE(firstBurstLength, _OPT_INT(rval));
_CASE(defaultTime2Wait, _OPT_INT(rval));
_CASE(defaultTime2Retain, _OPT_INT(rval));
_CASE(maxOutstandingR2T, _OPT_INT(rval));
_CASE(errorRecoveryLevel, _OPT_INT(rval));
_CASE(targetPortalGroupTag, _OPT_INT(rval));
_CASE(headerDigest, _OPT_STR(rval));
_CASE(dataDigest, _OPT_STR(rval));
_CASE(targetAddress, _OPT_STR(rval));
_CASE(targetAlias, _OPT_STR(rval));
_CASE(targetName, _OPT_STR(rval));
_CASE(initiatorName, _OPT_STR(rval));
_CASE(initiatorAlias, _OPT_STR(rval));
_CASE(authMethod, _OPT_STR(rval));
_CASE(chapSecret, _OPT_STR(rval));
_CASE(chapIName, _OPT_STR(rval));
_CASE(chapDigest, _OPT_STR(rval));
_CASE(tgtChapName, _OPT_STR(rval));
_CASE(tgtChapSecret, _OPT_STR(rval));
_CASE(initialR2T, _OPT_BOOL(rval));
_CASE(immediateData, _OPT_BOOL(rval));
_CASE(dataPDUInOrder, _OPT_BOOL(rval));
_CASE(dataSequenceInOrder, _OPT_BOOL(rval));
}
}
static char *
get_line(FILE *fd)
{
static char *sp, line[BUFSIZ];
char *lp, *p;
do {
if(sp == NULL)
sp = fgets(line, sizeof line, fd);
if((lp = sp) == NULL)
break;
if((p = strchr(lp, '\n')) != NULL)
*p = 0;
if((p = strchr(lp, '#')) != NULL)
*p = 0;
if((p = strchr(lp, ';')) != NULL) {
*p++ = 0;
sp = p;
} else
sp = NULL;
if(*lp)
return lp;
} while (feof(fd) == 0);
return NULL;
}
static int
getConfig(FILE *fd, char *key, char **Ar, int *nargs)
{
char *lp, *p, **ar;
int state, len, n;
ar = Ar;
if(key)
len = strlen(key);
else
len = 0;
state = 0;
while((lp = get_line(fd)) != NULL) {
for(; isspace((unsigned char)*lp); lp++)
;
switch(state) {
case 0:
if((p = strchr(lp, '{')) != NULL) {
while((--p > lp) && *p && isspace((unsigned char)*p));
n = p - lp;
if(len && strncmp(lp, key, MAX(n, len)) == 0)
state = 2;
else
state = 1;
continue;
}
break;
case 1:
if(*lp == '}')
state = 0;
continue;
case 2:
if(*lp == '}')
goto done;
break;
}
for(p = &lp[strlen(lp)-1]; isspace((unsigned char)*p); p--)
*p = 0;
if((*nargs)-- > 0)
*ar++ = strdup(lp);
}
done:
if(*nargs > 0)
*ar = 0;
*nargs = ar - Ar;
return ar - Ar;
}
static textkey_t *
keyLookup(char *key)
{
textkey_t *tk;
for(tk = keyMap; tk->name && strcmp(tk->name, "end"); tk++) {
if(strcasecmp(key, tk->name) == 0)
return tk;
}
return NULL;
}
static void
puke(isc_opt_t *op)
{
printf("%24s = %d\n", "port", op->port);
printf("%24s = %d\n", "tags", op->tags);
printf("%24s = %d\n", "maxluns", op->maxluns);
printf("%24s = %s\n", "iqn", op->iqn);
printf("%24s = %d\n", "maxConnections", op->maxConnections);
printf("%24s = %d\n", "maxRecvDataSegmentLength", op->maxRecvDataSegmentLength);
printf("%24s = %d\n", "maxXmitDataSegmentLength", op->maxRecvDataSegmentLength);
printf("%24s = %d\n", "maxBurstLength", op->maxBurstLength);
printf("%24s = %d\n", "firstBurstLength", op->firstBurstLength);
printf("%24s = %d\n", "defaultTime2Wait", op->defaultTime2Wait);
printf("%24s = %d\n", "defaultTime2Retain", op->defaultTime2Retain);
printf("%24s = %d\n", "maxOutstandingR2T", op->maxOutstandingR2T);
printf("%24s = %d\n", "errorRecoveryLevel", op->errorRecoveryLevel);
printf("%24s = %d\n", "targetPortalGroupTag", op->targetPortalGroupTag);
printf("%24s = %s\n", "headerDigest", op->headerDigest);
printf("%24s = %s\n", "dataDigest", op->dataDigest);
printf("%24s = %d\n", "initialR2T", op->initialR2T);
printf("%24s = %d\n", "immediateData", op->immediateData);
printf("%24s = %d\n", "dataPDUInOrder", op->dataPDUInOrder);
printf("%24s = %d\n", "dataSequenceInOrder", op->dataSequenceInOrder);
printf("%24s = %s\n", "sessionType", op->sessionType);
printf("%24s = %s\n", "targetAddress", op->targetAddress);
printf("%24s = %s\n", "targetAlias", op->targetAlias);
printf("%24s = %s\n", "targetName", op->targetName);
printf("%24s = %s\n", "initiatorName", op->initiatorName);
printf("%24s = %s\n", "initiatorAlias", op->initiatorAlias);
printf("%24s = %s\n", "authMethod", op->authMethod);
printf("%24s = %s\n", "chapSecret", op->chapSecret);
printf("%24s = %s\n", "chapIName", op->chapIName);
printf("%24s = %s\n", "tgtChapName", op->tgtChapName);
printf("%24s = %s\n", "tgtChapSecret", op->tgtChapSecret);
printf("%24s = %d\n", "tgttgtChallengeLen", op->tgtChallengeLen);
}
void
parseArgs(int nargs, char **args, isc_opt_t *op)
{
char **ar;
char *p, *v;
textkey_t *tk;
for(ar = args; nargs > 0; nargs--, ar++) {
p = strchr(*ar, '=');
if(p == NULL)
continue;
*p = 0;
v = p + 1;
while(isspace((unsigned char)*--p))
*p = 0;
while(isspace((unsigned char)*v))
v++;
if((tk = keyLookup(*ar)) == NULL)
continue;
setOption(op, tk->tokenID, v);
}
}
void
parseConfig(FILE *fd, char *key, isc_opt_t *op)
{
char *Ar[256];
int cc;
cc = 256;
if(getConfig(fd, key, Ar, &cc))
parseArgs(cc, Ar, op);
if(vflag)
puke(op);
}

View file

@ -1,759 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: fsm.c,v 2.8 2007/05/19 16:34:21 danny Exp danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <syslog.h>
#include <stdarg.h>
#include <camlib.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
typedef enum {
T1 = 1,
T2, /*T3,*/ T4, T5, /*T6,*/ T7, T8, T9,
T10, T11, T12, T13, T14, T15, T16, T18
} trans_t;
/*
| now supports IPV6
| thanks to:
| Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
| ume@mahoroba.org ume@{,jp.}FreeBSD.org
| http://www.imasy.org/~ume/
*/
static trans_t
tcpConnect(isess_t *sess)
{
isc_opt_t *op = sess->op;
int val, sv_errno, soc;
struct addrinfo *res, *res0, hints;
char pbuf[10];
debug_called(3);
if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) {
syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT)
? "Reconnect": "Redirected");
debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected");
shutdown(sess->soc, SHUT_RDWR);
//close(sess->soc);
sess->soc = -1;
sess->flags &= ~SESS_CONNECTED;
if(sess->flags & SESS_REDIRECT) {
sess->redirect_cnt++;
sess->flags |= SESS_RECONNECT;
} else
sleep(2); // XXX: actually should be ?
#ifdef notyet
{
time_t sec;
// make sure we are not in a loop
// XXX: this code has to be tested
sec = time(0) - sess->reconnect_time;
if(sec > (5*60)) {
// if we've been connected for more that 5 minutes
// then just reconnect
sess->reconnect_time = sec;
sess->reconnect_cnt1 = 0;
}
else {
//
sess->reconnect_cnt1++;
if((sec / sess->reconnect_cnt1) < 2) {
// if less that 2 seconds from the last reconnect
// we are most probably looping
syslog(LOG_CRIT, "too many reconnects %d", sess->reconnect_cnt1);
return 0;
}
}
}
#endif
sess->reconnect_cnt++;
}
snprintf(pbuf, sizeof(pbuf), "%d", op->port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
debug(1, "targetAddress=%s port=%d", op->targetAddress, op->port);
if((val = getaddrinfo(op->targetAddress, pbuf, &hints, &res0)) != 0) {
fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val));
return 0;
}
sess->flags &= ~SESS_CONNECTED;
sv_errno = 0;
soc = -1;
for(res = res0; res; res = res->ai_next) {
soc = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (soc == -1)
continue;
// from Patrick.Guelat@imp.ch:
// iscontrol can be called without waiting for the socket entry to time out
val = 1;
if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) {
fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n",
errno, strerror(errno));
}
if(connect(soc, res->ai_addr, res->ai_addrlen) == 0)
break;
sv_errno = errno;
close(soc);
soc = -1;
}
freeaddrinfo(res0);
if(soc != -1) {
sess->soc = soc;
#if 0
struct timeval timeout;
val = 1;
if(setsockopt(sess->soc, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0)
fprintf(stderr, "Cannot set socket KEEPALIVE option err=%d %s\n",
errno, strerror(errno));
if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0)
fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n",
errno, strerror(errno));
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
|| (setsockopt(sess->soc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)) {
fprintf(stderr, "Cannot set socket timeout to %ld err=%d %s\n",
timeout.tv_sec, errno, strerror(errno));
}
#endif
#ifdef CURIOUS
{
int len = sizeof(val);
if(getsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0)
fprintf(stderr, "was: SO_SNDBUF=%dK\n", val/1024);
}
#endif
if(sess->op->sockbufsize) {
val = sess->op->sockbufsize * 1024;
if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0)
|| (setsockopt(sess->soc, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)) {
fprintf(stderr, "Cannot set socket sndbuf & rcvbuf to %d err=%d %s\n",
val, errno, strerror(errno));
return 0;
}
}
sess->flags |= SESS_CONNECTED;
return T1;
}
fprintf(stderr, "errno=%d\n", sv_errno);
perror("connect");
switch(sv_errno) {
case ECONNREFUSED:
case EHOSTUNREACH:
case ENETUNREACH:
case ETIMEDOUT:
if((sess->flags & SESS_REDIRECT) == 0) {
if(strcmp(op->targetAddress, sess->target.address) != 0) {
syslog(LOG_INFO, "reconnecting to original target address");
free(op->targetAddress);
op->targetAddress = sess->target.address;
op->port = sess->target.port;
op->targetPortalGroupTag = sess->target.pgt;
return T1;
}
}
sleep(5); // for now ...
return T1;
default:
return 0; // terminal error
}
}
int
setOptions(isess_t *sess, int flag)
{
isc_opt_t oop;
char *sep;
debug_called(3);
bzero(&oop, sizeof(isc_opt_t));
if((flag & SESS_FULLFEATURE) == 0) {
oop.initiatorName = sess->op->initiatorName;
oop.targetAddress = sess->op->targetAddress;
if(sess->op->targetName != 0)
oop.targetName = sess->op->targetName;
oop.maxRecvDataSegmentLength = sess->op->maxRecvDataSegmentLength;
oop.maxXmitDataSegmentLength = sess->op->maxXmitDataSegmentLength; // XXX:
oop.maxBurstLength = sess->op->maxBurstLength;
oop.maxluns = sess->op->maxluns;
}
else {
/*
| turn on digestion only after login
*/
if(sess->op->headerDigest != NULL) {
sep = strchr(sess->op->headerDigest, ',');
if(sep == NULL)
oop.headerDigest = sess->op->headerDigest;
debug(1, "oop.headerDigest=%s", oop.headerDigest);
}
if(sess->op->dataDigest != NULL) {
sep = strchr(sess->op->dataDigest, ',');
if(sep == NULL)
oop.dataDigest = sess->op->dataDigest;
debug(1, "oop.dataDigest=%s", oop.dataDigest);
}
}
if(ioctl(sess->fd, ISCSISETOPT, &oop)) {
perror("ISCSISETOPT");
return -1;
}
return 0;
}
static trans_t
startSession(isess_t *sess)
{
int n, fd, nfd;
char *dev;
debug_called(3);
if((sess->flags & SESS_CONNECTED) == 0) {
return T2;
}
if(sess->fd == -1) {
fd = open(iscsidev, O_RDWR);
if(fd < 0) {
perror(iscsidev);
return 0;
}
{
// XXX: this has to go
size_t n;
n = sizeof(sess->isid);
if(sysctlbyname("net.iscsi_initiator.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0)
perror("sysctlbyname");
}
if(ioctl(fd, ISCSISETSES, &n)) {
perror("ISCSISETSES");
return 0;
}
asprintf(&dev, "%s%d", iscsidev, n);
nfd = open(dev, O_RDWR);
if(nfd < 0) {
perror(dev);
free(dev);
return 0;
}
free(dev);
close(fd);
sess->fd = nfd;
if(setOptions(sess, 0) != 0)
return -1;
}
if(ioctl(sess->fd, ISCSISETSOC, &sess->soc)) {
perror("ISCSISETSOC");
return 0;
}
return T4;
}
isess_t *currsess;
static void
trap(int sig)
{
syslog(LOG_NOTICE, "trapped signal %d", sig);
fprintf(stderr, "trapped signal %d\n", sig);
switch(sig) {
case SIGHUP:
currsess->flags |= SESS_DISCONNECT;
break;
case SIGUSR1:
currsess->flags |= SESS_RECONNECT;
break;
case SIGINT:
case SIGTERM:
default:
return; // ignore
}
}
static int
doCAM(isess_t *sess)
{
char pathstr[1024];
union ccb *ccb;
int i, n;
if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) {
syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno);
return 0;
}
debug(1, "nluns=%d", sess->cam.target_nluns);
/*
| for now will do this for each lun ...
*/
for(n = i = 0; i < sess->cam.target_nluns; i++) {
debug(2, "CAM path_id=%d target_id=%d",
sess->cam.path_id, sess->cam.target_id);
sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id,
i, O_RDWR, NULL);
if(sess->camdev == NULL) {
//syslog(LOG_WARNING, "%s", cam_errbuf);
debug(3, "%s", cam_errbuf);
continue;
}
cam_path_string(sess->camdev, pathstr, sizeof(pathstr));
debug(2, "pathstr=%s", pathstr);
ccb = cam_getccb(sess->camdev);
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->crs);
ccb->ccb_h.func_code = XPT_REL_SIMQ;
ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
ccb->crs.openings = sess->op->tags;
if(cam_send_ccb(sess->camdev, ccb) < 0)
debug(2, "%s", cam_errbuf);
else
if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed");
// cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
}
else {
n++;
syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings);
}
cam_freeccb(ccb);
cam_close_device(sess->camdev);
}
return n;
}
static trans_t
supervise(isess_t *sess)
{
int sig, val;
debug_called(3);
if(strcmp(sess->op->sessionType, "Discovery") == 0) {
sess->flags |= SESS_DISCONNECT;
return T9;
}
if(vflag)
printf("ready to go scsi\n");
if(setOptions(sess, SESS_FULLFEATURE) != 0)
return 0; // failure
if((sess->flags & SESS_FULLFEATURE) == 0) {
if(daemon(0, 1) != 0) {
perror("daemon");
exit(1);
}
if(sess->op->pidfile != NULL) {
FILE *pidf;
pidf = fopen(sess->op->pidfile, "w");
if(pidf != NULL) {
fprintf(pidf, "%d\n", getpid());
fclose(pidf);
}
}
openlog("iscontrol", LOG_CONS|LOG_PERROR|LOG_PID|LOG_NDELAY, LOG_KERN);
syslog(LOG_INFO, "running");
currsess = sess;
if(ioctl(sess->fd, ISCSISTART)) {
perror("ISCSISTART");
return -1;
}
if(doCAM(sess) == 0) {
syslog(LOG_WARNING, "no device found");
ioctl(sess->fd, ISCSISTOP);
return T15;
}
}
else {
if(ioctl(sess->fd, ISCSIRESTART)) {
perror("ISCSIRESTART");
return -1;
}
}
signal(SIGINT, trap);
signal(SIGHUP, trap);
signal(SIGTERM, trap);
sig = SIGUSR1;
signal(sig, trap);
if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
perror("ISCSISIGNAL");
return -1;
}
sess->flags |= SESS_FULLFEATURE;
sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT);
if(vflag)
printf("iscontrol: supervise starting main loop\n");
/*
| the main loop - actually do nothing
| all the work is done inside the kernel
*/
while((sess->flags & (SESS_REDIRECT|SESS_RECONNECT|SESS_DISCONNECT)) == 0) {
// do something?
// like sending a nop_out?
sleep(60);
}
printf("iscontrol: supervise going down\n");
syslog(LOG_INFO, "sess flags=%x", sess->flags);
sig = 0;
if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
perror("ISCSISIGNAL");
}
if(sess->flags & SESS_DISCONNECT) {
sess->flags &= ~SESS_FULLFEATURE;
return T9;
}
else {
val = 0;
if(ioctl(sess->fd, ISCSISTOP, &val)) {
perror("ISCSISTOP");
}
sess->flags |= SESS_INITIALLOGIN1;
}
return T8;
}
static int
handledDiscoveryResp(isess_t *sess, pdu_t *pp)
{
u_char *ptr;
int len, n;
debug_called(3);
len = pp->ds_len;
ptr = pp->ds_addr;
while(len > 0) {
if(*ptr != 0)
printf("%s\n", ptr);
n = strlen((char *)ptr) + 1;
len -= n;
ptr += n;
}
return 0;
}
static int
doDiscovery(isess_t *sess)
{
pdu_t spp;
text_req_t *tp = (text_req_t *)&spp.ipdu.bhs;
debug_called(3);
bzero(&spp, sizeof(pdu_t));
tp->cmd = ISCSI_TEXT_CMD /*| 0x40 */; // because of a bug in openiscsi-target
tp->F = 1;
tp->ttt = 0xffffffff;
addText(&spp, "SendTargets=All");
return sendPDU(sess, &spp, handledDiscoveryResp);
}
static trans_t
doLogin(isess_t *sess)
{
isc_opt_t *op = sess->op;
int status, count;
debug_called(3);
if(op->chapSecret == NULL && op->tgtChapSecret == NULL)
/*
| don't need any security negotiation
| or in other words: we don't have any secrets to exchange
*/
sess->csg = LON_PHASE;
else
sess->csg = SN_PHASE;
if(sess->tsih) {
sess->tsih = 0; // XXX: no 'reconnect' yet
sess->flags &= ~SESS_NEGODONE; // XXX: KLUDGE
}
count = 10; // should be more than enough
do {
debug(3, "count=%d csg=%d", count, sess->csg);
status = loginPhase(sess);
if(count-- == 0)
// just in case we get into a loop
status = -1;
} while(status == 0 && (sess->csg != FF_PHASE));
sess->flags &= ~SESS_INITIALLOGIN;
debug(3, "status=%d", status);
switch(status) {
case 0: // all is ok ...
sess->flags |= SESS_LOGGEDIN;
if(strcmp(sess->op->sessionType, "Discovery") == 0)
doDiscovery(sess);
return T5;
case 1: // redirect - temporary/permanent
/*
| start from scratch?
*/
sess->flags &= ~SESS_NEGODONE;
sess->flags |= (SESS_REDIRECT | SESS_INITIALLOGIN1);
syslog(LOG_DEBUG, "target sent REDIRECT");
return T7;
case 2: // initiator terminal error
return 0;
case 3: // target terminal error -- could retry ...
sleep(5);
return T7; // lets try
default:
return 0;
}
}
static int
handleLogoutResp(isess_t *sess, pdu_t *pp)
{
if(sess->flags & SESS_DISCONNECT) {
int val = 0;
if(ioctl(sess->fd, ISCSISTOP, &val)) {
perror("ISCSISTOP");
}
return 0;
}
return T13;
}
static trans_t
startLogout(isess_t *sess)
{
pdu_t spp;
logout_req_t *p = (logout_req_t *)&spp.ipdu.bhs;
bzero(&spp, sizeof(pdu_t));
p->cmd = ISCSI_LOGOUT_CMD| 0x40;
p->reason = BIT(7) | 0;
p->CID = htons(1);
return sendPDU(sess, &spp, handleLogoutResp);
}
static trans_t
inLogout(isess_t *sess)
{
if(sess->flags & SESS_RECONNECT)
return T18;
return 0;
}
typedef enum {
S1, S2, /*S3,*/ S4, S5, S6, S7, S8
} state_t;
/**
S1: FREE
S2: XPT_WAIT
S4: IN_LOGIN
S5: LOGGED_IN
S6: IN_LOGOUT
S7: LOGOUT_REQUESTED
S8: CLEANUP_WAIT
-------<-------------+
+--------->/ S1 \<----+ |
T13| +->\ /<-+ \ |
| / ---+--- \ \ |
| / | T2 \ | |
| T8 | |T1 | | |
| | | / |T7 |
| | | / | |
| | | / | |
| | V / / |
| | ------- / / |
| | / S2 \ / |
| | \ / / |
| | ---+--- / |
| | |T4 / |
| | V / | T18
| | ------- / |
| | / S4 \ |
| | \ / |
| | ---+--- | T15
| | |T5 +--------+---------+
| | | /T16+-----+------+ |
| | | / -+-----+--+ | |
| | | / / S7 \ |T12| |
| | | / +->\ /<-+ V V
| | | / / -+----- -------
| | | / /T11 |T10 / S8 \
| | V / / V +----+ \ /
| | ---+-+- ----+-- | -------
| | / S5 \T9 / S6 \<+ ^
| +-----\ /--->\ / T14 |
| ------- --+----+------+T17
+---------------------------+
*/
int
fsm(isc_opt_t *op)
{
state_t state;
isess_t *sess;
if((sess = calloc(1, sizeof(isess_t))) == NULL) {
// boy, is this a bad start ...
fprintf(stderr, "no memory!\n");
return -1;
}
state = S1;
sess->op = op;
sess->fd = -1;
sess->soc = -1;
sess->target.address = strdup(op->targetAddress);
sess->target.port = op->port;
sess->target.pgt = op->targetPortalGroupTag;
sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1;
do {
switch(state) {
case S1:
switch(tcpConnect(sess)) {
case T1: state = S2; break;
default: state = S8; break;
}
break;
case S2:
switch(startSession(sess)) {
case T2: state = S1; break;
case T4: state = S4; break;
default: state = S8; break;
}
break;
case S4:
switch(doLogin(sess)) {
case T7: state = S1; break;
case T5: state = S5; break;
default: state = S8; break;
}
break;
case S5:
switch(supervise(sess)) {
case T8: state = S1; break;
case T9: state = S6; break;
case T11: state = S7; break;
case T15: state = S8; break;
default: state = S8; break;
}
break;
case S6:
switch(startLogout(sess)) {
case T13: state = S1; break;
case T14: state = S6; break;
case T16: state = S8; break;
default: state = S8; break;
}
break;
case S7:
switch(inLogout(sess)) {
case T18: state = S1; break;
case T10: state = S6; break;
case T12: state = S7; break;
case T16: state = S8; break;
default: state = S8; break;
}
break;
case S8:
// maybe do some clean up?
syslog(LOG_INFO, "terminated");
return 0;
}
} while(1);
}

View file

@ -1,141 +0,0 @@
.\" Copyright (c) 2007-2010 Daniel Braniss <danny@cs.huji.ac.il>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd September 9, 2016
.Dt ISCONTROL 8
.Os
.Sh NAME
.Nm iscontrol
.Nd login/negotiator/control for an iSCSI initiator session
.Sh SYNOPSIS
.Nm
.Op Fl dv
.Oo
.Fl c Ar file
.Op Fl n Ar nickname
.Oc
.Op Fl p Ar pidfile
.Op Fl t Ar target
.Op Ar variable Ns = Ns Ar value
.Sh DESCRIPTION
.Bf -symbolic
This command, along with its kernel counterpart
.Xr iscsi_initiator 4 ,
is obsolete.
Users are advised to use
.Xr iscsictl 8
instead.
.Ef
.Pp
Internet SCSI (iSCSI) is a network protocol standard, that allows the
use of the SCSI protocol over TCP/IP networks,
the
.Nm
program is the userland side of an iSCSI session, see
.Xr iscsi_initiator 4 .
It has 2 modes of operation, if -d (discovery session) is specified,
it will print out the
.Em target names
returned by the target and exit.
In the second mode, it will, after a successful login/negotiation, run
in daemon mode, monitoring the connection, and will try to reconnect
in case of a network/target failure.
It will terminate/logout the session
when a SIGHUP signal is received.
The flags are as follows:
.Bl -tag -width variable=value
.It Fl c Ar file
a file containing configuration
.Em key-options ,
see
.Xr iscsi.conf 5 .
.It Fl d
do a
.Em discovery session
and exit.
.It Fl n Ar nickname
if
.Sy -c file
is specified, then search for the block named
.Em nickname
in that file, see
.Xr iscsi.conf 5 .
.It Fl p Ar pidfile
will write the process ID of the session to the specified
.Em pidfile
.It Fl t Ar target
the target's IP address or name.
.It Fl v
verbose mode.
.It Ar variable Ns = Ns Ar value
see
.Xr iscsi.conf 5
for the complete list of variables/options and their
possible values.
.El
.Sh EXAMPLES
.Dl iscontrol -dt myiscsitarget
.Pp
will start a
.Em discovery session
with the target and
print to stdout the list of available targetnames/targetadresses.
Note: this listing does not necessarily mean availability, since
depending on the target configuration, a discovery session might
not need login/access permission, but a
.Em full session
certainly does.
.sp
.Dl iscontrol -c /etc/iscsi.conf -n myiscsi
.Pp
will read options from
.Pa /etc/iscsi.conf ,
use the targetaddress
found in the block nicknamed myiscsi, login and negotiate
whatever options are specified, and start an iscsi-session.
.Sh SEE ALSO
.Xr da 4 ,
.Xr iscsi_initiator 4 ,
.Xr sa 4 ,
.Xr iscsi.conf 5 ,
.Xr camcontrol 8 ,
.Xr iscsictl 8
.Sh STANDARDS
RFC 3720
.Sh HISTORY
The
.Nm
utility appeared in
.Fx 7.0 .
.Sh BUGS
.Nm
should probably load the iscsi_initiator module if needed.
.br
Not all functions/specifications have been implemented yet, noticeably
missing are the Task Management Functions.
The error recovery, though not
.Em fully compliant
does a brave effort to recover from network disconnects.

View file

@ -1,264 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: iscontrol.c,v 2.2 2006/12/01 09:11:56 danny Exp danny $
*/
/*
| the user level initiator (client)
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <camlib.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static char version[] = "2.3.1"; // keep in sync with iscsi_initiator
#define USAGE "[-v] [-d] [-c config] [-n name] [-t target] [-p pidfile]"
#define OPTIONS "vdc:t:n:p:"
token_t AuthMethods[] = {
{"None", NONE},
{"KRB5", KRB5},
{"SPKM1", SPKM1},
{"SPKM2", SPKM2},
{"SRP", SRP},
{"CHAP", CHAP},
{0, 0}
};
token_t DigestMethods[] = {
{"None", 0},
{"CRC32", 1},
{"CRC32C", 1},
{0, 0}
};
int vflag;
char *iscsidev;
u_char isid[6 + 6];
/*
| Default values
*/
isc_opt_t opvals = {
.port = 3260,
.sockbufsize = 128,
.iqn = "iqn.2005-01.il.ac.huji.cs:",
.sessionType = "Normal",
.targetAddress = 0,
.targetName = 0,
.initiatorName = 0,
.authMethod = "None",
.headerDigest = "None,CRC32C",
.dataDigest = "None,CRC32C",
.maxConnections = 1,
.maxRecvDataSegmentLength = 64 * 1024,
.maxXmitDataSegmentLength = 8 * 1024, // 64 * 1024,
.maxBurstLength = 128 * 1024,
.firstBurstLength = 64 * 1024, // must be less than maxBurstLength
.defaultTime2Wait = 0,
.defaultTime2Retain = 0,
.maxOutstandingR2T = 1,
.errorRecoveryLevel = 0,
.dataPDUInOrder = TRUE,
.dataSequenceInOrder = TRUE,
.initialR2T = TRUE,
.immediateData = TRUE,
};
static void
usage(const char *pname)
{
fprintf(stderr, "usage: %s " USAGE "\n", pname);
exit(1);
}
int
lookup(token_t *tbl, char *m)
{
token_t *tp;
for(tp = tbl; tp->name != NULL; tp++)
if(strcasecmp(tp->name, m) == 0)
return tp->val;
return 0;
}
int
main(int cc, char **vv)
{
int ch, disco;
char *pname, *pidfile, *p, *q, *ta, *kw, *v;
isc_opt_t *op;
FILE *fd;
size_t n;
op = &opvals;
iscsidev = "/dev/"ISCSIDEV;
fd = NULL;
pname = vv[0];
if ((pname = basename(pname)) == NULL)
err(1, "basename");
kw = ta = 0;
disco = 0;
pidfile = NULL;
/*
| check for driver & controller version match
*/
n = 0;
#define VERSION_OID_S "net.iscsi_initiator.driver_version"
if (sysctlbyname(VERSION_OID_S, 0, &n, 0, 0) != 0) {
if (errno == ENOENT)
errx(1, "sysctlbyname(\"" VERSION_OID_S "\") "
"failed; is the iscsi driver loaded?");
err(1, "sysctlbyname(\"" VERSION_OID_S "\")");
}
v = malloc(n+1);
if (v == NULL)
err(1, "malloc");
if (sysctlbyname(VERSION_OID_S, v, &n, 0, 0) != 0)
err(1, "sysctlbyname");
if (strncmp(version, v, 3) != 0)
errx(1, "versions mismatch");
while((ch = getopt(cc, vv, OPTIONS)) != -1) {
switch(ch) {
case 'v':
vflag++;
break;
case 'c':
fd = fopen(optarg, "r");
if (fd == NULL)
err(1, "fopen(\"%s\")", optarg);
break;
case 'd':
disco = 1;
break;
case 't':
ta = optarg;
break;
case 'n':
kw = optarg;
break;
case 'p':
pidfile = optarg;
break;
default:
usage(pname);
}
}
if(fd == NULL)
fd = fopen("/etc/iscsi.conf", "r");
if(fd != NULL) {
parseConfig(fd, kw, op);
fclose(fd);
}
cc -= optind;
vv += optind;
if(cc > 0) {
if(vflag)
printf("adding '%s'\n", *vv);
parseArgs(cc, vv, op);
}
if(ta)
op->targetAddress = ta;
if(op->targetAddress == NULL) {
warnx("no target specified!");
usage(pname);
}
q = op->targetAddress;
if(*q == '[' && (q = strchr(q, ']')) != NULL) {
*q++ = '\0';
op->targetAddress++;
} else
q = op->targetAddress;
if((p = strchr(q, ':')) != NULL) {
*p++ = 0;
op->port = atoi(p);
p = strchr(p, ',');
}
if(p || ((p = strchr(q, ',')) != NULL)) {
*p++ = 0;
op->targetPortalGroupTag = atoi(p);
}
if(op->initiatorName == 0) {
char hostname[MAXHOSTNAMELEN];
if(op->iqn) {
if(gethostname(hostname, sizeof(hostname)) == 0)
asprintf(&op->initiatorName, "%s:%s", op->iqn, hostname);
else
asprintf(&op->initiatorName, "%s:%d", op->iqn, (int)time(0) & 0xff); // XXX:
}
else {
if(gethostname(hostname, sizeof(hostname)) == 0)
asprintf(&op->initiatorName, "%s", hostname);
else
asprintf(&op->initiatorName, "%d", (int)time(0) & 0xff); // XXX:
}
}
if(disco) {
op->sessionType = "Discovery";
op->targetName = 0;
}
op->pidfile = pidfile;
fsm(op);
exit(0);
}

View file

@ -1,167 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
| $Id: iscontrol.h,v 2.3 2007/04/27 08:36:49 danny Exp danny $
*/
#ifdef DEBUG
int vflag;
# define debug(level, fmt, args...) do {if (level <= vflag) printf("%s: " fmt "\n", __func__ , ##args);} while(0)
# define debug_called(level) do {if (level <= vflag) printf("%s: called\n", __func__);} while(0)
#else
# define debug(level, fmt, args...)
# define debug_called(level)
#endif // DEBUG
#define xdebug(fmt, args...) printf("%s: " fmt "\n", __func__ , ##args)
#define BIT(n) (1 <<(n))
#define MAXREDIRECTS 2
typedef int auth_t(void *sess);
typedef struct {
char *address;
int port;
int pgt;
} target_t;
typedef struct isess {
int flags;
#define SESS_CONNECTED BIT(0)
#define SESS_DISCONNECT BIT(1)
#define SESS_LOGGEDIN BIT(2)
#define SESS_RECONNECT BIT(3)
#define SESS_REDIRECT BIT(4)
#define SESS_NEGODONE BIT(10) // XXX: kludge
#define SESS_FULLFEATURE BIT(29)
#define SESS_INITIALLOGIN1 BIT(30)
#define SESS_INITIALLOGIN BIT(31)
isc_opt_t *op; // operational values
target_t target; // the Original target address
int fd; // the session fd
int soc; // the socket
iscsi_cam_t cam;
struct cam_device *camdev;
time_t open_time;
int redirect_cnt;
time_t redirect_time;
int reconnect_cnt;
int reconnect_cnt1;
time_t reconnect_time;
char isid[6+1];
int csg; // current stage
int nsg; // next stage
// Phases/Stages
#define SN_PHASE 0 // Security Negotiation
#define LON_PHASE 1 // Login Operational Negotiation
#define FF_PHASE 3 // FuLL-Feature
uint tsih;
sn_t sn;
} isess_t;
typedef struct token {
char *name;
int val;
} token_t;
typedef enum {
NONE = 0,
KRB5,
SPKM1,
SPKM2,
SRP,
CHAP
} authm_t;
extern token_t AuthMethods[];
extern token_t DigestMethods[];
typedef enum {
SET,
GET
} oper_t;
typedef enum {
U_PR, // private
U_IO, // Initialize Only -- during login
U_LO, // Leading Only -- when TSIH is zero
U_FFPO, // Full Feature Phase Only
U_ALL // in any phase
} usage_t;
typedef enum {
S_PR,
S_CO, // Connect only
S_SW // Session Wide
} scope_t;
typedef void keyfun_t(isess_t *, oper_t);
typedef struct {
usage_t usage;
scope_t scope;
char *name;
int tokenID;
} textkey_t;
typedef int handler_t(isess_t *sess, pdu_t *pp);
int authenticateLogin(isess_t *sess);
int fsm(isc_opt_t *op);
int sendPDU(isess_t *sess, pdu_t *pp, handler_t *hdlr);
int addText(pdu_t *pp, char *fmt, ...);
void freePDU(pdu_t *pp);
int xmitpdu(isess_t *sess, pdu_t *pp);
int recvpdu(isess_t *sess, pdu_t *pp);
int lookup(token_t *tbl, char *m);
extern int vflag;
extern char *iscsidev;
void parseArgs(int nargs, char **args, isc_opt_t *op);
void parseConfig(FILE *fd, char *key, isc_opt_t *op);
char *chapDigest(char *ap, char id, char *cp, char *chapSecret);
char *genChapChallenge(char *encoding, uint len);
int str2bin(char *str, char **rsp);
char *bin2str(char *fmt, unsigned char *md, int blen);
int negotiateOPV(isess_t *sess);
int setOptions(isess_t *sess, int flag);
int loginPhase(isess_t *sess);

View file

@ -1,442 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: login.c,v 1.4 2007/04/27 07:40:40 danny Exp danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static char *status_class1[] = {
"Initiator error",
"Authentication failure",
"Authorization failure",
"Not found",
"Target removed",
"Unsupported version",
"Too many connections",
"Missing parameter",
"Can't include in session",
"Session type not supported",
"Session does not exist",
"Invalid during login",
};
#define CLASS1_ERRS ((sizeof status_class1) / sizeof(char *))
static char *status_class3[] = {
"Target error",
"Service unavailable",
"Out of resources"
};
#define CLASS3_ERRS ((sizeof status_class3) / sizeof(char *))
static char *
selectFrom(char *str, token_t *list)
{
char *sep, *sp;
token_t *lp;
int n;
sp = str;
do {
sep = strchr(sp, ',');
if(sep != NULL)
n = sep - sp;
else
n = strlen(sp);
for(lp = list; lp->name != NULL; lp++) {
if(strncasecmp(lp->name, sp, n) == 0)
return strdup(lp->name);
}
sp = sep + 1;
} while(sep != NULL);
return NULL;
}
static char *
getkeyval(char *key, pdu_t *pp)
{
char *ptr;
int klen, len, n;
debug_called(3);
len = pp->ds_len;
ptr = (char *)pp->ds_addr;
klen = strlen(key);
while(len > klen) {
if(strncmp(key, ptr, klen) == 0)
return ptr+klen;
n = strlen(ptr) + 1;
len -= n;
ptr += n;
}
return 0;
}
static int
handleTgtResp(isess_t *sess, pdu_t *pp)
{
isc_opt_t *op = sess->op;
char *np, *rp, *d1, *d2;
int res, l1, l2;
res = -1;
if(((np = getkeyval("CHAP_N=", pp)) == NULL) ||
((rp = getkeyval("CHAP_R=", pp)) == NULL))
goto out;
if(strcmp(np, op->tgtChapName? op->tgtChapName: op->initiatorName) != 0) {
fprintf(stderr, "%s does not match\n", np);
goto out;
}
l1 = str2bin(op->tgtChapDigest, &d1);
l2 = str2bin(rp, &d2);
debug(3, "l1=%d '%s' l2=%d '%s'", l1, op->tgtChapDigest, l2, rp);
if(l1 == l2 && memcmp(d1, d2, l1) == 0)
res = 0;
if(l1)
free(d1);
if(l2)
free(d2);
out:
free(op->tgtChapDigest);
op->tgtChapDigest = NULL;
debug(3, "res=%d", res);
return res;
}
static void
processParams(isess_t *sess, pdu_t *pp)
{
isc_opt_t *op = sess->op;
int len, klen, n;
char *eq, *ptr;
debug_called(3);
len = pp->ds_len;
ptr = (char *)pp->ds_addr;
while(len > 0) {
if(vflag > 1)
printf("got: len=%d %s\n", len, ptr);
klen = 0;
if((eq = strchr(ptr, '=')) != NULL)
klen = eq - ptr;
if(klen > 0) {
if(strncmp(ptr, "TargetAddress", klen) == 0) {
char *p, *q, *ta = NULL;
// TargetAddress=domainname[:port][,portal-group-tag]
// XXX: if(op->targetAddress) free(op->targetAddress);
q = op->targetAddress = strdup(eq+1);
if(*q == '[') {
// bracketed IPv6
if((q = strchr(q, ']')) != NULL) {
*q++ = '\0';
ta = op->targetAddress;
op->targetAddress = strdup(ta+1);
} else
q = op->targetAddress;
}
if((p = strchr(q, ',')) != NULL) {
*p++ = 0;
op->targetPortalGroupTag = atoi(p);
}
if((p = strchr(q, ':')) != NULL) {
*p++ = 0;
op->port = atoi(p);
}
if(ta)
free(ta);
} else if(strncmp(ptr, "MaxRecvDataSegmentLength", klen) == 0) {
// danny's RFC
op->maxXmitDataSegmentLength = strtol(eq+1, (char **)NULL, 0);
} else if(strncmp(ptr, "TargetPortalGroupTag", klen) == 0) {
op->targetPortalGroupTag = strtol(eq+1, (char **)NULL, 0);
} else if(strncmp(ptr, "HeaderDigest", klen) == 0) {
op->headerDigest = selectFrom(eq+1, DigestMethods);
} else if(strncmp(ptr, "DataDigest", klen) == 0) {
op->dataDigest = selectFrom(eq+1, DigestMethods);
} else if(strncmp(ptr, "MaxOutstandingR2T", klen) == 0)
op->maxOutstandingR2T = strtol(eq+1, (char **)NULL, 0);
#if 0
else
for(kp = keyMap; kp->name; kp++) {
if(strncmp(ptr, kp->name, kp->len) == 0 && ptr[kp->len] == '=')
mp->func(sess, ptr+kp->len+1, GET);
}
#endif
}
n = strlen(ptr) + 1;
len -= n;
ptr += n;
}
}
static int
handleLoginResp(isess_t *sess, pdu_t *pp)
{
login_rsp_t *lp = (login_rsp_t *)pp;
uint st_class, status = ntohs(lp->status);
debug_called(3);
debug(4, "Tbit=%d csg=%d nsg=%d status=%x", lp->T, lp->CSG, lp->NSG, status);
st_class = status >> 8;
if(status) {
uint st_detail = status & 0xff;
switch(st_class) {
case 1: // Redirect
switch(st_detail) {
// the ITN (iSCSI target Name) requests a:
case 1: // temporary address change
case 2: // permanent address change
status = 0;
}
break;
case 2: // Initiator Error
if(st_detail < CLASS1_ERRS)
printf("0x%04x: %s\n", status, status_class1[st_detail]);
break;
case 3:
if(st_detail < CLASS3_ERRS)
printf("0x%04x: %s\n", status, status_class3[st_detail]);
break;
}
}
if(status == 0) {
processParams(sess, pp);
setOptions(sess, 0); // XXX: just in case ...
if(lp->T) {
isc_opt_t *op = sess->op;
if(sess->csg == SN_PHASE && (op->tgtChapDigest != NULL))
if(handleTgtResp(sess, pp) != 0)
return 1; // XXX: Authentication failure ...
sess->csg = lp->NSG;
if(sess->csg == FF_PHASE) {
// XXX: will need this when implementing reconnect.
sess->tsih = lp->tsih;
debug(2, "TSIH=%x", sess->tsih);
}
}
}
return st_class;
}
static int
handleChap(isess_t *sess, pdu_t *pp)
{
pdu_t spp;
login_req_t *lp;
isc_opt_t *op = sess->op;
char *ap, *ip, *cp, *digest; // MD5 is 128bits, SHA1 160bits
debug_called(3);
bzero(&spp, sizeof(pdu_t));
lp = (login_req_t *)&spp.ipdu.bhs;
lp->cmd = ISCSI_LOGIN_CMD | 0x40; // login request + Inmediate
memcpy(lp->isid, sess->isid, 6);
lp->tsih = sess->tsih; // MUST be zero the first time!
lp->CID = htons(1);
lp->CSG = SN_PHASE; // Security Negotiation
lp->NSG = LON_PHASE;
lp->T = 1;
if(((ap = getkeyval("CHAP_A=", pp)) == NULL) ||
((ip = getkeyval("CHAP_I=", pp)) == NULL) ||
((cp = getkeyval("CHAP_C=", pp)) == NULL))
return -1;
if((digest = chapDigest(ap, (char)strtol(ip, (char **)NULL, 0), cp, op->chapSecret)) == NULL)
return -1;
addText(&spp, "CHAP_N=%s", op->chapIName? op->chapIName: op->initiatorName);
addText(&spp, "CHAP_R=%s", digest);
free(digest);
if(op->tgtChapSecret != NULL) {
op->tgtChapID = (random() >> 24) % 255; // should be random enough ...
addText(&spp, "CHAP_I=%d", op->tgtChapID);
cp = genChapChallenge(cp, op->tgtChallengeLen? op->tgtChallengeLen: 8);
addText(&spp, "CHAP_C=%s", cp);
op->tgtChapDigest = chapDigest(ap, op->tgtChapID, cp, op->tgtChapSecret);
}
return sendPDU(sess, &spp, handleLoginResp);
}
static int
authenticate(isess_t *sess)
{
pdu_t spp;
login_req_t *lp;
isc_opt_t *op = sess->op;
bzero(&spp, sizeof(pdu_t));
lp = (login_req_t *)&spp.ipdu.bhs;
lp->cmd = ISCSI_LOGIN_CMD | 0x40; // login request + Inmediate
memcpy(lp->isid, sess->isid, 6);
lp->tsih = sess->tsih; // MUST be zero the first time!
lp->CID = htons(1);
lp->CSG = SN_PHASE; // Security Negotiation
lp->NSG = SN_PHASE;
lp->T = 0;
switch((authm_t)lookup(AuthMethods, op->authMethod)) {
case NONE:
return 0;
case KRB5:
case SPKM1:
case SPKM2:
case SRP:
return 2;
case CHAP:
if(op->chapDigest == 0)
addText(&spp, "CHAP_A=5");
else
if(strcmp(op->chapDigest, "MD5") == 0)
addText(&spp, "CHAP_A=5");
else
if(strcmp(op->chapDigest, "SHA1") == 0)
addText(&spp, "CHAP_A=7");
else
addText(&spp, "CHAP_A=5,7");
return sendPDU(sess, &spp, handleChap);
}
return 1;
}
int
loginPhase(isess_t *sess)
{
pdu_t spp, *sp = &spp;
isc_opt_t *op = sess->op;
login_req_t *lp;
int status = 1;
debug_called(3);
bzero(sp, sizeof(pdu_t));
lp = (login_req_t *)&spp.ipdu.bhs;
lp->cmd = ISCSI_LOGIN_CMD | 0x40; // login request + Inmediate
memcpy(lp->isid, sess->isid, 6);
lp->tsih = sess->tsih; // MUST be zero the first time!
lp->CID = htons(1); // sess->cid?
if((lp->CSG = sess->csg) == LON_PHASE)
lp->NSG = FF_PHASE; // lets try and go full feature ...
else
lp->NSG = LON_PHASE;
lp->T = 1; // transit to next login stage
if(sess->flags & SESS_INITIALLOGIN1) {
sess->flags &= ~SESS_INITIALLOGIN1;
addText(sp, "SessionType=%s", op->sessionType);
addText(sp, "InitiatorName=%s", op->initiatorName);
if(strcmp(op->sessionType, "Discovery") != 0) {
addText(sp, "TargetName=%s", op->targetName);
}
}
switch(sess->csg) {
case SN_PHASE: // Security Negotiation
addText(sp, "AuthMethod=%s", op->authMethod);
break;
case LON_PHASE: // Login Operational Negotiation
if((sess->flags & SESS_NEGODONE) == 0) {
sess->flags |= SESS_NEGODONE;
addText(sp, "MaxBurstLength=%d", op->maxBurstLength);
addText(sp, "HeaderDigest=%s", op->headerDigest);
addText(sp, "DataDigest=%s", op->dataDigest);
addText(sp, "MaxRecvDataSegmentLength=%d", op->maxRecvDataSegmentLength);
addText(sp, "ErrorRecoveryLevel=%d", op->errorRecoveryLevel);
addText(sp, "DefaultTime2Wait=%d", op->defaultTime2Wait);
addText(sp, "DefaultTime2Retain=%d", op->defaultTime2Retain);
addText(sp, "DataPDUInOrder=%s", op->dataPDUInOrder? "Yes": "No");
addText(sp, "DataSequenceInOrder=%s", op->dataSequenceInOrder? "Yes": "No");
addText(sp, "MaxOutstandingR2T=%d", op->maxOutstandingR2T);
if(strcmp(op->sessionType, "Discovery") != 0) {
addText(sp, "MaxConnections=%d", op->maxConnections);
addText(sp, "FirstBurstLength=%d", op->firstBurstLength);
addText(sp, "InitialR2T=%s", op->initialR2T? "Yes": "No");
addText(sp, "ImmediateData=%s", op->immediateData? "Yes": "No");
}
}
break;
}
status = sendPDU(sess, &spp, handleLoginResp);
switch(status) {
case 0: // all is ok ...
if(sess->csg == SN_PHASE)
/*
| if we are still here, then we need
| to exchange some secrets ...
*/
status = authenticate(sess);
}
return status;
}

View file

@ -1,228 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: misc.c,v 2.1 2006/11/12 08:06:51 danny Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static inline char
c2b(unsigned char c)
{
switch(c) {
case '0' ... '9':
return c - '0';
case 'a' ... 'f':
return c - 'a' + 10;
case 'A' ... 'F':
return c - 'A' + 10;
}
return 0;
}
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static __inline unsigned char
c64tobin(unsigned char c64)
{
int i;
for(i = 0; i < 64; i++)
if(base64[i] == c64)
break;
return i;
}
/*
| according to rfc3720, the binary string
| cannot be larger than 1024 - but i can't find it :-) XXX
| not enforced yet.
*/
int
str2bin(char *str, char **rsp)
{
char *src, *dst, *tmp;
int i, len = 0;
src = str;
tmp = NULL;
if(strncasecmp("0x", src, 2) == 0) {
src += 2;
len = strlen(src);
if((tmp = malloc((len+1)/2)) == NULL) {
// XXX: print some error?
return 0;
}
dst = tmp;
if(len & 1)
*dst++ = c2b(*src++);
while(*src) {
*dst = c2b(*src++) << 4;
*dst++ |= c2b(*src++);
}
len = dst - tmp;
} else
if(strncasecmp("0b", src , 2) == 0) {
// base64
unsigned char b6;
src += 2;
len = strlen(src) / 4 * 3;
if((tmp = malloc(len)) == NULL) {
// XXX: print some error?
return 0;
}
dst = tmp;
i = 0;
while(*src && ((b6 = c64tobin(*src++)) != 64)) {
switch(i % 4) {
case 0:
*dst = b6 << 2;
break;
case 1:
*dst++ |= b6 >> 4;
*dst = b6 << 4;
break;
case 2:
*dst++ |= b6 >> 2;
*dst = b6 << 6;
break;
case 3:
*dst++ |= b6;
break;
}
i++;
}
len = dst - tmp;
}
else {
/*
| assume it to be an ascii string, so just copy it
*/
len = strlen(str);
if((tmp = malloc(len)) == NULL)
return 0;
dst = tmp;
src = str;
while(*src)
*dst++ = *src++;
}
*rsp = tmp;
return len;
}
char *
bin2str(char *encoding, unsigned char *md, int blen)
{
int len;
char *dst, *ds;
unsigned char *cp;
if(strncasecmp(encoding, "0x", 2) == 0) {
char ofmt[5];
len = blen * 2;
dst = malloc(len + 3);
strcpy(dst, encoding);
ds = dst + 2;
cp = md;
sprintf(ofmt, "%%02%c", encoding[1]);
while(blen-- > 0) {
sprintf(ds, ofmt, *cp++);
ds += 2;
}
*ds = 0;
return dst;
}
if(strncasecmp(encoding, "0b", 2) == 0) {
int i, b6;
len = (blen + 2) * 4 / 3;
dst = malloc(len + 3);
strcpy(dst, encoding);
ds = dst + 2;
cp = md;
b6 = 0; // to keep compiler happy.
for(i = 0; i < blen; i++) {
switch(i % 3) {
case 0:
*ds++ = base64[*cp >> 2];
b6 = (*cp & 0x3) << 4;
break;
case 1:
b6 += (*cp >> 4);
*ds++ = base64[b6];
b6 = (*cp & 0xf) << 2;
break;
case 2:
b6 += (*cp >> 6);
*ds++ = base64[b6];
*ds++ = base64[*cp & 0x3f];
}
cp++;
}
switch(blen % 3) {
case 0:
break;
case 1:
*ds++ = base64[b6];
*ds++ = '=';
*ds++ = '=';
break;
case 2:
*ds++ = base64[b6];
*ds++ = '=';
break;
}
*ds = 0;
return dst;
}
return NULL;
}

View file

@ -1,178 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: pdu.c,v 2.2 2006/12/01 09:11:56 danny Exp danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <camlib.h>
#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static void pukeText(char *it, pdu_t *pp);
int
xmitpdu(isess_t *sess, pdu_t *pp)
{
if(ioctl(sess->fd, ISCSISEND, pp)) {
perror("xmitpdu");
return -1;
}
if(vflag)
pukeText("I-", pp);
return 0;
}
int
recvpdu(isess_t *sess, pdu_t *pp)
{
if(ioctl(sess->fd, ISCSIRECV, pp)) {
perror("recvpdu");
return -1;
}
// XXX: return error if truncated via
// the FUDGE factor.
if(vflag)
pukeText("T-", pp);
return 0;
}
int
sendPDU(isess_t *sess, pdu_t *pp, handler_t *hdlr)
{
if(xmitpdu(sess, pp))
return 0;
if(hdlr) {
int res;
pp->ahs_size = 8 * 1024;
if((pp->ahs_addr = malloc(pp->ahs_size)) == NULL) {
fprintf(stderr, "out of mem!");
return -1;
}
pp->ds_size = 0;
if((res = recvpdu(sess, pp)) != 0) {
fprintf(stderr, "recvpdu failed\n");
return res;
}
res = hdlr(sess, pp);
freePDU(pp);
return res;
}
return 1;
}
#define FUDGE (512 * 8)
/*
| We use the same memory for the response
| so make enough room ...
| XXX: must find a better way.
*/
int
addText(pdu_t *pp, char *fmt, ...)
{
u_int len;
char *str;
va_list ap;
va_start(ap, fmt);
len = vasprintf(&str, fmt, ap) + 1;
if((pp->ds_len + len) > 0xffffff) {
printf("ds overflow\n");
free(str);
return 0;
}
if((pp->ds_len + len) > pp->ds_size) {
u_char *np;
np = realloc(pp->ds_addr, pp->ds_size + len + FUDGE);
if(np == NULL) {
free(str);
//XXX: out of memory!
return -1;
}
pp->ds_addr = np;
pp->ds_size += len + FUDGE;
}
memcpy(pp->ds_addr + pp->ds_len, str, len);
pp->ds_len += len;
free(str);
return len;
}
void
freePDU(pdu_t *pp)
{
if(pp->ahs_size)
free(pp->ahs_addr);
if(pp->ds_size)
free(pp->ds_addr);
bzero(&pp->ipdu, sizeof(union ipdu_u));
pp->ahs_addr = NULL;
pp->ds_addr = NULL;
pp->ahs_size = 0;
pp->ds_size = pp->ds_len = 0;
}
static void
pukeText(char *it, pdu_t *pp)
{
char *ptr;
int cmd;
size_t len, n;
len = pp->ds_len;
ptr = (char *)pp->ds_addr;
cmd = pp->ipdu.bhs.opcode;
printf("%s: cmd=0x%x len=%d\n", it, cmd, (int)len);
while(len > 0) {
printf("\t%s\n", ptr);
n = strlen(ptr) + 1;
len -= n;
ptr += n;
}
}

View file

@ -937,7 +937,6 @@ MLINKS+= efidev.4 efirtc.4
.if ${MK_ISCSI} != "no"
MAN+= cfiscsi.4
MAN+= iscsi.4
MAN+= iscsi_initiator.4
MAN+= iser.4
.endif

View file

@ -1,118 +0,0 @@
.\" Copyright (c) 2007-2010 Daniel Braniss <danny@cs.huji.ac.il>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd October 9, 2014
.Dt ISCSI_INITIATOR 4
.Os
.Sh NAME
.Nm iscsi_initiator
.Nd kernel driver for the iSCSI protocol
.Sh SYNOPSIS
To compile this driver into the kernel,
place the following lines in your
kernel configuration file:
.Bd -ragged -offset indent
.Cd "device iscsi_initiator"
.Ed
.Pp
Alternatively, to load the driver as a
module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
iscsi_initiator_load="YES"
.Ed
.Sh DESCRIPTION
.Bf -symbolic
This driver, along with its userspace counterpart
.Xr iscontrol 8 ,
is obsolete.
Users are advised to use
.Xr iscsi 4
instead.
.Ef
.Pp
The
.Nm
implements the kernel side of the Internet SCSI (iSCSI) network
protocol standard, the userland companion is
.Xr iscontrol 8 ,
and permits access to remote
.Em virtual
SCSI devices via
.Xr cam 4 .
.Sh SYSCTL VARIABLES
.Bl -tag -width ".Va net.iscsi.n.targeaddress"
.It Va debug.iscsi_initiator
set the debug-level, 0 means no debugging, 9 for maximum.
.It Va net.iscsi.isid
the initiator part of the Session Identifier.
.It Va "kern.cam.cam_srch_hi=1"
allow search above LUN 7 for SCSI3 and greater devices.
.It "the following are informative only:"
.It Va net.iscsi.driver_version
the current version of the driver.
.It Va net.iscsi.sessions
the number of current active sessions.
.It Va net.iscsi.n.targetname
is the targe name of session
.Em n .
.It Va net.iscsi.n.targeaddress
is the IP address of the target of session
.Em n .
.It Va net.iscsi.n.stats
are some statistics for session
.Em n
.It Va net.iscsi.n.pid
is the
.Em "process id"
of the userland side of session
.Em n ,
see
.Xr iscontrol 8 .
.El
.Sh FILES
The
.Nm
driver creates the following:
.Pp
.Bl -tag -width ".Pa /dev/iscsi%dxx" -compact
.It Pa /dev/iscsi
used to create new sessions.
.It Pa /dev/iscsi%d
for each new session.
.El
.Sh SEE ALSO
.Xr cam 4 ,
.Xr camcontrol 8 ,
.Xr iscontrol 8
.Sh STANDARDS
iSCSI RFC 3720
.\" .Sh HISTORY
.Sh AUTHORS
This software was written by
.An Daniel Braniss Aq Mt danny@cs.huji.ac.il
.Sh BUGS
The lun discovery method is old-fashioned.

View file

@ -1523,7 +1523,6 @@ device aacraid
device ahc
device ahd
device esp
device iscsi_initiator
device isp
envvar hint.isp.0.disable="1"
envvar hint.isp.0.role="3"

View file

@ -1929,12 +1929,6 @@ dev/iscsi/icl_conn_if.m optional cfiscsi | iscsi
dev/iscsi/icl_soft.c optional iscsi
dev/iscsi/icl_soft_proxy.c optional iscsi
dev/iscsi/iscsi.c optional iscsi scbus
dev/iscsi_initiator/iscsi.c optional iscsi_initiator scbus
dev/iscsi_initiator/iscsi_subr.c optional iscsi_initiator scbus
dev/iscsi_initiator/isc_cam.c optional iscsi_initiator scbus
dev/iscsi_initiator/isc_soc.c optional iscsi_initiator scbus
dev/iscsi_initiator/isc_sm.c optional iscsi_initiator scbus
dev/iscsi_initiator/isc_subr.c optional iscsi_initiator scbus
dev/ismt/ismt.c optional ismt
dev/isl/isl.c optional isl iicbus
dev/isp/isp.c optional isp

View file

@ -1,351 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: isc_cam.c 998 2009-12-20 10:32:45Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/callout.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <vm/uma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_periph.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
static void
_inq(struct cam_sim *sim, union ccb *ccb)
{
struct ccb_pathinq *cpi = &ccb->cpi;
isc_session_t *sp = cam_sim_softc(sim);
debug_called(8);
debug(3, "sid=%d target=%d lun=%jx", sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun);
cpi->version_num = 1; /* XXX??? */
cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_32;
cpi->target_sprt = 0;
cpi->hba_misc = 0;
cpi->hba_eng_cnt = 0;
cpi->max_target = 0; //ISCSI_MAX_TARGETS - 1;
cpi->initiator_id = ISCSI_MAX_TARGETS;
cpi->max_lun = sp->opt.maxluns - 1;
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 3300; // 40000; // XXX:
strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
strlcpy(cpi->hba_vid, "iSCSI", HBA_IDLEN);
strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
cpi->unit_number = cam_sim_unit(sim);
cpi->ccb_h.status = CAM_REQ_CMP;
#if defined(KNOB_VALID_ADDRESS)
cpi->transport = XPORT_ISCSI;
cpi->transport_version = 0;
#endif
}
static __inline int
_scsi_encap(struct cam_sim *sim, union ccb *ccb)
{
int ret;
isc_session_t *sp = cam_sim_softc(sim);
mtx_unlock(&sp->cam_mtx);
ret = scsi_encap(sim, ccb);
mtx_lock(&sp->cam_mtx);
return ret;
}
void
ic_lost_target(isc_session_t *sp, int target)
{
debug_called(8);
sdebug(2, "lost target=%d", target);
if(sp->cam_path != NULL) {
mtx_lock(&sp->cam_mtx);
xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL);
xpt_free_path(sp->cam_path);
mtx_unlock(&sp->cam_mtx);
sp->cam_path = 0; // XXX
}
}
static void
scan_callback(struct cam_periph *periph, union ccb *ccb)
{
isc_session_t *sp = (isc_session_t *)ccb->ccb_h.spriv_ptr0;
debug_called(8);
xpt_free_ccb(ccb);
if(sp->flags & ISC_SCANWAIT) {
sp->flags &= ~ISC_SCANWAIT;
wakeup(sp);
}
}
static int
ic_scan(isc_session_t *sp)
{
union ccb *ccb;
debug_called(8);
sdebug(2, "scanning sid=%d", sp->sid);
sp->flags &= ~ISC_CAMDEVS;
sp->flags |= ISC_SCANWAIT;
ccb = xpt_alloc_ccb();
ccb->ccb_h.path = sp->cam_path;
ccb->ccb_h.cbfcnp = scan_callback;
ccb->ccb_h.spriv_ptr0 = sp;
xpt_rescan(ccb);
while(sp->flags & ISC_SCANWAIT)
tsleep(sp, PRIBIO, "ffp", 5*hz); // the timeout time should
// be configurable
sdebug(2, "# of luns=%d", sp->target_nluns);
if(sp->target_nluns > 0) {
sp->flags |= ISC_CAMDEVS;
return 0;
}
return ENODEV;
}
static void
ic_action(struct cam_sim *sim, union ccb *ccb)
{
isc_session_t *sp = cam_sim_softc(sim);
struct ccb_hdr *ccb_h = &ccb->ccb_h;
debug_called(8);
ccb_h->spriv_ptr0 = sp;
sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%jx retry_count=%d timeout=%d",
ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status,
ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun,
ccb->ccb_h.retry_count, ccb_h->timeout);
if(sp == NULL) {
xdebug("sp == NULL! cannot happen");
return;
}
switch(ccb_h->func_code) {
case XPT_PATH_INQ:
_inq(sim, ccb);
break;
case XPT_RESET_BUS: // (can just be a stub that does nothing and completes)
{
struct ccb_pathinq *cpi = &ccb->cpi;
debug(3, "XPT_RESET_BUS");
cpi->ccb_h.status = CAM_REQ_CMP;
break;
}
case XPT_SCSI_IO:
{
struct ccb_scsiio* csio = &ccb->csio;
debug(4, "XPT_SCSI_IO cmd=0x%x", csio->cdb_io.cdb_bytes[0]);
if(sp == NULL) {
ccb_h->status = CAM_REQ_INVALID; //CAM_NO_NEXUS;
debug(4, "xpt_done.status=%d", ccb_h->status);
break;
}
if(ccb_h->target_lun == CAM_LUN_WILDCARD) {
debug(3, "target=%d: bad lun (-1)", ccb_h->target_id);
ccb_h->status = CAM_LUN_INVALID;
break;
}
if(_scsi_encap(sim, ccb) != 0)
return;
break;
}
case XPT_CALC_GEOMETRY:
{
struct ccb_calc_geometry *ccg;
ccg = &ccb->ccg;
debug(4, "sid=%d target=%d lun=%jx XPT_CALC_GEOMETRY vsize=%jd bsize=%d",
sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun,
ccg->volume_size, ccg->block_size);
if(ccg->block_size == 0 ||
(ccg->volume_size < ccg->block_size)) {
// print error message ...
/* XXX: what error is appropriate? */
break;
}
else {
int lun, *off, boff;
lun = ccb->ccb_h.target_lun;
if(lun > ISCSI_MAX_LUNS) {
// XXX:
xdebug("lun %d > ISCSI_MAX_LUNS!\n", lun);
lun %= ISCSI_MAX_LUNS;
}
off = &sp->target_lun[lun / (sizeof(int)*8)];
boff = BIT(lun % (sizeof(int)*8));
debug(4, "sp->target_nluns=%d *off=%x boff=%x",
sp->target_nluns, *off, boff);
if((*off & boff) == 0) {
sp->target_nluns++;
*off |= boff;
}
cam_calc_geometry(ccg, /*extended*/1);
}
break;
}
case XPT_GET_TRAN_SETTINGS:
default:
ccb_h->status = CAM_REQ_INVALID;
break;
}
xpt_done(ccb);
return;
}
static void
ic_poll(struct cam_sim *sim)
{
debug_called(4);
}
int
ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp)
{
debug_called(8);
if(sp && sp->cam_sim) {
cp->path_id = cam_sim_path(sp->cam_sim);
cp->target_id = 0;
cp->target_nluns = ISCSI_MAX_LUNS; // XXX: -1?
return 0;
}
return ENXIO;
}
void
ic_destroy(isc_session_t *sp )
{
debug_called(8);
if(sp->cam_path != NULL) {
sdebug(2, "name=%s unit=%d",
cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim));
#if 0
xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL);
#else
xpt_async(XPT_RESET_BUS, sp->cam_path, NULL);
#endif
xpt_free_path(sp->cam_path);
xpt_bus_deregister(cam_sim_path(sp->cam_sim));
cam_sim_free(sp->cam_sim, TRUE /*free_devq*/);
sdebug(2, "done");
}
}
int
ic_init(isc_session_t *sp)
{
struct cam_sim *sim;
struct cam_devq *devq;
debug_called(8);
if((devq = cam_simq_alloc(256)) == NULL)
return ENOMEM;
mtx_init(&sp->cam_mtx, "isc-cam", NULL, MTX_DEF);
sim = cam_sim_alloc(ic_action,
ic_poll,
"iscsi",
sp,
sp->sid, // unit
&sp->cam_mtx,
1, // max_dev_transactions
0, // max_tagged_dev_transactions
devq);
if(sim == NULL) {
cam_simq_free(devq);
mtx_destroy(&sp->cam_mtx);
return ENXIO;
}
if(xpt_bus_register(sim,
NULL,
0/*bus_number*/) != CAM_SUCCESS) {
cam_sim_free(sim, /*free_devq*/TRUE);
mtx_destroy(&sp->cam_mtx);
return ENXIO;
}
sp->cam_sim = sim;
if(xpt_create_path(&sp->cam_path, NULL, cam_sim_path(sp->cam_sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path(sp->cam_sim));
cam_sim_free(sim, /*free_devq*/TRUE);
mtx_destroy(&sp->cam_mtx);
return ENXIO;
}
sdebug(1, "cam subsystem initialized");
ic_scan(sp);
return 0;
}

View file

@ -1,750 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| iSCSI - Session Manager
| $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/proc.h>
#include <sys/ioccom.h>
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/syslog.h>
#include <sys/mbuf.h>
#include <sys/bus.h>
#include <sys/sbuf.h>
#include <sys/sx.h>
#include <vm/uma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_periph.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
static void
_async(isc_session_t *sp, pduq_t *pq)
{
debug_called(8);
iscsi_async(sp, pq);
pdu_free(sp->isc, pq);
}
static void
_reject(isc_session_t *sp, pduq_t *pq)
{
pduq_t *opq;
pdu_t *pdu;
reject_t *reject;
int itt;
debug_called(8);
pdu = mtod(pq->mp, pdu_t *);
itt = pdu->ipdu.bhs.itt;
reject = &pq->pdu.ipdu.reject;
sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason);
opq = i_search_hld(sp, itt, 0);
if(opq != NULL)
iscsi_reject(sp, opq, pq);
else {
switch(pq->pdu.ipdu.bhs.opcode) {
case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why
sdebug(2, "ISCSI_LOGOUT_CMD ...");
break;
default:
xdebug("%d] we lost something itt=%x",
sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
}
}
pdu_free(sp->isc, pq);
}
static void
_r2t(isc_session_t *sp, pduq_t *pq)
{
pduq_t *opq;
debug_called(8);
opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
if(opq != NULL) {
iscsi_r2t(sp, opq, pq);
}
else {
r2t_t *r2t = &pq->pdu.ipdu.r2t;
xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x",
sp->sid, ntohl(pq->pdu.ipdu.bhs.itt),
ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl));
}
pdu_free(sp->isc, pq);
}
static void
_scsi_rsp(isc_session_t *sp, pduq_t *pq)
{
pduq_t *opq;
debug_called(8);
opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0);
debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq);
if(opq != NULL) {
iscsi_done(sp, opq, pq);
i_acked_hld(sp, &pq->pdu);
}
else
xdebug("%d] we lost something itt=%x",
sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
pdu_free(sp->isc, pq);
}
static void
_read_data(isc_session_t *sp, pduq_t *pq)
{
pduq_t *opq;
debug_called(8);
opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
if(opq != NULL) {
if(scsi_decap(sp, opq, pq) != 1) {
i_remove_hld(sp, opq); // done
pdu_free(sp->isc, opq);
}
}
else
xdebug("%d] we lost something itt=%x",
sp->sid, ntohl(pq->pdu.ipdu.bhs.itt));
pdu_free(sp->isc, pq);
}
/*
| this is a kludge,
| the jury is not back with a veredict, user or kernel
*/
static void
_nop_out(isc_session_t *sp)
{
pduq_t *pq;
nop_out_t *nop_out;
debug_called(8);
sdebug(4, "cws=%d", sp->cws);
if(sp->cws == 0) {
/*
| only send a nop if window is closed.
*/
if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
// I guess we ran out of resources
return;
nop_out = &pq->pdu.ipdu.nop_out;
nop_out->opcode = ISCSI_NOP_OUT;
nop_out->itt = htonl(sp->sn.itt);
nop_out->ttt = -1;
nop_out->I = 1;
nop_out->F = 1;
if(isc_qout(sp, pq) != 0) {
sdebug(1, "failed");
pdu_free(sp->isc, pq);
}
}
}
static void
_nop_in(isc_session_t *sp, pduq_t *pq)
{
pdu_t *pp = &pq->pdu;
nop_in_t *nop_in = &pp->ipdu.nop_in;
bhs_t *bhs = &pp->ipdu.bhs;
debug_called(8);
sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt));
if(nop_in->itt == -1) {
if(pp->ds_len != 0) {
/*
| according to RFC 3720 this should be zero
| what to do if not?
*/
xdebug("%d] dslen not zero", sp->sid);
}
if(nop_in->ttt != -1) {
nop_out_t *nop_out;
/*
| target wants a nop_out
*/
bhs->opcode = ISCSI_NOP_OUT;
bhs->I = 1;
bhs->F = 1;
/*
| we are reusing the pdu, so bhs->ttt == nop_in->ttt;
| and need to zero out 'Reserved'
| small cludge here.
*/
nop_out = &pp->ipdu.nop_out;
nop_out->sn.maxcmd = 0;
memset(nop_out->mbz, 0, sizeof(nop_out->mbz));
(void)isc_qout(sp, pq); //XXX: should check return?
return;
}
//else {
// just making noise?
// see 10.9.1: target does not want and answer.
//}
} else
if(nop_in->ttt == -1) {
/*
| it is an answer to a nop_in from us
*/
if(nop_in->itt != -1) {
#ifdef ISC_WAIT4PING
// XXX: MUTEX please
if(sp->flags & ISC_WAIT4PING) {
i_nqueue_rsp(sp, pq);
wakeup(&sp->rsp);
return;
}
#endif
}
}
/*
| drop it
*/
pdu_free(sp->isc, pq);
return;
}
int
i_prepPDU(isc_session_t *sp, pduq_t *pq)
{
size_t len, n;
pdu_t *pp = &pq->pdu;
bhs_t *bhp = &pp->ipdu.bhs;
len = sizeof(bhs_t);
if(pp->ahs_len) {
len += pp->ahs_len;
bhp->AHSLength = pp->ahs_len / 4;
}
if(ISOK2DIG(sp->hdrDigest, pp))
len += 4;
if(pp->ds_len) {
n = pp->ds_len;
len += n;
#if BYTE_ORDER == LITTLE_ENDIAN
bhp->DSLength = ((n & 0x00ff0000) >> 16)
| (n & 0x0000ff00)
| ((n & 0x000000ff) << 16);
#else
bhp->DSLength = n;
#endif
if(len & 03) {
n = 4 - (len & 03);
len += n;
}
if(ISOK2DIG(sp->dataDigest, pp))
len += 4;
}
pq->len = len;
len -= sizeof(bhs_t);
if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) {
xdebug("%d] pdu len=%zd > %d",
sp->sid, len, sp->opt.maxBurstLength);
// XXX: when this happens it used to hang ...
return E2BIG;
}
return 0;
}
int
isc_qout(isc_session_t *sp, pduq_t *pq)
{
int error = 0;
debug_called(8);
if(pq->len == 0 && (error = i_prepPDU(sp, pq)))
return error;
if(pq->pdu.ipdu.bhs.I)
i_nqueue_isnd(sp, pq);
else
if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA)
i_nqueue_wsnd(sp, pq);
else
i_nqueue_csnd(sp, pq);
sdebug(5, "enqued: pq=%p", pq);
mtx_lock(&sp->io_mtx);
sp->flags |= ISC_OQNOTEMPTY;
if(sp->flags & ISC_OWAITING)
wakeup(&sp->flags);
mtx_unlock(&sp->io_mtx);
return error;
}
/*
| called when a fullPhase is restarted
*/
void
ism_restart(isc_session_t *sp)
{
int lastcmd;
sdebug(2, "restart ...");
lastcmd = iscsi_requeue(sp);
#if 0
if(lastcmd != sp->sn.cmd) {
sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd);
sp->sn.cmd = lastcmd;
}
#endif
mtx_lock(&sp->io_mtx);
if(sp->flags & ISC_OWAITING) {
wakeup(&sp->flags);
}
mtx_unlock(&sp->io_mtx);
sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd);
}
void
ism_recv(isc_session_t *sp, pduq_t *pq)
{
bhs_t *bhs;
int statSN;
debug_called(8);
bhs = &pq->pdu.ipdu.bhs;
statSN = ntohl(bhs->OpcodeSpecificFields[1]);
#ifdef notyet
if(sp->sn.expCmd != sn->cmd) {
sdebug(1, "we lost something ... exp=0x%x cmd=0x%x",
sn->expCmd, sn->cmd);
}
#endif
sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x",
bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd);
switch(bhs->opcode) {
case ISCSI_READ_DATA: {
data_in_t *cmd = &pq->pdu.ipdu.data_in;
if(cmd->S == 0)
break;
}
default:
if(statSN > (sp->sn.stat + 1)) {
sdebug(1, "we lost some rec=0x%x exp=0x%x",
statSN, sp->sn.stat);
// XXX: must do some error recovery here.
}
sp->sn.stat = statSN;
}
switch(bhs->opcode) {
case ISCSI_LOGIN_RSP:
case ISCSI_TEXT_RSP:
case ISCSI_LOGOUT_RSP:
i_nqueue_rsp(sp, pq);
wakeup(&sp->rsp);
sdebug(3, "wakeup rsp");
break;
case ISCSI_NOP_IN: _nop_in(sp, pq); break;
case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break;
case ISCSI_READ_DATA: _read_data(sp, pq); break;
case ISCSI_R2T: _r2t(sp, pq); break;
case ISCSI_REJECT: _reject(sp, pq); break;
case ISCSI_ASYNC: _async(sp, pq); break;
case ISCSI_TASK_RSP:
default:
sdebug(1, "opcode=0x%x itt=0x%x not implemented yet",
bhs->opcode, ntohl(bhs->itt));
break;
}
}
/*
| go through the out queues looking for work
| if either nothing to do, or window is closed
| return.
*/
static int
proc_out(isc_session_t *sp)
{
sn_t *sn = &sp->sn;
pduq_t *pq;
int error, which;
debug_called(8);
error = 0;
while(sp->flags & ISC_LINK_UP) {
pdu_t *pp;
bhs_t *bhs;
/*
| check if there is outstanding work in:
| 1- the Immediate queue
| 2- the R2T queue
| 3- the cmd queue, only if the command window allows it.
*/
which = BIT(0) | BIT(1);
if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0
which |= BIT(2);
sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd);
if((pq = i_dqueue_snd(sp, which)) == NULL)
break;
sdebug(4, "pq=%p", pq);
pp = &pq->pdu;
bhs = &pp->ipdu.bhs;
switch(bhs->opcode) {
case ISCSI_SCSI_CMD:
sn->itt++;
bhs->itt = htonl(sn->itt);
case ISCSI_LOGIN_CMD:
case ISCSI_TEXT_CMD:
case ISCSI_LOGOUT_CMD:
case ISCSI_SNACK:
case ISCSI_NOP_OUT:
case ISCSI_TASK_CMD:
bhs->CmdSN = htonl(sn->cmd);
if(bhs->I == 0)
sn->cmd++;
case ISCSI_WRITE_DATA:
bhs->ExpStSN = htonl(sn->stat + 1);
break;
default:
// XXX: can this happen?
xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
bhs->opcode,
sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
// XXX: and now?
}
sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
bhs->opcode,
sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
if(bhs->opcode != ISCSI_NOP_OUT)
/*
| enqued till ack is received
| note: sosend(...) does not mean the packet left
| the host so that freeing resources has to wait
*/
i_nqueue_hld(sp, pq);
error = isc_sendPDU(sp, pq);
if(bhs->opcode == ISCSI_NOP_OUT)
pdu_free(sp->isc, pq);
if(error) {
xdebug("error=%d opcode=0x%x ccb=%p itt=%x",
error, bhs->opcode, pq->ccb, ntohl(bhs->itt));
i_remove_hld(sp, pq);
switch(error) {
case EPIPE:
sp->flags &= ~ISC_LINK_UP;
case EAGAIN:
xdebug("requed");
i_rqueue_pdu(sp, pq);
break;
default:
if(pq->ccb) {
xdebug("back to cam");
pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
xpt_done(pq->ccb);
pdu_free(sp->isc, pq);
}
else
xdebug("we lost it!");
}
}
}
return error;
}
/*
| survives link breakdowns.
*/
static void
ism_out(void *vp)
{
isc_session_t *sp = (isc_session_t *)vp;
int error;
debug_called(8);
sp->flags |= ISC_SM_RUNNING;
sdebug(3, "started sp->flags=%x", sp->flags);
do {
if((sp->flags & ISC_HOLD) == 0) {
error = proc_out(sp);
if(error) {
sdebug(3, "error=%d", error);
}
}
mtx_lock(&sp->io_mtx);
if((sp->flags & ISC_LINK_UP) == 0) {
sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags);
if(sp->soc != NULL)
sdebug(3, "so_state=%x", sp->soc->so_state);
wakeup(&sp->soc);
}
if(!(sp->flags & ISC_OQNOTEMPTY)) {
sp->flags |= ISC_OWAITING;
if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) {
if(sp->flags & ISC_CON_RUNNING)
_nop_out(sp);
}
sp->flags &= ~ISC_OWAITING;
}
sp->flags &= ~ISC_OQNOTEMPTY;
mtx_unlock(&sp->io_mtx);
} while(sp->flags & ISC_SM_RUN);
sp->flags &= ~ISC_SM_RUNNING;
sdebug(3, "dropped ISC_SM_RUNNING");
wakeup(&sp->soc);
wakeup(sp); // XXX: do we need this one?
destroy_dev(sp->dev);
debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
kproc_exit(0);
}
#if 0
static int
isc_dump_options(SYSCTL_HANDLER_ARGS)
{
int error;
isc_session_t *sp;
struct sbuf sb;
sbuf_new_for_sysctl(&sb, NULL, 128, req);
sp = (isc_session_t *)arg1;
sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName);
sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
return error;
}
#endif
static int
isc_dump_stats(SYSCTL_HANDLER_ARGS)
{
isc_session_t *sp;
struct isc_softc *sc;
int error;
struct sbuf sb;
sp = (isc_session_t *)arg1;
sc = sp->isc;
sbuf_new_for_sysctl(&sb, NULL, 128, req);
sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent);
sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d",
sp->flags, sc->npdu_alloc, sc->npdu_max);
sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x",
sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
return error;
}
static void
isc_add_sysctls(isc_session_t *sp)
{
debug_called(8);
sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev));
sysctl_ctx_init(&sp->clist);
sp->oid = SYSCTL_ADD_NODE(&sp->clist,
SYSCTL_CHILDREN(sp->isc->oid),
OID_AUTO,
devtoname(sp->dev) + 5, // iscsi0
CTLFLAG_RD | CTLFLAG_MPSAFE,
0,
"initiator");
SYSCTL_ADD_PROC(&sp->clist,
SYSCTL_CHILDREN(sp->oid),
OID_AUTO,
"targetname",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
(void *)&sp->opt.targetName, 0,
sysctl_handle_string, "A", "target name");
SYSCTL_ADD_PROC(&sp->clist,
SYSCTL_CHILDREN(sp->oid),
OID_AUTO,
"targeaddress",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
(void *)&sp->opt.targetAddress, 0,
sysctl_handle_string, "A", "target address");
SYSCTL_ADD_PROC(&sp->clist,
SYSCTL_CHILDREN(sp->oid),
OID_AUTO,
"stats",
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
(void *)sp, 0,
isc_dump_stats, "A", "statistics");
SYSCTL_ADD_INT(&sp->clist,
SYSCTL_CHILDREN(sp->oid),
OID_AUTO,
"douio",
CTLFLAG_RW,
&sp->douio, 0, "enable uio on read");
}
void
ism_stop(isc_session_t *sp)
{
struct isc_softc *sc = sp->isc;
int n;
debug_called(8);
sdebug(2, "terminating");
/*
| first stop the receiver
*/
isc_stop_receiver(sp);
/*
| now stop the xmitter
*/
n = 5;
sp->flags &= ~ISC_SM_RUN;
while(n-- && (sp->flags & ISC_SM_RUNNING)) {
sdebug(2, "n=%d", n);
wakeup(&sp->flags);
tsleep(sp, PRIBIO, "-", 5*hz);
}
sdebug(2, "final n=%d", n);
sp->flags &= ~ISC_FFPHASE;
iscsi_cleanup(sp);
(void)i_pdu_flush(sp);
ic_destroy(sp);
sx_xlock(&sc->unit_sx);
free_unr(sc->unit, sp->sid);
sx_xunlock(&sc->unit_sx);
mtx_lock(&sc->isc_mtx);
TAILQ_REMOVE(&sc->isc_sess, sp, sp_link);
sc->nsess--;
mtx_unlock(&sc->isc_mtx);
mtx_destroy(&sp->rsp_mtx);
mtx_destroy(&sp->rsv_mtx);
mtx_destroy(&sp->hld_mtx);
mtx_destroy(&sp->snd_mtx);
mtx_destroy(&sp->io_mtx);
i_freeopt(&sp->opt);
if(sysctl_ctx_free(&sp->clist))
xdebug("sysctl_ctx_free failed");
free(sp, M_ISCSI);
}
int
ism_start(isc_session_t *sp)
{
debug_called(8);
/*
| now is a good time to do some initialization
*/
TAILQ_INIT(&sp->rsp);
TAILQ_INIT(&sp->rsv);
TAILQ_INIT(&sp->csnd);
TAILQ_INIT(&sp->isnd);
TAILQ_INIT(&sp->wsnd);
TAILQ_INIT(&sp->hld);
mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF);
mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF);
mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF);
mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF);
mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF);
isc_add_sysctls(sp);
sp->flags |= ISC_SM_RUN;
debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
}

View file

@ -1,680 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/proc.h>
#include <sys/ioccom.h>
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/syslog.h>
#include <sys/mbuf.h>
#include <sys/user.h>
#include <vm/uma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
#ifndef NO_USE_MBUF
#define USE_MBUF
#endif
#ifdef USE_MBUF
static int ou_refcnt = 0;
/*
| function for freeing external storage for mbuf
*/
static void
ext_free(struct mbuf *m)
{
pduq_t *pq = m->m_ext.ext_arg1;
if(pq->buf != NULL) {
debug(3, "ou_refcnt=%d a=%p b=%p",
ou_refcnt, m->m_ext.ext_buf, pq->buf);
free(pq->buf, M_ISCSIBUF);
pq->buf = NULL;
}
}
int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
struct mbuf *mh, **mp;
pdu_t *pp = &pq->pdu;
int len, error;
debug_called(8);
/*
| mbuf for the iSCSI header
*/
MGETHDR(mh, M_WAITOK, MT_DATA);
mh->m_pkthdr.rcvif = NULL;
mh->m_next = NULL;
mh->m_len = sizeof(union ipdu_u);
if(ISOK2DIG(sp->hdrDigest, pp)) {
pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
mh->m_len += sizeof(pp->hdr_dig);
if(pp->ahs_len) {
debug(2, "ahs_len=%d", pp->ahs_len);
pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
}
debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig));
}
if(pp->ahs_len) {
/*
| Add any AHS to the iSCSI hdr mbuf
*/
if((mh->m_len + pp->ahs_len) < MHLEN) {
M_ALIGN(mh, mh->m_len + pp->ahs_len);
bcopy(&pp->ipdu, mh->m_data, mh->m_len);
bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len);
mh->m_len += pp->ahs_len;
}
else
panic("len AHS=%d too big, not impleneted yet", pp->ahs_len);
}
else {
M_ALIGN(mh, mh->m_len);
bcopy(&pp->ipdu, mh->m_data, mh->m_len);
}
mh->m_pkthdr.len = mh->m_len;
mp = &mh->m_next;
if(pp->ds_len && pq->pdu.ds_addr) {
struct mbuf *md;
int off = 0;
len = pp->ds_len;
while(len > 0) {
int l;
MGET(md, M_WAITOK, MT_DATA);
md->m_ext.ext_cnt = &ou_refcnt;
l = min(MCLBYTES, len);
debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
m_extadd(md, pp->ds_addr + off, l, ext_free, pq, NULL, 0,
EXT_EXTREF);
md->m_len = l;
md->m_next = NULL;
mh->m_pkthdr.len += l;
*mp = md;
mp = &md->m_next;
len -= l;
off += l;
}
if(((pp->ds_len & 03) != 0) || ISOK2DIG(sp->dataDigest, pp)) {
MGET(md, M_WAITOK, MT_DATA);
if(pp->ds_len & 03)
len = 4 - (pp->ds_len & 03);
else
len = 0;
md->m_len = len;
if(ISOK2DIG(sp->dataDigest, pp))
md->m_len += sizeof(pp->ds_dig);
M_ALIGN(md, md->m_len);
if(ISOK2DIG(sp->dataDigest, pp)) {
pp->ds_dig = sp->dataDigest(pp->ds_addr, pp->ds_len, 0);
if(len) {
bzero(md->m_data, len); // RFC says SHOULD be 0
pp->ds_dig = sp->dataDigest(md->m_data, len, pp->ds_dig);
}
bcopy(&pp->ds_dig, md->m_data+len, sizeof(pp->ds_dig));
}
md->m_next = NULL;
mh->m_pkthdr.len += md->m_len;
*mp = md;
}
}
if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
sdebug(2, "error=%d", error);
return error;
}
sp->stats.nsent++;
getbintime(&sp->stats.t_sent);
return 0;
}
#else /* NO_USE_MBUF */
int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
struct uio *uio = &pq->uio;
struct iovec *iv;
pdu_t *pp = &pq->pdu;
int len, error;
debug_called(8);
bzero(uio, sizeof(struct uio));
uio->uio_rw = UIO_WRITE;
uio->uio_segflg = UIO_SYSSPACE;
uio->uio_td = sp->td;
uio->uio_iov = iv = pq->iov;
iv->iov_base = &pp->ipdu;
iv->iov_len = sizeof(union ipdu_u);
uio->uio_resid = iv->iov_len;
iv++;
if(ISOK2DIG(sp->hdrDigest, pp))
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
if(pp->ahs_len) {
iv->iov_base = pp->ahs_addr;
iv->iov_len = pp->ahs_len;
uio->uio_resid += iv->iov_len;
iv++;
if(ISOK2DIG(sp->hdrDigest, pp))
pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
}
if(ISOK2DIG(sp->hdrDigest, pp)) {
debug(3, "hdr_dig=%04x", htonl(pp->hdr_dig));
iv->iov_base = &pp->hdr_dig;
iv->iov_len = sizeof(int);
uio->uio_resid += iv->iov_len ;
iv++;
}
if(pq->pdu.ds_addr && pp->ds_len) {
iv->iov_base = pp->ds_addr;
iv->iov_len = pp->ds_len;
while(iv->iov_len & 03) // the specs say it must be int aligned
iv->iov_len++;
uio->uio_resid += iv->iov_len ;
iv++;
if(ISOK2DIG(sp->dataDigest, pp)) {
pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
iv->iov_base = &pp->ds_dig;
iv->iov_len = sizeof(pp->ds_dig);
uio->uio_resid += iv->iov_len ;
iv++;
}
}
uio->uio_iovcnt = iv - pq->iov;
sdebug(4, "pq->len=%d uio->uio_resid=%d uio->uio_iovcnt=%d", pq->len,
uio->uio_resid,
uio->uio_iovcnt);
sdebug(4, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
ntohl(pp->ipdu.bhs.itt));
sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
sp, sp->soc, uio, sp->td);
do {
len = uio->uio_resid;
error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td);
if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
if(uio->uio_resid) {
sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
uio->uio_resid, uio->uio_iovcnt, error, len);
if(error == 0)
error = EAGAIN; // 35
}
break;
}
/*
| XXX: untested code
*/
sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
uio->uio_resid, uio->uio_iovcnt);
iv = uio->uio_iov;
len -= uio->uio_resid;
while(uio->uio_iovcnt > 0) {
if(iv->iov_len > len) {
caddr_t bp = (caddr_t)iv->iov_base;
iv->iov_len -= len;
iv->iov_base = (void *)&bp[len];
break;
}
len -= iv->iov_len;
uio->uio_iovcnt--;
uio->uio_iov++;
iv++;
}
} while(uio->uio_resid);
if(error == 0) {
sp->stats.nsent++;
getbintime(&sp->stats.t_sent);
}
return error;
}
#endif /* USE_MBUF */
/*
| wait till a PDU header is received
| from the socket.
*/
/*
The format of the BHS is:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| Opcode |F| Opcode-specific fields |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Opcode-specific fields |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20/ Opcode-specific fields /
+/ /
+---------------+---------------+---------------+---------------+
48
*/
static __inline int
so_getbhs(isc_session_t *sp)
{
bhs_t *bhs = &sp->bhs;
struct uio *uio = &sp->uio;
struct iovec *iov = &sp->iov;
int error, flags;
debug_called(8);
iov->iov_base = bhs;
iov->iov_len = sizeof(bhs_t);
uio->uio_iov = iov;
uio->uio_iovcnt = 1;
uio->uio_rw = UIO_READ;
uio->uio_segflg = UIO_SYSSPACE;
uio->uio_td = curthread; // why ...
uio->uio_resid = sizeof(bhs_t);
flags = MSG_WAITALL;
error = soreceive(sp->soc, NULL, uio, 0, 0, &flags);
if(error)
debug(2,
"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
error,
sp->soc->so_error, uio->uio_resid, iov->iov_len);
if(!error && (uio->uio_resid > 0)) {
error = EPIPE; // was EAGAIN
debug(2,
"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x",
error,
sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
}
return error;
}
/*
| so_recv gets called when
| an iSCSI header has been received.
| Note: the designers had no intentions
| in making programmer's life easy.
*/
static int
so_recv(isc_session_t *sp, pduq_t *pq)
{
sn_t *sn = &sp->sn;
struct uio *uio = &pq->uio;
pdu_t *pp = &pq->pdu;
bhs_t *bhs = &pp->ipdu.bhs;
struct iovec *iov = pq->iov;
int error;
u_int len;
u_int max, exp;
int flags = MSG_WAITALL;
debug_called(8);
/*
| now calculate how much data should be in the buffer
*/
uio->uio_iov = iov;
uio->uio_iovcnt = 0;
len = 0;
if(bhs->AHSLength) {
debug(2, "bhs->AHSLength=%d", bhs->AHSLength);
pp->ahs_len = bhs->AHSLength * 4;
len += pp->ahs_len;
pp->ahs_addr = malloc(pp->ahs_len, M_TEMP, M_WAITOK); // XXX: could get stuck here
iov->iov_base = pp->ahs_addr;
iov->iov_len = pp->ahs_len;
uio->uio_iovcnt++;
iov++;
}
if(ISOK2DIG(sp->hdrDigest, pp)) {
len += sizeof(pp->hdr_dig);
iov->iov_base = &pp->hdr_dig;
iov->iov_len = sizeof(pp->hdr_dig);
uio->uio_iovcnt++;
}
if(len) {
uio->uio_rw = UIO_READ;
uio->uio_segflg = UIO_SYSSPACE;
uio->uio_resid = len;
uio->uio_td = sp->td; // why ...
error = soreceive(sp->soc, NULL, uio, NULL, NULL, &flags);
//if(error == EAGAIN)
// XXX: this needs work! it hangs iscontrol
if(error || uio->uio_resid) {
debug(2,
"len=%d error=%d uio->uio_resid=%zd",
len, error, uio->uio_resid);
goto out;
}
if(ISOK2DIG(sp->hdrDigest, pp)) {
bhs_t *bhs;
u_int digest;
bhs = (bhs_t *)&pp->ipdu;
digest = sp->hdrDigest(bhs, sizeof(bhs_t), 0);
if(pp->ahs_len)
digest = sp->hdrDigest(pp->ahs_addr, pp->ahs_len, digest);
if(pp->hdr_dig != digest) {
debug(2, "bad header digest: received=%x calculated=%x", pp->hdr_dig, digest);
// XXX: now what?
error = EIO;
goto out;
}
}
if(pp->ahs_len) {
debug(2, "ahs len=%x type=%x spec=%x",
pp->ahs_addr->len, pp->ahs_addr->type, pp->ahs_addr->spec);
// XXX: till I figure out what to do with this
free(pp->ahs_addr, M_TEMP);
}
pq->len += len; // XXX: who needs this?
bzero(uio, sizeof(struct uio));
len = 0;
}
if(bhs->DSLength) {
len = bhs->DSLength;
#if BYTE_ORDER == LITTLE_ENDIAN
len = ((len & 0x00ff0000) >> 16)
| (len & 0x0000ff00)
| ((len & 0x000000ff) << 16);
#endif
pp->ds_len = len;
if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
len, sp->opt.maxRecvDataSegmentLength);
log(LOG_ERR,
"so_recv: impossible PDU length(%d) from iSCSI %s/%s\n",
len, sp->opt.targetAddress, sp->opt.targetName);
/*
| XXX: this will really screwup the stream.
| should clear up the buffer till a valid header
| is found, or just close connection ...
| should read the RFC.
*/
error = E2BIG;
goto out;
}
while(len & 03)
len++;
if(ISOK2DIG(sp->dataDigest, pp))
len += 4;
uio->uio_resid = len;
uio->uio_td = sp->td; // why ...
pq->len += len; // XXX: do we need this?
error = soreceive(sp->soc, NULL, uio, &pq->mp, NULL, &flags);
//if(error == EAGAIN)
// XXX: this needs work! it hangs iscontrol
if(error || uio->uio_resid)
goto out;
if(ISOK2DIG(sp->dataDigest, pp)) {
struct mbuf *m;
u_int digest, ds_len, cnt;
// get the received digest
m_copydata(pq->mp,
len - sizeof(pp->ds_dig),
sizeof(pp->ds_dig),
(caddr_t)&pp->ds_dig);
// calculate all mbufs
digest = 0;
ds_len = len - sizeof(pp->ds_dig);
for(m = pq->mp; m != NULL; m = m->m_next) {
cnt = MIN(ds_len, m->m_len);
digest = sp->dataDigest(mtod(m, char *), cnt, digest);
ds_len -= cnt;
if(ds_len == 0)
break;
}
if(digest != pp->ds_dig) {
sdebug(1, "bad data digest: received=%x calculated=%x", pp->ds_dig, digest);
error = EIO; // XXX: find a better error
goto out;
}
KASSERT(ds_len == 0, ("ds_len not zero"));
}
}
sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
max = ntohl(bhs->MaxCmdSN);
exp = ntohl(bhs->ExpStSN);
if(max < exp - 1 &&
max > exp - _MAXINCR) {
sdebug(2, "bad cmd window size");
error = EIO; // XXX: for now;
goto out; // error
}
if(SNA_GT(max, sn->maxCmd))
sn->maxCmd = max;
if(SNA_GT(exp, sn->expCmd))
sn->expCmd = exp;
/*
| remove from the holding queue packets
| that have been acked and don't need
| further processing.
*/
i_acked_hld(sp, NULL);
sp->cws = sn->maxCmd - sn->expCmd + 1;
return 0;
out:
// XXX: need some work here
if(pp->ahs_len) {
// XXX: till I figure out what to do with this
free(pp->ahs_addr, M_TEMP);
}
xdebug("have a problem, error=%d", error);
pdu_free(sp->isc, pq);
if(!error && uio->uio_resid > 0)
error = EPIPE;
return error;
}
/*
| wait for something to arrive.
| and if the pdu is without errors, process it.
*/
static int
so_input(isc_session_t *sp)
{
pduq_t *pq;
int error;
debug_called(8);
/*
| first read in the iSCSI header
*/
error = so_getbhs(sp);
if(error == 0) {
/*
| now read the rest.
*/
pq = pdu_alloc(sp->isc, M_NOWAIT);
if(pq == NULL) { // XXX: might cause a deadlock ...
debug(2, "out of pdus, wait");
pq = pdu_alloc(sp->isc, M_WAITOK); // OK to WAIT
}
pq->pdu.ipdu.bhs = sp->bhs;
pq->len = sizeof(bhs_t); // so far only the header was read
error = so_recv(sp, pq);
if(error != 0) {
error += 0x800; // XXX: just to see the error.
// terminal error
// XXX: close connection and exit
}
else {
sp->stats.nrecv++;
getbintime(&sp->stats.t_recv);
ism_recv(sp, pq);
}
}
return error;
}
/*
| one per active (connected) session.
| this thread is responsible for reading
| in packets from the target.
*/
static void
isc_in(void *vp)
{
isc_session_t *sp = (isc_session_t *)vp;
struct socket *so = sp->soc;
int error;
debug_called(8);
sp->flags |= ISC_CON_RUNNING;
error = 0;
while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
// XXX: hunting ...
if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
debug(2, "sp->soc=%p", sp->soc);
break;
}
error = so_input(sp);
if(error == 0) {
mtx_lock(&sp->io_mtx);
if(sp->flags & ISC_OWAITING) {
wakeup(&sp->flags);
}
mtx_unlock(&sp->io_mtx);
} else if(error == EPIPE) {
break;
}
else if(error == EAGAIN) {
if(so->so_state & SS_ISCONNECTED)
// there seems to be a problem in 6.0 ...
tsleep(sp, PRIBIO, "isc_soc", 2*hz);
}
}
sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p",
sp->flags, so->so_count, so->so_state, error, sp->proc);
if((sp->proc != NULL) && sp->signal) {
PROC_LOCK(sp->proc);
kern_psignal(sp->proc, sp->signal);
PROC_UNLOCK(sp->proc);
sp->flags |= ISC_SIGNALED;
sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
}
else {
// we have to do something ourselves
// like closing this session ...
}
/*
| we've been terminated
*/
// do we need this mutex ...?
mtx_lock(&sp->io_mtx);
sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP);
wakeup(&sp->soc);
mtx_unlock(&sp->io_mtx);
sdebug(2, "dropped ISC_CON_RUNNING");
kproc_exit(0);
}
void
isc_stop_receiver(isc_session_t *sp)
{
int n;
debug_called(8);
sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
mtx_lock(&sp->io_mtx);
sp->flags &= ~ISC_LINK_UP;
msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz);
soshutdown(sp->soc, SHUT_RD);
mtx_lock(&sp->io_mtx);
sdebug(3, "soshutdown");
sp->flags &= ~ISC_CON_RUN;
n = 2;
while(n-- && (sp->flags & ISC_CON_RUNNING)) {
sdebug(3, "waiting n=%d... flags=%x", n, sp->flags);
msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz);
}
mtx_unlock(&sp->io_mtx);
if(sp->fp != NULL)
fdrop(sp->fp, sp->td);
sp->soc = NULL;
sp->fp = NULL;
sdebug(3, "done");
}
void
isc_start_receiver(isc_session_t *sp)
{
debug_called(8);
sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
kproc_create(isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid);
}

View file

@ -1,184 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| iSCSI
| $Id: isc_subr.c 560 2009-05-07 07:37:49Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/gsb_crc32.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/proc.h>
#include <sys/ioccom.h>
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/syslog.h>
#include <sys/mbuf.h>
#include <sys/libkern.h>
#include <vm/uma.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
static MALLOC_DEFINE(M_ISC, "iSC", "iSCSI driver options");
static char *
i_strdupin(char *s, size_t maxlen)
{
size_t len;
char *p, *q;
p = malloc(maxlen, M_ISC, M_WAITOK);
if(copyinstr(s, p, maxlen, &len)) {
free(p, M_ISC);
return NULL;
}
q = malloc(len, M_ISC, M_WAITOK);
bcopy(p, q, len);
free(p, M_ISC);
return q;
}
static uint32_t
i_crc32c(const void *buf, size_t size, uint32_t crc)
{
crc = crc ^ 0xffffffff;
crc = calculate_crc32c(crc, buf, size);
crc = crc ^ 0xffffffff;
return crc;
}
/*
| XXX: not finished coding
*/
int
i_setopt(isc_session_t *sp, isc_opt_t *opt)
{
char buf[16];
int error;
if(opt->maxRecvDataSegmentLength > 0) {
sp->opt.maxRecvDataSegmentLength = opt->maxRecvDataSegmentLength;
sdebug(2, "maxRecvDataSegmentLength=%d", sp->opt.maxRecvDataSegmentLength);
}
if(opt->maxXmitDataSegmentLength > 0) {
// danny's RFC
sp->opt.maxXmitDataSegmentLength = opt->maxXmitDataSegmentLength;
sdebug(2, "opt.maXmitDataSegmentLength=%d", sp->opt.maxXmitDataSegmentLength);
}
if(opt->maxBurstLength != 0) {
sp->opt.maxBurstLength = opt->maxBurstLength;
sdebug(2, "opt.maxBurstLength=%d", sp->opt.maxBurstLength);
}
if(opt->targetAddress != NULL) {
if(sp->opt.targetAddress != NULL)
free(sp->opt.targetAddress, M_ISC);
sp->opt.targetAddress = i_strdupin(opt->targetAddress, 128);
sdebug(2, "opt.targetAddress='%s'", sp->opt.targetAddress);
}
if(opt->targetName != NULL) {
if(sp->opt.targetName != NULL)
free(sp->opt.targetName, M_ISC);
sp->opt.targetName = i_strdupin(opt->targetName, 128);
sdebug(2, "opt.targetName='%s'", sp->opt.targetName);
}
if(opt->initiatorName != NULL) {
if(sp->opt.initiatorName != NULL)
free(sp->opt.initiatorName, M_ISC);
sp->opt.initiatorName = i_strdupin(opt->initiatorName, 128);
sdebug(2, "opt.initiatorName='%s'", sp->opt.initiatorName);
}
if(opt->maxluns > 0) {
if(opt->maxluns > ISCSI_MAX_LUNS)
sp->opt.maxluns = ISCSI_MAX_LUNS; // silently chop it down ...
sp->opt.maxluns = opt->maxluns;
sdebug(2, "opt.maxluns=%d", sp->opt.maxluns);
}
if(opt->headerDigest != NULL) {
error = copyinstr(opt->headerDigest, buf, sizeof(buf), NULL);
if (error != 0)
return (error);
sdebug(2, "opt.headerDigest='%s'", buf);
if(strcmp(buf, "CRC32C") == 0) {
sp->hdrDigest = (digest_t *)i_crc32c;
sdebug(2, "opt.headerDigest set");
}
}
if(opt->dataDigest != NULL) {
error = copyinstr(opt->dataDigest, buf, sizeof(buf), NULL);
if (error != 0)
return (error);
sdebug(2, "opt.dataDigest='%s'", opt->dataDigest);
if(strcmp(buf, "CRC32C") == 0) {
sp->dataDigest = (digest_t *)i_crc32c;
sdebug(2, "opt.dataDigest set");
}
}
return 0;
}
void
i_freeopt(isc_opt_t *opt)
{
debug_called(8);
if(opt->targetAddress != NULL) {
free(opt->targetAddress, M_ISC);
opt->targetAddress = NULL;
}
if(opt->targetName != NULL) {
free(opt->targetName, M_ISC);
opt->targetName = NULL;
}
if(opt->initiatorName != NULL) {
free(opt->initiatorName, M_ISC);
opt->initiatorName = NULL;
}
}

View file

@ -1,880 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/capsicum.h>
#ifdef DO_EVENTHANDLER
#include <sys/eventhandler.h>
#endif
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/proc.h>
#include <sys/ioccom.h>
#include <sys/queue.h>
#include <sys/kthread.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <vm/uma.h>
#include <sys/sx.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
static char *iscsi_driver_version = "2.3.1";
static struct isc_softc *isc;
MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
#ifdef ISCSI_INITIATOR_DEBUG
int iscsi_debug = ISCSI_INITIATOR_DEBUG;
SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
"iSCSI driver debug flag");
struct mtx iscsi_dbg_mtx;
#endif
static int max_sessions = MAX_SESSIONS;
SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
&max_sessions, 0, "Max sessions allowed");
static int max_pdus = MAX_PDUS;
SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
&max_pdus, 0, "Max PDU pool");
static char isid[6+1] = {
0x80,
'D',
'I',
'B',
'0',
'0',
0
};
static int i_create_session(struct cdev *dev, int *ndev);
static int i_ping(struct cdev *dev);
static int i_send(struct cdev *dev, caddr_t arg, struct thread *td);
static int i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
static int i_setsoc(isc_session_t *sp, int fd, struct thread *td);
static int i_fullfeature(struct cdev *dev, int flag);
static d_open_t iscsi_open;
static d_close_t iscsi_close;
static d_ioctl_t iscsi_ioctl;
#ifdef ISCSI_INITIATOR_DEBUG
static d_read_t iscsi_read;
#endif
static struct cdevsw iscsi_cdevsw = {
.d_version = D_VERSION,
.d_open = iscsi_open,
.d_close = iscsi_close,
.d_ioctl = iscsi_ioctl,
#ifdef ISCSI_INITIATOR_DEBUG
.d_read = iscsi_read,
#endif
.d_name = "iSCSI",
};
static int
iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
{
debug_called(8);
debug(7, "dev=%d", dev2unit(dev));
if(dev2unit(dev) > max_sessions) {
// should not happen
return ENODEV;
}
return 0;
}
static int
iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
{
isc_session_t *sp;
debug_called(8);
debug(3, "session=%d flag=%x", dev2unit(dev), flag);
if(dev2unit(dev) == max_sessions) {
return 0;
}
sp = dev->si_drv2;
if(sp != NULL) {
sdebug(3, "sp->flags=%x", sp->flags );
/*
| if still in full phase, this probably means
| that something went really bad.
| it could be a result from 'shutdown', in which case
| we will ignore it (so buffers can be flushed).
| the problem is that there is no way of differentiating
| between a shutdown procedure and 'iscontrol' dying.
*/
if(sp->flags & ISC_FFPHASE)
// delay in case this is a shutdown.
tsleep(sp, PRIBIO, "isc-cls", 60*hz);
ism_stop(sp);
}
debug(2, "done");
return 0;
}
static int
iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
{
struct isc_softc *sc;
isc_session_t *sp;
isc_opt_t *opt;
int error;
debug_called(8);
error = 0;
if(dev2unit(dev) == max_sessions) {
/*
| non Session commands
*/
sc = dev->si_drv1;
if(sc == NULL)
return ENXIO;
switch(cmd) {
case ISCSISETSES:
error = i_create_session(dev, (int *)arg);
if(error == 0)
break;
default:
error = ENXIO;
}
return error;
}
/*
| session commands
*/
sp = dev->si_drv2;
if(sp == NULL)
return ENXIO;
sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff));
switch(cmd) {
case ISCSISETSOC:
error = i_setsoc(sp, *(u_int *)arg, td);
break;
case ISCSISETOPT:
opt = (isc_opt_t *)arg;
error = i_setopt(sp, opt);
break;
case ISCSISEND:
error = i_send(dev, arg, td);
break;
case ISCSIRECV:
error = i_recv(dev, arg, td);
break;
case ISCSIPING:
error = i_ping(dev);
break;
case ISCSISTART:
error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
if(error == 0) {
sp->proc = td->td_proc;
SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid),
OID_AUTO, "pid", CTLFLAG_RD,
&sp->proc->p_pid, sizeof(pid_t), "control process id");
}
break;
case ISCSIRESTART:
error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2);
break;
case ISCSISTOP:
error = i_fullfeature(dev, 0);
break;
case ISCSISIGNAL: {
int sig = *(int *)arg;
if(sig < 0 || sig > _SIG_MAXSIG)
error = EINVAL;
else
sp->signal = sig;
break;
}
case ISCSIGETCAM: {
iscsi_cam_t *cp = (iscsi_cam_t *)arg;
error = ic_getCamVals(sp, cp);
break;
}
default:
error = ENOIOCTL;
}
return error;
}
static int
iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
{
#ifdef ISCSI_INITIATOR_DEBUG
struct isc_softc *sc;
isc_session_t *sp;
pduq_t *pq;
char buf[1024];
sc = dev->si_drv1;
sp = dev->si_drv2;
if(dev2unit(dev) == max_sessions) {
sprintf(buf, "/----- Session ------/\n");
uiomove(buf, strlen(buf), uio);
int i = 0;
TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
if(uio->uio_resid == 0)
return 0;
sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName);
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "free npdu_alloc=%d, npdu_max=%d\n", sc->npdu_alloc, sc->npdu_max);
uiomove(buf, strlen(buf), uio);
}
else {
int i = 0;
struct socket *so = sp->soc;
#define pukeit(i, pq) do {\
sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\
i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\
pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
(intmax_t)pq->ts.sec);\
} while(0)
sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
uiomove(buf, strlen(buf), uio);
TAILQ_FOREACH(pq, &sp->hld, pq_link) {
if(uio->uio_resid == 0)
return 0;
pukeit(i, pq); i++;
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp);
uiomove(buf, strlen(buf), uio);
i = 0;
TAILQ_FOREACH(pq, &sp->rsp, pq_link) {
if(uio->uio_resid == 0)
return 0;
pukeit(i, pq); i++;
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd);
i = 0;
uiomove(buf, strlen(buf), uio);
TAILQ_FOREACH(pq, &sp->csnd, pq_link) {
if(uio->uio_resid == 0)
return 0;
pukeit(i, pq); i++;
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd);
i = 0;
uiomove(buf, strlen(buf), uio);
TAILQ_FOREACH(pq, &sp->wsnd, pq_link) {
if(uio->uio_resid == 0)
return 0;
pukeit(i, pq); i++;
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd);
i = 0;
uiomove(buf, strlen(buf), uio);
TAILQ_FOREACH(pq, &sp->isnd, pq_link) {
if(uio->uio_resid == 0)
return 0;
pukeit(i, pq); i++;
uiomove(buf, strlen(buf), uio);
}
sprintf(buf, "/---- Stats ---/\n");
uiomove(buf, strlen(buf), uio);
sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent);
uiomove(buf, strlen(buf), uio);
sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n",
sp->flags, sc->npdu_alloc, sc->npdu_max);
uiomove(buf, strlen(buf), uio);
sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n",
sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
uiomove(buf, strlen(buf), uio);
sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state);
uiomove(buf, strlen(buf), uio);
}
#endif
return 0;
}
static int
i_ping(struct cdev *dev)
{
return 0;
}
/*
| low level I/O
*/
static int
i_setsoc(isc_session_t *sp, int fd, struct thread *td)
{
cap_rights_t rights;
int error = 0;
if(sp->soc != NULL)
isc_stop_receiver(sp);
error = getsock_cap(td, fd, cap_rights_init_one(&rights, CAP_SOCK_CLIENT),
&sp->fp, NULL, NULL);
if(error)
return error;
sp->soc = sp->fp->f_data;
sp->td = td;
isc_start_receiver(sp);
return error;
}
static int
i_send(struct cdev *dev, caddr_t arg, struct thread *td)
{
isc_session_t *sp = dev->si_drv2;
caddr_t bp;
pduq_t *pq;
pdu_t *pp;
int n, error;
debug_called(8);
if(sp->soc == NULL)
return ENOTCONN;
if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
return EAGAIN;
pp = &pq->pdu;
pq->pdu = *(pdu_t *)arg;
if((error = i_prepPDU(sp, pq)) != 0)
goto out;
bp = NULL;
if((pq->len - sizeof(union ipdu_u)) > 0) {
pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
if(pq->buf == NULL) {
error = EAGAIN;
goto out;
}
}
else
pq->buf = NULL; // just in case?
sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
if(pp->ahs_len) {
// XXX: never tested, looks suspicious
n = pp->ahs_len;
error = copyin(pp->ahs_addr, bp, n);
if(error != 0) {
sdebug(3, "copyin ahs: error=%d", error);
goto out;
}
pp->ahs_addr = (ahs_t *)bp;
bp += n;
}
if(pp->ds_len) {
n = pp->ds_len;
error = copyin(pp->ds_addr, bp, n);
if(error != 0) {
sdebug(3, "copyin ds: error=%d", error);
goto out;
}
pp->ds_addr = bp;
bp += n;
while(n & 03) {
n++;
*bp++ = 0;
}
}
error = isc_qout(sp, pq);
if(error == 0)
wakeup(&sp->flags); // XXX: to 'push' proc_out ...
out:
if(error)
pdu_free(sp->isc, pq);
return error;
}
static int
i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
{
isc_session_t *sp = dev->si_drv2;
pduq_t *pq;
pdu_t *pp, *up;
caddr_t bp;
int error, mustfree, cnt;
size_t need, have, n;
debug_called(8);
if(sp == NULL)
return EIO;
if(sp->soc == NULL)
return ENOTCONN;
cnt = 6; // XXX: maybe the user can request a time out?
mtx_lock(&sp->rsp_mtx);
while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
if(cnt-- == 0) break; // XXX: for now, needs work
}
if(pq != NULL) {
sp->stats.nrsp--;
TAILQ_REMOVE(&sp->rsp, pq, pq_link);
}
mtx_unlock(&sp->rsp_mtx);
sdebug(6, "cnt=%d", cnt);
if(pq == NULL) {
error = ENOTCONN;
sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
return error;
}
up = (pdu_t *)arg;
pp = &pq->pdu;
up->ipdu = pp->ipdu;
n = 0;
up->ds_len = 0;
up->ahs_len = 0;
error = 0;
if(pq->mp) {
u_int len;
// Grr...
len = 0;
if(pp->ahs_len) {
len += pp->ahs_len;
}
if(pp->ds_len) {
len += pp->ds_len;
}
mustfree = 0;
if(len > pq->mp->m_len) {
mustfree++;
bp = malloc(len, M_TMP, M_WAITOK);
sdebug(4, "need mbufcopy: %d", len);
i_mbufcopy(pq->mp, bp, len);
}
else
bp = mtod(pq->mp, caddr_t);
if(pp->ahs_len) {
need = pp->ahs_len;
n = MIN(up->ahs_size, need);
error = copyout(bp, (caddr_t)up->ahs_addr, n);
up->ahs_len = n;
bp += need;
}
if(!error && pp->ds_len) {
need = pp->ds_len;
if((have = up->ds_size) == 0) {
have = up->ahs_size - n;
up->ds_addr = (caddr_t)up->ahs_addr + n;
}
n = MIN(have, need);
error = copyout(bp, (caddr_t)up->ds_addr, n);
up->ds_len = n;
}
if(mustfree)
free(bp, M_TMP);
}
sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
pdu_free(sp->isc, pq);
return error;
}
static int
i_fullfeature(struct cdev *dev, int flag)
{
isc_session_t *sp = dev->si_drv2;
int error;
sdebug(2, "flag=%d", flag);
error = 0;
switch(flag) {
case 0: // stop
sp->flags &= ~ISC_FFPHASE;
break;
case 1: // start
sp->flags |= ISC_FFPHASE;
error = ic_init(sp);
break;
case 2: // restart
sp->flags |= ISC_FFPHASE;
ism_restart(sp);
break;
}
return error;
}
static int
i_create_session(struct cdev *dev, int *ndev)
{
struct isc_softc *sc = dev->si_drv1;
isc_session_t *sp;
int error, n;
debug_called(8);
sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
if(sp == NULL)
return ENOMEM;
sx_xlock(&sc->unit_sx);
if((n = alloc_unr(sc->unit)) < 0) {
sx_unlock(&sc->unit_sx);
free(sp, M_ISCSI);
xdebug("too many sessions!");
return EPERM;
}
sx_unlock(&sc->unit_sx);
mtx_lock(&sc->isc_mtx);
TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
isc->nsess++;
mtx_unlock(&sc->isc_mtx);
sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
*ndev = sp->sid = n;
sp->isc = sc;
sp->dev->si_drv1 = sc;
sp->dev->si_drv2 = sp;
sp->opt.maxRecvDataSegmentLength = 8192;
sp->opt.maxXmitDataSegmentLength = 8192;
sp->opt.maxBurstLength = 65536; // 64k
sp->opt.maxluns = ISCSI_MAX_LUNS;
error = ism_start(sp);
return error;
}
#ifdef notused
static void
iscsi_counters(isc_session_t *sp)
{
int h, r, s;
pduq_t *pq;
#define _puke(i, pq) do {\
debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
(long)pq->ts.sec, pq->ts.frac, pq->flags);\
} while(0)
h = r = s = 0;
TAILQ_FOREACH(pq, &sp->hld, pq_link) {
_puke(h, pq);
h++;
}
TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
}
#endif
static void
iscsi_shutdown(void *v)
{
struct isc_softc *sc = v;
isc_session_t *sp;
int n;
debug_called(8);
if(sc == NULL) {
xdebug("sc is NULL!");
return;
}
#ifdef DO_EVENTHANDLER
if(sc->eh == NULL)
debug(2, "sc->eh is NULL");
else {
EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
debug(2, "done n=%d", sc->nsess);
}
#endif
n = 0;
TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
n++;
}
debug(2, "done");
}
static void
free_pdus(struct isc_softc *sc)
{
debug_called(8);
if(sc->pdu_zone != NULL) {
uma_zdestroy(sc->pdu_zone);
sc->pdu_zone = NULL;
}
}
static int
iscsi_start(void)
{
debug_called(8);
isc = malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
TAILQ_INIT(&isc->isc_sess);
/*
| now init the free pdu list
*/
isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
NULL, NULL, NULL, NULL,
0, 0);
uma_zone_set_max(isc->pdu_zone, max_pdus);
isc->unit = new_unrhdr(0, max_sessions-1, NULL);
sx_init(&isc->unit_sx, "iscsi sx");
#ifdef DO_EVENTHANDLER
if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
xdebug("shutdown event registration failed\n");
#endif
/*
| sysctl stuff
*/
sysctl_ctx_init(&isc->clist);
isc->oid = SYSCTL_ADD_NODE(&isc->clist,
SYSCTL_STATIC_CHILDREN(_net),
OID_AUTO,
"iscsi_initiator",
CTLFLAG_RD | CTLFLAG_MPSAFE,
0,
"iSCSI Subsystem");
SYSCTL_ADD_STRING(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"driver_version",
CTLFLAG_RD,
iscsi_driver_version,
0,
"iscsi driver version");
SYSCTL_ADD_STRING(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"isid",
CTLFLAG_RW,
isid,
6+1,
"initiator part of the Session Identifier");
SYSCTL_ADD_INT(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"sessions",
CTLFLAG_RD,
&isc->nsess,
sizeof(isc->nsess),
"number of active session");
#ifdef ISCSI_INITIATOR_DEBUG
mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
#endif
isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
if (isc->dev == NULL) {
xdebug("iscsi_initiator: make_dev_credf failed");
return (EEXIST);
}
isc->dev->si_drv1 = isc;
printf("iscsi: version %s\n", iscsi_driver_version);
return (0);
}
/*
| Notes:
| unload SHOULD fail if there is activity
| activity: there is/are active session/s
*/
static void
iscsi_stop(void)
{
isc_session_t *sp, *sp_tmp;
debug_called(8);
/*
| go through all the sessions
| Note: close should have done this ...
*/
TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
//XXX: check for activity ...
ism_stop(sp);
}
mtx_destroy(&isc->isc_mtx);
sx_destroy(&isc->unit_sx);
free_pdus(isc);
if(isc->dev)
destroy_dev(isc->dev);
if(sysctl_ctx_free(&isc->clist))
xdebug("sysctl_ctx_free failed");
iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
#ifdef ISCSI_INITIATOR_DEBUG
mtx_destroy(&iscsi_dbg_mtx);
#endif
free(isc, M_ISCSI);
}
static int
iscsi_modevent(module_t mod, int what, void *arg)
{
int error = 0;
debug_called(8);
switch(what) {
case MOD_LOAD:
error = iscsi_start();
break;
case MOD_QUIESCE:
if(isc->nsess) {
xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
log(LOG_ERR, "iscsi module busy, cannot unload");
}
return isc->nsess;
case MOD_SHUTDOWN:
break;
case MOD_UNLOAD:
iscsi_stop();
break;
default:
break;
}
return (error);
}
moduledata_t iscsi_mod = {
"iscsi_initiator",
(modeventhand_t) iscsi_modevent,
0
};
#ifdef ISCSI_ROOT
static void
iscsi_rootconf(void)
{
#if 0
nfs_setup_diskless();
if (nfs_diskless_valid)
rootdevnames[0] = "nfs:";
#endif
printf("** iscsi_rootconf **\n");
}
SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
#endif
DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);

View file

@ -1,502 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
| $Id: iscsi.h 743 2009-08-08 10:54:53Z danny $
*/
#define TRUE 1
#define FALSE 0
#ifndef _KERNEL
typedef int boolean_t;
#endif
#include <cam/cam.h>
#define ISCSIDEV "iscsi"
#define ISCSI_MAX_TARGETS 64
/*
| iSCSI commands
*/
/*
| Initiator Opcodes:
*/
#define ISCSI_NOP_OUT 0x00
#define ISCSI_SCSI_CMD 0x01
#define ISCSI_TASK_CMD 0x02
#define ISCSI_LOGIN_CMD 0x03
#define ISCSI_TEXT_CMD 0x04
#define ISCSI_WRITE_DATA 0x05
#define ISCSI_LOGOUT_CMD 0x06
#define ISCSI_SNACK 0x10
/*
| Target Opcodes:
*/
#define ISCSI_NOP_IN 0x20
#define ISCSI_SCSI_RSP 0x21
#define ISCSI_TASK_RSP 0x22
#define ISCSI_LOGIN_RSP 0x23
#define ISCSI_TEXT_RSP 0x24
#define ISCSI_READ_DATA 0x25
#define ISCSI_LOGOUT_RSP 0x26
#define ISCSI_R2T 0x31
#define ISCSI_ASYNC 0x32
#define ISCSI_REJECT 0x3f
/*
| PDU stuff
*/
/*
| BHS Basic Header Segment
*/
typedef struct bhs {
// the order is network byte order!
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char __:7;
u_char F:1; // Final bit
u_char ___[2];
u_int AHSLength:8; // in 4byte words
u_int DSLength:24; // in bytes
u_int LUN[2]; // or Opcode-specific fields
u_int itt;
u_int OpcodeSpecificFields[7];
#define CmdSN OpcodeSpecificFields[1]
#define ExpStSN OpcodeSpecificFields[2]
#define MaxCmdSN OpcodeSpecificFields[3]
} bhs_t;
typedef struct ahs {
u_int len:16;
u_int type:8;
u_int spec:8;
char data[0];
} ahs_t;
typedef struct {
// Sequence Numbers
// (computers were invented to count, right?)
int cmd;
int expcmd;
int maxcmd;
} req_sn_t;
typedef struct {
// Sequence Numbers
// (computers were invented to count, right?)
int stat;
int expcmd;
int maxcmd;
} rsp_sn_t;
typedef struct scsi_req {
u_char opcode:6; // 0x01
u_char I:1;
u_char _:1;
u_char attr:3;
u_char _0:2;
u_char W:1;
u_char R:1;
u_char F:1;
#define iSCSI_TASK_UNTAGGED 0
#define iSCSI_TASK_SIMPLE 1
#define iSCSI_TASK_ORDER 2
#define iSCSI_TASK_HOFQ 3
#define iSCSI_TASK_ACA 4
char _1[2];
int len;
int lun[2];
int itt;
int edtlen; // expectect data transfere length
int cmdSN;
int extStatSN;
int cdb[4];
} scsi_req_t;
typedef struct scsi_rsp {
char opcode; // 0x21
u_char flag;
u_char response;
u_char status;
int len;
int _[2];
int itt;
int stag;
rsp_sn_t sn;
int expdatasn;
int bdrcnt; // bidirectional residual count
int rcnt; // residual count
} scsi_rsp_t;
typedef struct nop_out {
// the order is network byte order!
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char __:7;
u_char F:1; // Final bit
u_char ___[2];
u_int len;
u_int lun[2];
u_int itt;
u_int ttt;
req_sn_t sn;
u_int mbz[3];
} nop_out_t;
typedef struct nop_in {
// the order is network byte order!
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char __:7;
u_char F:1; // Final bit
u_char ___[2];
u_int len;
u_int lun[2];
u_int itt;
u_int ttt;
rsp_sn_t sn;
u_int ____[2];
} nop_in_t;
typedef struct r2t {
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char __:7;
u_char F:1; // Final bit
u_char ___[2];
u_int len;
u_int lun[2];
u_int itt;
u_int ttt;
rsp_sn_t sn;
u_int r2tSN;
u_int bo;
u_int ddtl;
} r2t_t;
typedef struct data_out {
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char __:7;
u_char F:1; // Final bit
u_char ___[2];
u_int len;
u_int lun[2];
u_int itt;
u_int ttt;
rsp_sn_t sn;
u_int dsn; // data seq. number
u_int bo;
u_int ____;
} data_out_t;
typedef struct data_in {
u_char opcode:6;
u_char I:1;
u_char _:1;
u_char S:1;
u_char U:1;
u_char O:1;
u_char __:3;
u_char A:1;
u_char F:1; // Final bit
u_char ___[1];
u_char status;
u_int len;
u_int lun[2];
u_int itt;
u_int ttt;
rsp_sn_t sn;
u_int dataSN;
u_int bo;
u_int ____;
} data_in_t;
typedef struct reject {
u_char opcode:6;
u_char _:2;
u_char F:1;
u_char __:7;
u_char reason;
u_char ___;
u_int len;
u_int ____[2];
u_int tt[2]; // must be -1
rsp_sn_t sn;
u_int dataSN; // or R2TSN or reserved
u_int _____[2];
} reject_t;
typedef struct async {
u_char opcode:6;
u_char _:2;
u_char F:1;
u_char __:7;
u_char ___[2];
u_int len;
u_int lun[2];
u_int itt; // must be -1
u_int ____;
rsp_sn_t sn;
u_char asyncEvent;
u_char asyncVCode;
u_char param1[2];
u_char param2[2];
u_char param3[2];
u_int _____;
} async_t;
typedef struct login_req {
char cmd; // 0x03
u_char NSG:2;
u_char CSG:2;
u_char _:2;
u_char C:1;
u_char T:1;
char v_max;
char v_min;
int len; // remapped via standard bhs
char isid[6];
short tsih;
int itt; // Initiator Task Tag;
int CID:16;
int rsv:16;
int cmdSN;
int expStatSN;
int unused[4];
} login_req_t;
typedef struct login_rsp {
char cmd; // 0x23
u_char NSG:2;
u_char CSG:2;
u_char _1:2;
u_char C:1;
u_char T:1;
char v_max;
char v_act;
int len; // remapped via standard bhs
char isid[6];
short tsih;
int itt; // Initiator Task Tag;
int _2;
rsp_sn_t sn;
int status:16;
int _3:16;
int _4[2];
} login_rsp_t;
typedef struct text_req {
char cmd; // 0x04
u_char _1:6;
u_char C:1; // Continuation
u_char F:1; // Final
char _2[2];
int len;
int itt; // Initiator Task Tag
int LUN[2];
int ttt; // Target Transfer Tag
int cmdSN;
int expStatSN;
int unused[4];
} text_req_t;
typedef struct logout_req {
char cmd; // 0x06
u_char reason; // 0 - close session
// 1 - close connection
// 2 - remove the connection for recovery
char _2[2];
int len;
int _r[2];
int itt; // Initiator Task Tag;
u_int CID:16;
u_int rsv:16;
int cmdSN;
int expStatSN;
int unused[4];
} logout_req_t;
typedef struct logout_rsp {
char cmd; // 0x26
char cbits;
char _1[2];
int len;
int _2[2];
int itt;
int _3;
rsp_sn_t sn;
short time2wait;
short time2retain;
int _4;
} logout_rsp_t;
union ipdu_u {
bhs_t bhs;
scsi_req_t scsi_req;
scsi_rsp_t scsi_rsp;
nop_out_t nop_out;
nop_in_t nop_in;
r2t_t r2t;
data_out_t data_out;
data_in_t data_in;
reject_t reject;
async_t async;
};
/*
| Sequence Numbers
*/
typedef struct {
u_int itt;
u_int cmd;
u_int expCmd;
u_int maxCmd;
u_int stat;
u_int expStat;
u_int data;
} sn_t;
/*
| in-core version of a Protocol Data Unit
*/
typedef struct {
union ipdu_u ipdu;
u_int hdr_dig; // header digest
ahs_t *ahs_addr;
u_int ahs_len;
u_int ahs_size; // the allocated size
u_char *ds_addr;
u_int ds_len;
u_int ds_size; // the allocated size
u_int ds_dig; // data digest
} pdu_t;
typedef struct opvals {
int port;
int tags;
int maxluns;
int sockbufsize;
int maxConnections;
int maxRecvDataSegmentLength;
int maxXmitDataSegmentLength; // pseudo ...
int maxBurstLength;
int firstBurstLength;
int defaultTime2Wait;
int defaultTime2Retain;
int maxOutstandingR2T;
int errorRecoveryLevel;
int targetPortalGroupTag;
boolean_t initialR2T;
boolean_t immediateData;
boolean_t dataPDUInOrder;
boolean_t dataSequenceInOrder;
char *headerDigest;
char *dataDigest;
char *sessionType;
char *sendTargets;
char *targetAddress;
char *targetAlias;
char *targetName;
char *initiatorName;
char *initiatorAlias;
char *authMethod;
char *chapSecret;
char *chapIName;
char *chapDigest;
char *tgtChapName;
char *tgtChapSecret;
int tgtChallengeLen;
u_char tgtChapID;
char *tgtChapDigest;
char *iqn;
char *pidfile;
} isc_opt_t;
/*
| ioctl
*/
#define ISCSISETSES _IOR('i', 1, int)
#define ISCSISETSOC _IOW('i', 2, int)
#define ISCSISETOPT _IOW('i', 5, isc_opt_t)
#define ISCSIGETOPT _IOR('i', 6, isc_opt_t)
#define ISCSISEND _IOW('i', 10, pdu_t)
#define ISCSIRECV _IOWR('i', 11, pdu_t)
#define ISCSIPING _IO('i', 20)
#define ISCSISIGNAL _IOW('i', 21, int *)
#define ISCSISTART _IO('i', 30)
#define ISCSIRESTART _IO('i', 31)
#define ISCSISTOP _IO('i', 32)
typedef struct iscsi_cam {
path_id_t path_id;
target_id_t target_id;
int target_nluns;
} iscsi_cam_t;
#define ISCSIGETCAM _IOR('i', 33, iscsi_cam_t)

View file

@ -1,603 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
| $Id: iscsi_subr.c 743 2009-08-08 10:54:53Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_iscsi_initiator.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <vm/uma.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_periph.h>
#include <cam/scsi/scsi_message.h>
#include <sys/eventhandler.h>
#include <dev/iscsi_initiator/iscsi.h>
#include <dev/iscsi_initiator/iscsivar.h>
/*
| Interface to the SCSI layer
*/
void
iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
{
union ccb *ccb = opq->ccb;
struct ccb_scsiio *csio = &ccb->csio;
pdu_t *opp = &opq->pdu;
bhs_t *bhp = &opp->ipdu.bhs;
r2t_t *r2t = &pq->pdu.ipdu.r2t;
pduq_t *wpq;
int error;
debug_called(8);
sdebug(4, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt),
ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W);
switch(bhp->opcode) {
case ISCSI_SCSI_CMD:
if(opp->ipdu.scsi_req.W) {
data_out_t *cmd;
u_int ddtl = ntohl(r2t->ddtl);
u_int edtl = ntohl(opp->ipdu.scsi_req.edtlen);
u_int bleft, bs, dsn, bo;
caddr_t bp = csio->data_ptr;
bo = ntohl(r2t->bo);
bp += MIN(bo, edtl - ddtl);
bleft = ddtl;
if(sp->opt.maxXmitDataSegmentLength > 0) // danny's RFC
bs = MIN(sp->opt.maxXmitDataSegmentLength, ddtl);
else
bs = ddtl;
dsn = 0;
sdebug(4, "edtl=%x ddtl=%x bo=%x dsn=%x bs=%x maxX=%x",
edtl, ddtl, bo, dsn, bs, sp->opt.maxXmitDataSegmentLength);
while(bleft > 0) {
wpq = pdu_alloc(sp->isc, M_NOWAIT); // testing ...
if(wpq == NULL) {
sdebug(3, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt),
ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W);
sdebug(1, "npdu_max=%d npdu_alloc=%d", sp->isc->npdu_max, sp->isc->npdu_alloc);
while((wpq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
sdebug(2, "waiting...");
pause("isc_r2t", 5*hz);
}
}
cmd = &wpq->pdu.ipdu.data_out;
cmd->opcode = ISCSI_WRITE_DATA;
cmd->lun[0] = r2t->lun[0];
cmd->lun[1] = r2t->lun[1];
cmd->ttt = r2t->ttt;
cmd->itt = r2t->itt;
cmd->dsn = htonl(dsn);
cmd->bo = htonl(bo);
cmd->F = (bs < bleft)? 0: 1; // is this the last one?
bs = MIN(bs, bleft);
wpq->pdu.ds_len = bs;
wpq->pdu.ds_addr = bp;
error = isc_qout(sp, wpq);
sdebug(6, "bs=%x bo=%x bp=%p dsn=%x error=%d", bs, bo, bp, dsn, error);
if(error)
break;
bo += bs;
bp += bs;
bleft -= bs;
dsn++;
}
}
break;
default:
// XXX: should not happen ...
xdebug("huh? opcode=0x%x", bhp->opcode);
}
}
static int
getSenseData(u_int status, union ccb *ccb, pduq_t *pq)
{
pdu_t *pp = &pq->pdu;
struct ccb_scsiio *scsi = (struct ccb_scsiio *)ccb;
struct scsi_sense_data *sense = &scsi->sense_data;
struct mbuf *m = pq->mp;
scsi_rsp_t *cmd = &pp->ipdu.scsi_rsp;
caddr_t bp;
int sense_len, mustfree = 0;
int error_code, sense_key, asc, ascq;
bp = mtod(pq->mp, caddr_t);
if((sense_len = scsi_2btoul(bp)) == 0)
return 0;
debug(4, "sense_len=%d", sense_len);
/*
| according to the specs, the sense data cannot
| be larger than 252 ...
*/
if(sense_len > m->m_len) {
bp = malloc(sense_len, M_ISCSI, M_WAITOK);
debug(3, "calling i_mbufcopy(len=%d)", sense_len);
i_mbufcopy(pq->mp, bp, sense_len);
mustfree++;
}
scsi->scsi_status = status;
bcopy(bp+2, sense, min(sense_len, scsi->sense_len));
scsi->sense_resid = 0;
if(cmd->flag & (BIT(1)|BIT(2)))
scsi->sense_resid = ntohl(pp->ipdu.scsi_rsp.rcnt);
scsi_extract_sense_len(sense, scsi->sense_len - scsi->sense_resid,
&error_code, &sense_key, &asc, &ascq, /*show_errors*/ 1);
debug(3, "sense_len=%d rcnt=%d sense_resid=%d dsl=%d error_code=%x flags=%x",
sense_len,
ntohl(pp->ipdu.scsi_rsp.rcnt), scsi->sense_resid,
pp->ds_len, error_code, sense_key);
if(mustfree)
free(bp, M_ISCSI);
return 1;
}
/*
| Some information is from SAM draft.
*/
static void
_scsi_done(isc_session_t *sp, u_int response, u_int status, union ccb *ccb, pduq_t *pq)
{
struct ccb_hdr *ccb_h = &ccb->ccb_h;
debug_called(8);
if(status || response) {
sdebug(3, "response=%x status=%x ccb=%p pq=%p", response, status, ccb, pq);
if(pq != NULL)
sdebug(3, "mp=%p buf=%p len=%d", pq->mp, pq->buf, pq->len);
}
ccb_h->status = 0;
switch(response) {
case 0: // Command Completed at Target
switch(status) {
case 0: // Good, all is ok
ccb_h->status = CAM_REQ_CMP;
break;
case 0x02: // Check Condition
if((pq != NULL) && (pq->mp != NULL) && getSenseData(status, ccb, pq))
ccb_h->status |= CAM_AUTOSNS_VALID;
case 0x14: // Intermediate-Condition Met
case 0x10: // Intermediate
case 0x04: // Condition Met
ccb_h->status |= CAM_SCSI_STATUS_ERROR;
break;
case 0x08:
ccb_h->status = CAM_BUSY;
break;
case 0x18: // Reservation Conflict
case 0x28: // Task Set Full
ccb_h->status = CAM_REQUEUE_REQ;
break;
default:
//case 0x22: // Command Terminated
//case 0x30: // ACA Active
//case 0x40: // Task Aborted
ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
}
break;
default:
if((response >= 0x80) && (response <= 0xFF)) {
// Vendor specific ...
}
case 1: // target failure
ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
break;
}
sdebug(5, "ccb_h->status=%x", ccb_h->status);
xpt_done(ccb);
}
/*
| returns the lowest cmdseq that was not acked
*/
int
iscsi_requeue(isc_session_t *sp)
{
pduq_t *pq;
u_int i, n, last;
debug_called(8);
i = last = 0;
sp->flags |= ISC_HOLD;
while((pq = i_dqueue_hld(sp)) != NULL) {
i++;
if(pq->ccb != NULL) {
_scsi_done(sp, 0, 0x28, pq->ccb, NULL);
n = ntohl(pq->pdu.ipdu.bhs.CmdSN);
if(last==0 || (last > n))
last = n;
sdebug(2, "last=%x n=%x", last, n);
}
pdu_free(sp->isc, pq);
}
sp->flags &= ~ISC_HOLD;
return i? last: sp->sn.cmd;
}
int
i_pdu_flush(isc_session_t *sp)
{
int n = 0;
pduq_t *pq;
debug_called(8);
while((pq = i_dqueue_rsp(sp)) != NULL) {
pdu_free(sp->isc, pq);
n++;
}
while((pq = i_dqueue_rsv(sp)) != NULL) {
pdu_free(sp->isc, pq);
n++;
}
while((pq = i_dqueue_snd(sp, -1)) != NULL) {
pdu_free(sp->isc, pq);
n++;
}
while((pq = i_dqueue_hld(sp)) != NULL) {
pdu_free(sp->isc, pq);
n++;
}
while((pq = i_dqueue_wsnd(sp)) != NULL) {
pdu_free(sp->isc, pq);
n++;
}
if(n != 0)
xdebug("%d pdus recovered, should have been ZERO!", n);
return n;
}
/*
| called from ism_destroy.
*/
void
iscsi_cleanup(isc_session_t *sp)
{
pduq_t *pq, *pqtmp;
debug_called(8);
TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, pqtmp) {
sdebug(3, "hld pq=%p", pq);
if(pq->ccb)
_scsi_done(sp, 1, 0x40, pq->ccb, NULL);
TAILQ_REMOVE(&sp->hld, pq, pq_link);
if(pq->buf) {
free(pq->buf, M_ISCSIBUF);
pq->buf = NULL;
}
pdu_free(sp->isc, pq);
}
while((pq = i_dqueue_snd(sp, BIT(0)|BIT(1)|BIT(2))) != NULL) {
sdebug(3, "pq=%p", pq);
if(pq->ccb)
_scsi_done(sp, 1, 0x40, pq->ccb, NULL);
if(pq->buf) {
free(pq->buf, M_ISCSIBUF);
pq->buf = NULL;
}
pdu_free(sp->isc, pq);
}
wakeup(&sp->rsp);
}
void
iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
{
pdu_t *pp = &pq->pdu;
scsi_rsp_t *cmd = &pp->ipdu.scsi_rsp;
debug_called(8);
_scsi_done(sp, cmd->response, cmd->status, opq->ccb, pq);
pdu_free(sp->isc, opq);
}
// see RFC 3720, 10.9.1 page 146
/*
| NOTE:
| the call to isc_stop_receiver is a kludge,
| instead, it should be handled by the userland controller,
| but that means that there should be a better way, other than
| sending a signal. Somehow, this packet should be supplied to
| the userland via read.
*/
void
iscsi_async(isc_session_t *sp, pduq_t *pq)
{
pdu_t *pp = &pq->pdu;
async_t *cmd = &pp->ipdu.async;
debug_called(8);
sdebug(3, "asyncevent=0x%x asyncVCode=0x%0x", cmd->asyncEvent, cmd->asyncVCode);
switch(cmd->asyncEvent) {
case 0: // check status ...
break;
case 1: // target request logout
isc_stop_receiver(sp); // XXX: temporary solution
break;
case 2: // target indicates it wants to drop connection
isc_stop_receiver(sp); // XXX: temporary solution
break;
case 3: // target indicates it will drop all connections.
isc_stop_receiver(sp); // XXX: temporary solution
break;
case 4: // target request parameter negotiation
break;
default:
break;
}
}
void
iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
{
union ccb *ccb = opq->ccb;
//reject_t *reject = &pq->pdu.ipdu.reject;
debug_called(8);
//XXX: check RFC 10.17.1 (page 176)
ccb->ccb_h.status = CAM_REQ_ABORTED;
xpt_done(ccb);
pdu_free(sp->isc, opq);
}
/*
| deal with lun
*/
static int
dwl(isc_session_t *sp, int lun, u_char *lp)
{
debug_called(8);
sdebug(4, "lun=%d", lun);
/*
| mapping LUN to iSCSI LUN
| check the SAM-2 specs
| hint: maxLUNS is a small number, cam's LUN is 32bits
| iSCSI is 64bits, scsi is ?
*/
// XXX: check if this will pass the endian test
if(lun < 256) {
lp[0] = 0;
lp[1] = lun;
} else
if(lun < 16384) {
lp[0] = (1 << 5) | ((lun >> 8) & 0x3f);
lp[1] = lun & 0xff;
}
else {
xdebug("lun %d: is unsupported!", lun);
return -1;
}
return 0;
}
/*
| encapsulate the scsi command and
*/
int
scsi_encap(struct cam_sim *sim, union ccb *ccb)
{
isc_session_t *sp = cam_sim_softc(sim);
struct ccb_scsiio *csio = &ccb->csio;
struct ccb_hdr *ccb_h = &ccb->ccb_h;
pduq_t *pq;
scsi_req_t *cmd;
debug_called(8);
debug(4, "ccb->sp=%p", ccb_h->spriv_ptr0);
sp = ccb_h->spriv_ptr0;
if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
debug(2, "ccb->sp=%p", ccb_h->spriv_ptr0);
sdebug(1, "pdu_alloc failed sc->npdu_max=%d npdu_alloc=%d",
sp->isc->npdu_max, sp->isc->npdu_alloc);
while((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) {
sdebug(2, "waiting...");
pause("isc_encap", 5*hz);
}
}
cmd = &pq->pdu.ipdu.scsi_req;
cmd->opcode = ISCSI_SCSI_CMD;
cmd->F = 1;
#if 0
// this breaks at least Isilon's iscsi target.
/*
| map tag option, default is UNTAGGED
*/
switch(csio->tag_action) {
case MSG_SIMPLE_Q_TAG: cmd->attr = iSCSI_TASK_SIMPLE; break;
case MSG_HEAD_OF_Q_TAG: cmd->attr = iSCSI_TASK_HOFQ; break;
case MSG_ORDERED_Q_TAG: cmd->attr = iSCSI_TASK_ORDER; break;
case MSG_ACA_TASK: cmd->attr = iSCSI_TASK_ACA; break;
}
#else
cmd->attr = iSCSI_TASK_SIMPLE;
#endif
dwl(sp, ccb_h->target_lun, (u_char *)&cmd->lun);
if((ccb_h->flags & CAM_CDB_POINTER) != 0) {
if((ccb_h->flags & CAM_CDB_PHYS) == 0) {
if(csio->cdb_len > 16) {
sdebug(3, "oversize cdb %d > 16", csio->cdb_len);
goto invalid;
}
}
else {
sdebug(3, "not phys");
goto invalid;
}
}
if(csio->cdb_len > sizeof(cmd->cdb))
xdebug("guevalt! %d > %ld", csio->cdb_len, (long)sizeof(cmd->cdb));
memcpy(cmd->cdb,
ccb_h->flags & CAM_CDB_POINTER? csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes,
csio->cdb_len);
cmd->W = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT;
cmd->R = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN;
cmd->edtlen = htonl(csio->dxfer_len);
pq->ccb = ccb;
/*
| place it in the out queue
*/
if(isc_qout(sp, pq) == 0)
return 1;
invalid:
ccb->ccb_h.status = CAM_REQ_INVALID;
pdu_free(sp->isc, pq);
return 0;
}
int
scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
{
union ccb *ccb = opq->ccb;
struct ccb_scsiio *csio = &ccb->csio;
pdu_t *opp = &opq->pdu;
bhs_t *bhp = &opp->ipdu.bhs;
debug_called(8);
sdebug(6, "pq=%p opq=%p bhp->opcode=0x%x len=%d",
pq, opq, bhp->opcode, pq->pdu.ds_len);
if(ccb == NULL) {
sdebug(1, "itt=0x%x pq=%p opq=%p bhp->opcode=0x%x len=%d",
ntohl(pq->pdu.ipdu.bhs.itt),
pq, opq, bhp->opcode, pq->pdu.ds_len);
xdebug("%d] ccb == NULL!", sp->sid);
return 0;
}
if(pq->pdu.ds_len != 0) {
switch(bhp->opcode) {
case ISCSI_SCSI_CMD: {
scsi_req_t *cmd = &opp->ipdu.scsi_req;
sdebug(5, "itt=0x%x opcode=%x R=%d",
ntohl(pq->pdu.ipdu.bhs.itt),
pq->pdu.ipdu.bhs.opcode, cmd->R);
switch(pq->pdu.ipdu.bhs.opcode) {
case ISCSI_READ_DATA: // SCSI Data in
{
caddr_t bp = NULL; // = mtod(pq->mp, caddr_t);
data_in_t *rcmd = &pq->pdu.ipdu.data_in;
if(cmd->R) {
sdebug(5, "copy to=%p from=%p l1=%d l2=%d mp@%p",
csio->data_ptr, bp? mtod(pq->mp, caddr_t): 0,
ntohl(cmd->edtlen), pq->pdu.ds_len, pq->mp);
if(ntohl(cmd->edtlen) >= pq->pdu.ds_len) {
int offset, len = pq->pdu.ds_len;
if(pq->mp != NULL) {
caddr_t dp;
offset = ntohl(rcmd->bo);
dp = csio->data_ptr + offset;
i_mbufcopy(pq->mp, dp, len);
}
}
else {
xdebug("edtlen=%d < ds_len=%d",
ntohl(cmd->edtlen), pq->pdu.ds_len);
}
}
if(rcmd->S) {
/*
| contains also the SCSI Status
*/
_scsi_done(sp, 0, rcmd->status, opq->ccb, NULL);
return 0;
} else
return 1;
}
break;
}
}
default:
sdebug(3, "opcode=%02x", bhp->opcode);
break;
}
}
/*
| XXX: error ...
*/
return 1;
}

View file

@ -1,571 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
| $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
*/
#include <sys/lock.h>
#include <sys/mutex.h>
#define ISCSI_MAX_LUNS 128 // don't touch this
#if ISCSI_MAX_LUNS > 8
/*
| for this to work
| sysctl kern.cam.cam_srch_hi=1
*/
#endif
#ifndef ISCSI_INITIATOR_DEBUG
#define ISCSI_INITIATOR_DEBUG 1
#endif
#ifdef ISCSI_INITIATOR_DEBUG
extern int iscsi_debug;
#define debug(level, fmt, args...) do {if(level <= iscsi_debug)\
printf("%s: " fmt "\n", __func__ , ##args);} while(0)
#define sdebug(level, fmt, args...) do {if(level <= iscsi_debug)\
printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0)
#define debug_called(level) do {if(level <= iscsi_debug)\
printf("%s: called\n", __func__);} while(0)
#else
#define debug(level, fmt, args...)
#define debug_called(level)
#define sdebug(level, fmt, args...)
#endif /* ISCSI_INITIATOR_DEBUG */
#define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args)
#define MAX_SESSIONS ISCSI_MAX_TARGETS
#define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
typedef uint32_t digest_t(const void *, int len, uint32_t ocrc);
MALLOC_DECLARE(M_ISCSI);
MALLOC_DECLARE(M_ISCSIBUF);
#define ISOK2DIG(dig, pp) ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
#ifndef BIT
#define BIT(n) (1 <<(n))
#endif
#define ISC_SM_RUN BIT(0)
#define ISC_SM_RUNNING BIT(1)
#define ISC_LINK_UP BIT(2)
#define ISC_CON_RUN BIT(3)
#define ISC_CON_RUNNING BIT(4)
#define ISC_KILL BIT(5)
#define ISC_OQNOTEMPTY BIT(6)
#define ISC_OWAITING BIT(7)
#define ISC_FFPHASE BIT(8)
#define ISC_CAMDEVS BIT(9)
#define ISC_SCANWAIT BIT(10)
#define ISC_MEMWAIT BIT(11)
#define ISC_SIGNALED BIT(12)
#define ISC_HOLD BIT(15)
#define ISC_HOLDED BIT(16)
#define ISC_SHUTDOWN BIT(31)
/*
| some stats
*/
struct i_stats {
int npdu; // number of pdus malloc'ed.
int nrecv; // unprocessed received pdus
int nsent; // sent pdus
int nrsp, max_rsp;
int nrsv, max_rsv;
int ncsnd, max_csnd;
int nisnd, max_isnd;
int nwsnd, max_wsnd;
int nhld, max_hld;
struct bintime t_sent;
struct bintime t_recv;
};
/*
| one per 'session'
*/
typedef TAILQ_HEAD(, pduq) queue_t;
typedef struct isc_session {
TAILQ_ENTRY(isc_session) sp_link;
int flags;
struct cdev *dev;
struct socket *soc;
struct file *fp;
struct thread *td;
struct proc *proc; // the userland process
int signal;
struct proc *soc_proc;
struct proc *stp; // the sm thread
struct isc_softc *isc;
digest_t *hdrDigest; // the digest alg. if any
digest_t *dataDigest; // the digest alg. if any
int sid; // Session ID
sn_t sn; // sequence number stuff;
int cws; // current window size
int target_nluns; // this and target_lun are
// hopefully temporal till I
// figure out a better way.
int target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
struct mtx rsp_mtx;
struct mtx rsv_mtx;
struct mtx snd_mtx;
struct mtx hld_mtx;
struct mtx io_mtx;
queue_t rsp;
queue_t rsv;
queue_t csnd;
queue_t isnd;
queue_t wsnd;
queue_t hld;
isc_opt_t opt; // negotiable values
struct i_stats stats;
bhs_t bhs;
struct uio uio;
struct iovec iov;
/*
| cam stuff
*/
struct cam_sim *cam_sim;
struct cam_path *cam_path;
struct mtx cam_mtx;
/*
| sysctl stuff
*/
struct sysctl_ctx_list clist;
struct sysctl_oid *oid;
int douio; //XXX: turn on/off uio on read
} isc_session_t;
typedef struct pduq {
TAILQ_ENTRY(pduq) pq_link;
caddr_t buf;
u_int len; // the total length of the pdu
pdu_t pdu;
union ccb *ccb;
struct uio uio;
struct iovec iov[5]; // XXX: careful ...
struct mbuf *mp;
struct bintime ts;
queue_t *pduq;
} pduq_t;
/*
*/
struct isc_softc {
struct mtx isc_mtx;
TAILQ_HEAD(,isc_session) isc_sess;
int nsess;
struct cdev *dev;
char isid[6]; // Initiator Session ID (48 bits)
struct unrhdr *unit;
struct sx unit_sx;
uma_zone_t pdu_zone; // pool of free pdu's
TAILQ_HEAD(,pduq) freepdu;
#ifdef ISCSI_INITIATOR_DEBUG
int npdu_alloc, npdu_max; // for instrumentation
#endif
#ifdef DO_EVENTHANDLER
eventhandler_tag eh;
#endif
/*
| sysctl stuff
*/
struct sysctl_ctx_list clist;
struct sysctl_oid *oid;
};
#ifdef ISCSI_INITIATOR_DEBUG
extern struct mtx iscsi_dbg_mtx;
#endif
void isc_start_receiver(isc_session_t *sp);
void isc_stop_receiver(isc_session_t *sp);
int isc_sendPDU(isc_session_t *sp, pduq_t *pq);
int isc_qout(isc_session_t *sp, pduq_t *pq);
int i_prepPDU(isc_session_t *sp, pduq_t *pq);
int ism_fullfeature(struct cdev *dev, int flag);
int i_pdu_flush(isc_session_t *sc);
int i_setopt(isc_session_t *sp, isc_opt_t *opt);
void i_freeopt(isc_opt_t *opt);
int ic_init(isc_session_t *sp);
void ic_destroy(isc_session_t *sp);
void ic_lost_target(isc_session_t *sp, int target);
int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp);
void ism_recv(isc_session_t *sp, pduq_t *pq);
int ism_start(isc_session_t *sp);
void ism_restart(isc_session_t *sp);
void ism_stop(isc_session_t *sp);
int scsi_encap(struct cam_sim *sim, union ccb *ccb);
int scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
void iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
void iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
void iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq);
void iscsi_async(isc_session_t *sp, pduq_t *pq);
void iscsi_cleanup(isc_session_t *sp);
int iscsi_requeue(isc_session_t *sp);
// Serial Number Arithmetic
#define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1
#define SNA_GT(i1, i2) ((i1 != i2) && (\
(i1 < i2 && i2 - i1 > _MAXINCR) ||\
(i1 > i2 && i1 - i2 < _MAXINCR))?1: 0)
/*
| inlines
*/
static __inline pduq_t *
pdu_alloc(struct isc_softc *isc, int wait)
{
pduq_t *pq;
pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
if(pq == NULL) {
debug(7, "out of mem");
return NULL;
}
#ifdef ISCSI_INITIATOR_DEBUG
mtx_lock(&iscsi_dbg_mtx);
isc->npdu_alloc++;
if(isc->npdu_alloc > isc->npdu_max)
isc->npdu_max = isc->npdu_alloc;
mtx_unlock(&iscsi_dbg_mtx);
#endif
memset(pq, 0, sizeof(pduq_t));
return pq;
}
static __inline void
pdu_free(struct isc_softc *isc, pduq_t *pq)
{
if(pq->mp)
m_freem(pq->mp);
#ifdef NO_USE_MBUF
if(pq->buf != NULL)
free(pq->buf, M_ISCSIBUF);
#endif
uma_zfree(isc->pdu_zone, pq);
#ifdef ISCSI_INITIATOR_DEBUG
mtx_lock(&iscsi_dbg_mtx);
isc->npdu_alloc--;
mtx_unlock(&iscsi_dbg_mtx);
#endif
}
static __inline void
i_nqueue_rsp(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->rsp_mtx);
if(++sp->stats.nrsp > sp->stats.max_rsp)
sp->stats.max_rsp = sp->stats.nrsp;
TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link);
mtx_unlock(&sp->rsp_mtx);
}
static __inline pduq_t *
i_dqueue_rsp(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->rsp_mtx);
if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) {
sp->stats.nrsp--;
TAILQ_REMOVE(&sp->rsp, pq, pq_link);
}
mtx_unlock(&sp->rsp_mtx);
return pq;
}
static __inline void
i_nqueue_rsv(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->rsv_mtx);
if(++sp->stats.nrsv > sp->stats.max_rsv)
sp->stats.max_rsv = sp->stats.nrsv;
TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link);
mtx_unlock(&sp->rsv_mtx);
}
static __inline pduq_t *
i_dqueue_rsv(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->rsv_mtx);
if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) {
sp->stats.nrsv--;
TAILQ_REMOVE(&sp->rsv, pq, pq_link);
}
mtx_unlock(&sp->rsv_mtx);
return pq;
}
static __inline void
i_nqueue_csnd(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->snd_mtx);
if(++sp->stats.ncsnd > sp->stats.max_csnd)
sp->stats.max_csnd = sp->stats.ncsnd;
TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link);
mtx_unlock(&sp->snd_mtx);
}
static __inline pduq_t *
i_dqueue_csnd(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->snd_mtx);
if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
sp->stats.ncsnd--;
TAILQ_REMOVE(&sp->csnd, pq, pq_link);
}
mtx_unlock(&sp->snd_mtx);
return pq;
}
static __inline void
i_nqueue_isnd(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->snd_mtx);
if(++sp->stats.nisnd > sp->stats.max_isnd)
sp->stats.max_isnd = sp->stats.nisnd;
TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link);
mtx_unlock(&sp->snd_mtx);
}
static __inline pduq_t *
i_dqueue_isnd(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->snd_mtx);
if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
sp->stats.nisnd--;
TAILQ_REMOVE(&sp->isnd, pq, pq_link);
}
mtx_unlock(&sp->snd_mtx);
return pq;
}
static __inline void
i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->snd_mtx);
if(++sp->stats.nwsnd > sp->stats.max_wsnd)
sp->stats.max_wsnd = sp->stats.nwsnd;
TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link);
mtx_unlock(&sp->snd_mtx);
}
static __inline pduq_t *
i_dqueue_wsnd(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->snd_mtx);
if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
sp->stats.nwsnd--;
TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
}
mtx_unlock(&sp->snd_mtx);
return pq;
}
static __inline pduq_t *
i_dqueue_snd(isc_session_t *sp, int which)
{
pduq_t *pq;
pq = NULL;
mtx_lock(&sp->snd_mtx);
if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) {
sp->stats.nisnd--;
TAILQ_REMOVE(&sp->isnd, pq, pq_link);
pq->pduq = &sp->isnd; // remember where you came from
} else
if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) {
sp->stats.nwsnd--;
TAILQ_REMOVE(&sp->wsnd, pq, pq_link);
pq->pduq = &sp->wsnd; // remember where you came from
} else
if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) {
sp->stats.ncsnd--;
TAILQ_REMOVE(&sp->csnd, pq, pq_link);
pq->pduq = &sp->csnd; // remember where you came from
}
mtx_unlock(&sp->snd_mtx);
return pq;
}
static __inline void
i_rqueue_pdu(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->snd_mtx);
KASSERT(pq->pduq != NULL, ("pq->pduq is NULL"));
TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link);
mtx_unlock(&sp->snd_mtx);
}
/*
| Waiting for ACK (or something :-)
*/
static __inline void
i_nqueue_hld(isc_session_t *sp, pduq_t *pq)
{
getbintime(&pq->ts);
mtx_lock(&sp->hld_mtx);
if(++sp->stats.nhld > sp->stats.max_hld)
sp->stats.max_hld = sp->stats.nhld;
TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link);
mtx_unlock(&sp->hld_mtx);
return;
}
static __inline void
i_remove_hld(isc_session_t *sp, pduq_t *pq)
{
mtx_lock(&sp->hld_mtx);
sp->stats.nhld--;
TAILQ_REMOVE(&sp->hld, pq, pq_link);
mtx_unlock(&sp->hld_mtx);
}
static __inline pduq_t *
i_dqueue_hld(isc_session_t *sp)
{
pduq_t *pq;
mtx_lock(&sp->hld_mtx);
if((pq = TAILQ_FIRST(&sp->hld)) != NULL) {
sp->stats.nhld--;
TAILQ_REMOVE(&sp->hld, pq, pq_link);
}
mtx_unlock(&sp->hld_mtx);
return pq;
}
static __inline pduq_t *
i_search_hld(isc_session_t *sp, int itt, int keep)
{
pduq_t *pq, *tmp;
pq = NULL;
mtx_lock(&sp->hld_mtx);
TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
if(pq->pdu.ipdu.bhs.itt == itt) {
if(!keep) {
sp->stats.nhld--;
TAILQ_REMOVE(&sp->hld, pq, pq_link);
}
break;
}
}
mtx_unlock(&sp->hld_mtx);
return pq;
}
static __inline void
i_acked_hld(isc_session_t *sp, pdu_t *op)
{
pduq_t *pq, *tmp;
u_int exp = sp->sn.expCmd;
pq = NULL;
mtx_lock(&sp->hld_mtx);
TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) {
if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt)
|| (pq->ccb == NULL
&& (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA)
&& SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) {
sp->stats.nhld--;
TAILQ_REMOVE(&sp->hld, pq, pq_link);
pdu_free(sp->isc, pq);
}
}
mtx_unlock(&sp->hld_mtx);
}
static __inline void
i_mbufcopy(struct mbuf *mp, caddr_t dp, int len)
{
struct mbuf *m;
caddr_t bp;
for(m = mp; m != NULL; m = m->m_next) {
bp = mtod(m, caddr_t);
/*
| the pdu is word (4 octed) aligned
| so len <= packet
*/
memcpy(dp, bp, MIN(len, m->m_len));
dp += m->m_len;
len -= m->m_len;
if(len <= 0)
break;
}
}

View file

@ -487,7 +487,6 @@ _dpdk_lpm6= dpdk_lpm6
.if ${MK_ISCSI} != "no" || defined(ALL_MODULES)
SUBDIR+= cfiscsi
SUBDIR+= iscsi
SUBDIR+= iscsi_initiator
.endif
.if !empty(OPT_FDT)

View file

@ -1,14 +0,0 @@
# $FreeBSD$
.PATH: ${SRCTOP}/sys/dev/iscsi_initiator
KMOD=iscsi_initiator
SRCS= iscsi.h iscsivar.h
SRCS+= iscsi.c isc_cam.c isc_soc.c isc_sm.c isc_subr.c iscsi_subr.c
SRCS+= opt_cam.h opt_iscsi_initiator.h
SRCS+= bus_if.h device_if.h
# Debugging
# CFLAGS+= -DISCSI_INITIATOR_DEBUG=9
.include <bsd.kmod.mk>

View file

@ -88,7 +88,6 @@ DIRDEPS+= \
sbin/ipf/ippool \
sbin/ipf/libipf \
sbin/ipfw \
sbin/iscontrol \
sbin/kldconfig \
sbin/kldload \
sbin/kldstat \

View file

@ -2717,13 +2717,10 @@ OLD_FILES+=etc/rc.d/iscsictl
OLD_FILES+=etc/rc.d/iscsid
OLD_FILES+=rescue/iscsictl
OLD_FILES+=rescue/iscsid
OLD_FILES+=sbin/iscontrol
OLD_FILES+=usr/bin/iscsictl
OLD_FILES+=usr/sbin/iscsid
OLD_FILES+=usr/share/man/man4/iscsi.4.gz
OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz
OLD_FILES+=usr/share/man/man5/iscsi.conf.5.gz
OLD_FILES+=usr/share/man/man8/iscontrol.8.gz
OLD_FILES+=usr/share/man/man8/iscsictl.8.gz
OLD_FILES+=usr/share/man/man8/iscsid.8.gz
.endif

View file

@ -1,21 +0,0 @@
# Doxyfile 1.5.2
# $FreeBSD$
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "FreeBSD kernel iscsi_initiator device code"
OUTPUT_DIRECTORY = $(DOXYGEN_DEST_PATH)/dev_iscsi_initiator/
EXTRACT_ALL = YES # for undocumented src, no warnings enabled
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = $(DOXYGEN_SRC_PATH)/dev/iscsi_initiator/ \
$(NOTREVIEWED)
GENERATE_TAGFILE = dev_iscsi_initiator/dev_iscsi_initiator.tag
@INCLUDE_PATH = $(DOXYGEN_INCLUDE_PATH)
@INCLUDE = common-Doxyfile

View file

@ -35,9 +35,7 @@ The
.Nm
configuration file is used by the
.Xr iscsictl 8
and
.Xr iscontrol 8
utilities.
utility.
The general syntax is:
.Bf Li
.Bd -literal
@ -189,7 +187,6 @@ chaptest {
}
.Ed
.Sh SEE ALSO
.Xr iscontrol 8 ,
.Xr iscsictl 8
.\"Sh HISTORY
.\"Sh AUTHORS

View file

@ -169,21 +169,6 @@ Note that in order for the iSCSI initiator to be able to connect to a target,
the
.Xr iscsid 8
daemon must be running.
.Pp
Also note that
.Fx
currently supports two different initiators: the old one,
.Xr iscsi_initiator 4 ,
with its control utility
.Xr iscontrol 8 ,
and the new one,
.Xr iscsi 4 ,
with
.Nm
and
.Xr iscsid 8 .
The only thing the two have in common is the configuration file,
.Xr iscsi.conf 5 .
.Sh FILES
.Bl -tag -width ".Pa /etc/iscsi.conf" -compact
.It Pa /etc/iscsi.conf