- Add full support for header / data digests.

- Increase target limit from 4 to 64; this limit will be removed entirely
  at a later time.
- Improve recovery from lost network connections.
- Fix some potential deadlocks and a serious memory leak.
- Fix incorrect use of MH_ALIGN (instead of M_ALIGN), which makes no
  practical difference, but triggers a KASSERT with INVARIANTS.
- Fix some warnings in iscontrol(8) and improve the man page somewhat.

Submitted by:	Daniel Braniss <danny@cs.huji.ac.il>
Sponsored by:	Dansk Scanning A/S, Data Robotics Inc.
This commit is contained in:
Dag-Erling Smørgrav 2010-08-09 12:36:36 +00:00
parent 1dd592007a
commit c201d4532c
20 changed files with 940 additions and 1054 deletions

@ -4,9 +4,10 @@ SRCS= iscontrol.c pdu.c fsm.c config.c login.c auth_subr.c misc.c
PROG= iscontrol
DPADD= ${LIBCAM} ${LIBMD}
LDADD= -lcam -lmd
S= ${.CURDIR}/../../sys
WARNS?= 2
CFLAGS += -I${.CURDIR}/../../sys/dev/iscsi/initiator
WARNS?= 3
CFLAGS += -I$S
#CFLAGS += -g -DDEBUG
MAN= iscsi.conf.5 iscontrol.8

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$");
#include <md5.h>
#include <sha.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
static int
@ -152,7 +152,7 @@ chapDigest(char *ap, char id, char *cp, char *chapSecret)
}
char *
genChapChallenge(char *encoding, int len)
genChapChallenge(char *encoding, uint len)
{
int fd;
unsigned char tmp[1024];

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <camlib.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
/*
@ -94,6 +94,11 @@ __FBSDID("$FreeBSD$");
#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}
@ -145,7 +150,7 @@ textkey_t keyMap[] = {
_E(U_LO, S_SW, sessionType),
{0}
_E(0, 0, end)
};
#define _OPT_INT(w) strtol((char *)w, NULL, 0)
@ -154,7 +159,7 @@ textkey_t keyMap[] = {
static __inline int
_OPT_BOOL(char *w)
{
if(isalpha(*w))
if(isalpha((unsigned char)*w))
return strcasecmp(w, "TRUE") == 0;
else
return _OPT_INT(w);
@ -244,12 +249,12 @@ getConfig(FILE *fd, char *key, char **Ar, int *nargs)
len = 0;
state = 0;
while((lp = getline(fd)) != NULL) {
for(; isspace(*lp); lp++)
for(; isspace((unsigned char)*lp); lp++)
;
switch(state) {
case 0:
if((p = strchr(lp, '{')) != NULL) {
while((--p > lp) && *p && isspace(*p));
while((--p > lp) && *p && isspace((unsigned char)*p));
n = p - lp;
if(len && strncmp(lp, key, MAX(n, len)) == 0)
state = 2;
@ -272,7 +277,7 @@ getConfig(FILE *fd, char *key, char **Ar, int *nargs)
}
for(p = &lp[strlen(lp)-1]; isspace(*p); p--)
for(p = &lp[strlen(lp)-1]; isspace((unsigned char)*p); p--)
*p = 0;
if((*nargs)-- > 0)
*ar++ = strdup(lp);
@ -351,9 +356,9 @@ parseArgs(int nargs, char **args, isc_opt_t *op)
continue;
*p = 0;
v = p + 1;
while(isspace(*--p))
while(isspace((unsigned char)*--p))
*p = 0;
while(isspace(*v))
while(isspace((unsigned char)*v))
v++;
if((tk = keyLookup(*ar)) == NULL)
continue;

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <camlib.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
typedef enum {
@ -99,26 +99,26 @@ tcpConnect(isess_t *sess)
#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;
// 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++;
}
@ -140,13 +140,13 @@ tcpConnect(isess_t *sess)
if (soc == -1)
continue;
// from Patrick.Guelat@imp.ch:
// iscontrol can be called without waiting for the socket entry to time out
val = 1;
// 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));
}
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;
@ -196,7 +196,7 @@ tcpConnect(isess_t *sess)
}
sess->flags |= SESS_CONNECTED;
return T1;
}
}
fprintf(stderr, "errno=%d\n", sv_errno);
perror("connect");
@ -289,7 +289,7 @@ startSession(isess_t *sess)
// XXX: this has to go
size_t n;
n = sizeof(sess->isid);
if(sysctlbyname("net.iscsi.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0)
if(sysctlbyname("net.iscsi_initiator.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0)
perror("sysctlbyname");
}
if(ioctl(fd, ISCSISETSES, &n)) {
@ -343,29 +343,29 @@ trap(int sig)
}
}
static void
static int
doCAM(isess_t *sess)
{
char pathstr[1024];
union ccb *ccb;
int i;
int i, n;
if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) {
syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno);
return;
return 0;
}
debug(2, "nluns=%d", sess->cam.target_nluns);
debug(1, "nluns=%d", sess->cam.target_nluns);
/*
| for now will do this for each lun ...
*/
for(i = 0; i < sess->cam.target_nluns; i++) {
for(n = i = 0; i < sess->cam.target_nluns; i++) {
debug(2, "CAM path_id=%d target_id=%d target_lun=%d",
sess->cam.path_id, sess->cam.target_id, sess->cam.target_lun[i]);
sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id,
sess->cam.target_lun[i], O_RDWR, NULL);
i, O_RDWR, NULL);
if(sess->camdev == NULL) {
syslog(LOG_WARNING, "%s", cam_errbuf);
//syslog(LOG_WARNING, "%s", cam_errbuf);
debug(3, "%s", cam_errbuf);
continue;
}
@ -378,20 +378,21 @@ doCAM(isess_t *sess)
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)
syslog(LOG_WARNING, "%s", cam_errbuf);
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
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
@ -417,7 +418,15 @@ supervise(isess_t *sess)
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");
@ -426,7 +435,11 @@ supervise(isess_t *sess)
perror("ISCSISTART");
return -1;
}
doCAM(sess);
if(doCAM(sess) == 0) {
syslog(LOG_WARNING, "no device found");
ioctl(sess->fd, ISCSISTOP);
return T15;
}
}
else {
@ -449,7 +462,8 @@ supervise(isess_t *sess)
sess->flags |= SESS_FULLFEATURE;
sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT);
printf("iscontrol: supervise starting main loop\n");
if(vflag)
printf("iscontrol: supervise starting main loop\n");
/*
| the main loop - actually do nothing
| all the work is done inside the kernel
@ -468,14 +482,14 @@ supervise(isess_t *sess)
}
if(sess->flags & SESS_DISCONNECT) {
val = 0;
if(ioctl(sess->fd, ISCSISTOP, &val)) {
perror("ISCSISTOP");
}
sess->flags &= ~SESS_FULLFEATURE;
return T9;
}
else {
val = 0;
if(ioctl(sess->fd, ISCSISTOP, &val)) {
perror("ISCSISTOP");
}
sess->flags |= SESS_INITIALLOGIN1;
}
return T8;
@ -490,7 +504,7 @@ handledDiscoveryResp(isess_t *sess, pdu_t *pp)
debug_called(3);
len = pp->ds_len;
ptr = pp->ds;
ptr = pp->ds_addr;
while(len > 0) {
if(*ptr != 0)
printf("%s\n", ptr);
@ -579,8 +593,13 @@ doLogin(isess_t *sess)
static int
handleLogoutResp(isess_t *sess, pdu_t *pp)
{
if(sess->flags & SESS_DISCONNECT)
if(sess->flags & SESS_DISCONNECT) {
int val = 0;
if(ioctl(sess->fd, ISCSISTOP, &val)) {
perror("ISCSISTOP");
}
return 0;
}
return T13;
}
@ -610,7 +629,7 @@ typedef enum {
S1, S2, /*S3,*/ S4, S5, S6, S7, S8
} state_t;
#if 0
/**
S1: FREE
S2: XPT_WAIT
S4: IN_LOGIN
@ -652,7 +671,7 @@ typedef enum {
| +-----\ /--->\ / T14 |
| ------- --+----+------+T17
+---------------------------+
#endif
*/
int
fsm(isc_opt_t *op)

@ -1,4 +1,4 @@
.\" Copyright (c) 2007-2008 Daniel Braniss <danny@cs.huji.ac.il>
.\" 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
@ -32,11 +32,12 @@
.Nd login/negotiator/control for an iSCSI initiator session
.Sh SYNOPSIS
.Nm
.Op Fl vd
.Op Fl dv
.Oo
.Op Fl c Ar file
.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
@ -57,26 +58,29 @@ It will terminate/logout the session
when a SIGHUP signal is received.
The flags are as follows:
.Bl -tag -width variable=value
.It Fl v
verbose mode.
.It Fl d
do a
.Em discovery session
and exit.
.It Fl c Ar file
a file containing configuration
.Em key-options ,
see
.Xr iscsi.conf 5
.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
.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
is the target's IP address or name
the target's IP address or name.
.It Fl v
verbose mode.
.It Ar variable Ns = Ns Ar value
see
.Xr iscsi.conf 5
@ -86,13 +90,13 @@ possible values.
.Sh EXAMPLES
.Dl iscontrol -dt myiscsitarget
.Pp
will start a
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
not need login/access permission, but a
.Em full session
certainly does.
.sp

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -53,15 +53,11 @@ __FBSDID("$FreeBSD$");
#include <time.h>
#include <camlib.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
#define USAGE "[-v] [-d] [-c config] [-n name] [-t target] "
#define OPTIONS "vdc:t:n:"
#ifndef DEBUG
//int vflag;
#endif
#define USAGE "[-v] [-d] [-c config] [-n name] [-t target] [-p pidfile]"
#define OPTIONS "vdc:t:n:p:"
token_t AuthMethods[] = {
{"None", NONE},
@ -70,14 +66,14 @@ token_t AuthMethods[] = {
{"SPKM2", SPKM2},
{"SRP", SRP},
{"CHAP", CHAP},
{0}
{0, 0}
};
token_t DigestMethods[] = {
{"None", 0},
{"CRC32", 1},
{"CRC32C", 1},
{0}
{0, 0}
};
u_char isid[6 + 6];
@ -128,7 +124,7 @@ int
main(int cc, char **vv)
{
int ch, disco;
char *pname, *p, *q, *ta, *kw;
char *pname, *pidfile, *p, *q, *ta, *kw;
isc_opt_t *op;
FILE *fd;
@ -141,6 +137,7 @@ main(int cc, char **vv)
kw = ta = 0;
disco = 0;
pidfile = NULL;
while((ch = getopt(cc, vv, OPTIONS)) != -1) {
switch(ch) {
@ -163,6 +160,9 @@ main(int cc, char **vv)
case 'n':
kw = optarg;
break;
case 'p':
pidfile = optarg;
break;
default:
badu:
fprintf(stderr, "Usage: %s %s\n", pname, USAGE);
@ -225,7 +225,7 @@ main(int cc, char **vv)
op->sessionType = "Discovery";
op->targetName = 0;
}
op->pidfile = pidfile;
fsm(op);
exit(0);

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -154,7 +154,7 @@ 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, int len);
char *genChapChallenge(char *encoding, uint len);
int str2bin(char *str, char **rsp);
char *bin2str(char *fmt, unsigned char *md, int blen);

@ -1,4 +1,4 @@
.\" Copyright (c) 2007-2008 Daniel Braniss <danny@cs.huji.ac.il>
.\" 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
@ -68,6 +68,7 @@ Only CRC32C is implemented.
Default is none.
.It Cm DataDigest
same as for HeaderDigest, but on the data part of the iSCSI PDU.
(not yet tested)
.It Cm MaxConnections
is the number of simultaneous connections per session,
currently only 1.

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -47,7 +47,7 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
static char *status_class1[] = {
@ -107,7 +107,7 @@ getkeyval(char *key, pdu_t *pp)
debug_called(3);
len = pp->ds_len;
ptr = (char *)pp->ds;
ptr = (char *)pp->ds_addr;
klen = strlen(key);
while(len > klen) {
if(strncmp(key, ptr, klen) == 0)
@ -163,7 +163,7 @@ processParams(isess_t *sess, pdu_t *pp)
debug_called(3);
len = pp->ds_len;
ptr = (char *)pp->ds;
ptr = (char *)pp->ds_addr;
while(len > 0) {
if(vflag > 1)
printf("got: len=%d %s\n", len, ptr);
@ -233,7 +233,7 @@ handleLoginResp(isess_t *sess, pdu_t *pp)
st_class = status >> 8;
if(status) {
int st_detail = status & 0xff;
uint st_detail = status & 0xff;
switch(st_class) {
case 1: // Redirect

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
static inline char
c2b(unsigned char c)
{

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <camlib.h>
#include "iscsi.h"
#include <dev/iscsi/initiator/iscsi.h>
#include "iscontrol.h"
static void pukeText(char *it, pdu_t *pp);
@ -85,7 +85,7 @@ sendPDU(isess_t *sess, pdu_t *pp, handler_t *hdlr)
int res;
pp->ahs_size = 8 * 1024;
if((pp->ahs = malloc(pp->ahs_size)) == NULL) {
if((pp->ahs_addr = malloc(pp->ahs_size)) == NULL) {
fprintf(stderr, "out of mem!");
return -1;
}
@ -126,16 +126,16 @@ addText(pdu_t *pp, char *fmt, ...)
if((pp->ds_len + len) > pp->ds_size) {
u_char *np;
np = realloc(pp->ds, pp->ds_size + len + FUDGE);
np = realloc(pp->ds_addr, pp->ds_size + len + FUDGE);
if(np == NULL) {
free(str);
//XXX: out of memory!
return -1;
}
pp->ds = np;
pp->ds_addr = np;
pp->ds_size += len + FUDGE;
}
memcpy(pp->ds + pp->ds_len, str, len);
memcpy(pp->ds_addr + pp->ds_len, str, len);
pp->ds_len += len;
free(str);
return len;
@ -145,12 +145,12 @@ void
freePDU(pdu_t *pp)
{
if(pp->ahs_size)
free(pp->ahs);
free(pp->ahs_addr);
if(pp->ds_size)
free(pp->ds);
free(pp->ds_addr);
bzero(&pp->ipdu, sizeof(union ipdu_u));
pp->ahs = NULL;
pp->ds = NULL;
pp->ahs_addr = NULL;
pp->ds_addr = NULL;
pp->ahs_size = 0;
pp->ds_size = pp->ds_len = 0;
}
@ -163,7 +163,7 @@ pukeText(char *it, pdu_t *pp)
size_t len, n;
len = pp->ds_len;
ptr = (char *)pp->ds;
ptr = (char *)pp->ds_addr;
cmd = pp->ipdu.bhs.opcode;
printf("%s: cmd=0x%x len=%d\n", it, cmd, (int)len);

@ -1,134 +0,0 @@
/*-
* Copyright (c) 2005 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: pdu.h,v 2.1 2006/11/12 08:06:51 danny Exp $
*/
/*
| keep in BIG endian order (network byte order).
*/
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;
/*
| Responses
*/
typedef struct logout_req {
char cmd; // 0x06
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;

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -24,7 +24,9 @@
* SUCH DAMAGE.
*
*/
/*
| $Id: isc_cam.c 998 2009-12-20 10:32:45Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -43,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@ -53,146 +56,34 @@ __FBSDID("$FreeBSD$");
#include <dev/iscsi/initiator/iscsi.h>
#include <dev/iscsi/initiator/iscsivar.h>
// XXX: untested/incomplete
void
ic_freeze(isc_session_t *sp)
{
debug_called(8);
#if 0
sdebug(2, "freezing path=%p", sp->cam_path == NULL? 0: sp->cam_path);
if((sp->cam_path != NULL) && !(sp->flags & ISC_FROZEN)) {
xpt_freeze_devq(sp->cam_path, 1);
}
#endif
sp->flags |= ISC_FROZEN;
}
// XXX: untested/incomplete
void
ic_release(isc_session_t *sp)
{
debug_called(8);
#if 0
sdebug(2, "release path=%p", sp->cam_path == NULL? 0: sp->cam_path);
if((sp->cam_path != NULL) && (sp->flags & ISC_FROZEN)) {
xpt_release_devq(sp->cam_path, 1, TRUE);
}
#endif
sp->flags &= ~ISC_FROZEN;
}
void
ic_lost_target(isc_session_t *sp, int target)
{
struct isc_softc *isp = sp->isc;
debug_called(8);
sdebug(2, "target=%d", target);
if(sp->cam_path != NULL) {
mtx_lock(&isp->cam_mtx);
xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL);
xpt_free_path(sp->cam_path);
mtx_unlock(&isp->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);
free(ccb, M_TEMP);
if(sp->flags & ISC_FFPWAIT) {
sp->flags &= ~ISC_FFPWAIT;
wakeup(sp);
}
}
static void
_scan_target(isc_session_t *sp, int target)
{
union ccb *ccb;
debug_called(8);
sdebug(2, "target=%d", target);
if((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO)) == NULL) {
xdebug("scan failed (can't allocate CCB)");
return;
}
CAM_LOCK(sp->isc);
xpt_setup_ccb(&ccb->ccb_h, sp->cam_path, 5/*priority (low)*/);
ccb->ccb_h.func_code = XPT_SCAN_BUS;
ccb->ccb_h.cbfcnp = _scan_callback;
ccb->crcn.flags = CAM_FLAG_NONE;
ccb->ccb_h.spriv_ptr0 = sp;
xpt_action(ccb);
CAM_UNLOCK(sp->isc);
}
int
ic_fullfeature(struct cdev *dev)
{
struct isc_softc *isp = dev->si_drv1;
isc_session_t *sp = (isc_session_t *)dev->si_drv2;
debug_called(8);
sdebug(3, "dev=%d sc=%p", dev2unit(dev), isp);
sp->flags &= ~ISC_FFPHASE;
sp->flags |= ISC_FFPWAIT;
CAM_LOCK(isp);
if(xpt_create_path(&sp->cam_path, xpt_periph, cam_sim_path(sp->isc->cam_sim),
sp->sid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xdebug("can't create cam path");
CAM_UNLOCK(isp);
return ENODEV; // XXX
}
CAM_UNLOCK(isp);
_scan_target(sp, sp->sid);
while(sp->flags & ISC_FFPWAIT)
tsleep(sp, PRIBIO, "ffp", 5*hz); // the timeout time should
// be configurable
if(sp->target_nluns > 0) {
sp->flags |= ISC_FFPHASE;
return 0;
}
return ENODEV;
}
static void
_inq(struct cam_sim *sim, union ccb *ccb, int maxluns)
_inq(struct cam_sim *sim, union ccb *ccb)
{
struct ccb_pathinq *cpi = &ccb->cpi;
isc_session_t *sp = cam_sim_softc(sim);
debug_called(4);
debug_called(8);
debug(3, "sid=%d target=%d lun=%d", sp->sid, ccb->ccb_h.target_id, 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 = ISCSI_MAX_TARGETS - 1;
cpi->max_target = 0; //ISCSI_MAX_TARGETS - 1;
cpi->initiator_id = ISCSI_MAX_TARGETS;
cpi->max_lun = maxluns;
cpi->max_lun = sp->opt.maxluns - 1;
cpi->bus_id = cam_sim_bus(sim);
cpi->base_transfer_speed = 3300;
cpi->base_transfer_speed = 3300; // 40000; // XXX:
strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
strncpy(cpi->hba_vid, "iSCSI", HBA_IDLEN);
strncpy(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;
cpi->ccb_h.status = CAM_REQ_CMP;
#endif
}
static __inline int
@ -203,77 +94,111 @@ _scsi_encap(struct cam_sim *sim, union ccb *ccb)
#if __FreeBSD_version < 700000
ret = scsi_encap(sim, ccb);
#else
struct isc_softc *isp = (struct isc_softc *)cam_sim_softc(sim);
isc_session_t *sp = cam_sim_softc(sim);
mtx_unlock(&isp->cam_mtx);
mtx_unlock(&sp->cam_mtx);
ret = scsi_encap(sim, ccb);
mtx_lock(&isp->cam_mtx);
mtx_lock(&sp->cam_mtx);
#endif
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);
free(ccb, M_TEMP);
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);
if((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO)) == NULL) {
xdebug("scan failed (can't allocate CCB)");
return ENOMEM; // XXX
}
sp->flags &= ~ISC_CAMDEVS;
sp->flags |= ISC_SCANWAIT;
CAM_LOCK(sp);
if(xpt_create_path(&sp->cam_path, xpt_periph, cam_sim_path(sp->cam_sim),
0, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xdebug("can't create cam path");
CAM_UNLOCK(sp);
free(ccb, M_TEMP);
return ENODEV; // XXX
}
xpt_setup_ccb(&ccb->ccb_h, sp->cam_path, 5/*priority (low)*/);
ccb->ccb_h.func_code = XPT_SCAN_BUS;
ccb->ccb_h.cbfcnp = scan_callback;
ccb->crcn.flags = CAM_FLAG_NONE;
ccb->ccb_h.spriv_ptr0 = sp;
xpt_action(ccb);
CAM_UNLOCK(sp);
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;
struct isc_softc *isp = (struct isc_softc *)cam_sim_softc(sim);
isc_session_t *sp;
debug_called(8);
if((ccb_h->target_id != CAM_TARGET_WILDCARD) && (ccb_h->target_id < MAX_SESSIONS))
sp = isp->sessions[ccb_h->target_id];
else
sp = NULL;
ccb_h->spriv_ptr0 = sp;
debug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%d retry_count=%d timeout=%d",
sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%d retry_count=%d timeout=%d",
ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status,
ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
ccb->ccb_h.retry_count, ccb_h->timeout);
/*
| first quick check
*/
if(sp == NULL) {
xdebug("sp == NULL! cannot happen");
return;
}
switch(ccb_h->func_code) {
default:
// XXX: maybe check something else?
break;
case XPT_SCSI_IO:
case XPT_RESET_DEV:
case XPT_GET_TRAN_SETTINGS:
case XPT_SET_TRAN_SETTINGS:
case XPT_CALC_GEOMETRY:
if(sp == NULL) {
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
#if __FreeBSD_version < 700000
XPT_DONE(isp, ccb);
#else
xpt_done(ccb);
#endif
return;
}
break;
case XPT_PATH_INQ:
case XPT_NOOP:
if(sp == NULL && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
#if __FreeBSD_version < 700000
XPT_DONE(isp, ccb);
#else
xpt_done(ccb);
#endif
debug(4, "status = CAM_DEV_NOT_THERE");
return;
}
}
switch(ccb_h->func_code) {
case XPT_PATH_INQ:
_inq(sim, ccb, (sp? sp->opt.maxluns: ISCSI_MAX_LUNS) - 1);
_inq(sim, ccb);
break;
case XPT_RESET_BUS: // (can just be a stub that does nothing and completes)
@ -310,14 +235,35 @@ ic_action(struct cam_sim *sim, union ccb *ccb)
struct ccb_calc_geometry *ccg;
ccg = &ccb->ccg;
debug(6, "XPT_CALC_GEOMETRY vsize=%jd bsize=%d", ccg->volume_size, ccg->block_size);
debug(4, "sid=%d target=%d lun=%d XPT_CALC_GEOMETRY vsize=%jd bsize=%d",
sp->sid, ccb->ccb_h.target_id, 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 appropiate? */
break;
} else
}
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;
}
@ -327,7 +273,7 @@ ic_action(struct cam_sim *sim, union ccb *ccb)
break;
}
#if __FreeBSD_version < 700000
XPT_DONE(isp, ccb);
XPT_DONE(sp, ccb);
#else
xpt_done(ccb);
#endif
@ -337,102 +283,102 @@ ic_action(struct cam_sim *sim, union ccb *ccb)
static void
ic_poll(struct cam_sim *sim)
{
debug_called(8);
debug_called(4);
}
int
ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp)
{
int i;
debug_called(8);
if(sp && sp->isc->cam_sim) {
cp->path_id = cam_sim_path(sp->isc->cam_sim);
cp->target_id = sp->sid;
cp->target_nluns = sp->target_nluns; // XXX: -1?
for(i = 0; i < cp->target_nluns; i++)
cp->target_lun[i] = sp->target_lun[i];
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(struct isc_softc *isp)
ic_destroy(isc_session_t *sp )
{
debug_called(8);
CAM_LOCK(isp); // can't harm :-)
if(sp->cam_path != NULL) {
sdebug(2, "name=%s unit=%d",
cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim));
CAM_LOCK(sp);
#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*/);
xpt_async(AC_LOST_DEVICE, isp->cam_path, NULL);
xpt_free_path(isp->cam_path);
xpt_bus_deregister(cam_sim_path(isp->cam_sim));
cam_sim_free(isp->cam_sim, TRUE /*free_devq*/);
CAM_UNLOCK(isp);
CAM_UNLOCK(sp);
sdebug(2, "done");
}
}
int
ic_init(struct isc_softc *isp)
ic_init(isc_session_t *sp)
{
struct cam_sim *sim;
struct cam_devq *devq;
struct cam_path *path;
debug_called(8);
if((devq = cam_simq_alloc(256)) == NULL)
return ENOMEM;
#if __FreeBSD_version >= 700000
mtx_init(&isp->cam_mtx, "isc-cam", NULL, MTX_DEF);
mtx_init(&sp->cam_mtx, "isc-cam", NULL, MTX_DEF);
#else
isp->cam_mtx = Giant;
#endif
sim = cam_sim_alloc(ic_action, ic_poll,
"iscsi", isp, 0/*unit*/,
sim = cam_sim_alloc(ic_action,
ic_poll,
"iscsi",
sp,
sp->sid, // unit
#if __FreeBSD_version >= 700000
&isp->cam_mtx,
&sp->cam_mtx,
#endif
1/*max_dev_transactions*/,
100/*max_tagged_dev_transactions*/,
1, // max_dev_transactions
0, // max_tagged_dev_transactions
devq);
if(sim == NULL) {
cam_simq_free(devq);
#if __FreeBSD_version >= 700000
mtx_destroy(&isp->cam_mtx);
mtx_destroy(&sp->cam_mtx);
#endif
return ENXIO;
}
CAM_LOCK(isp);
CAM_LOCK(sp);
if(xpt_bus_register(sim,
#if __FreeBSD_version >= 700000
NULL,
#endif
0/*bus_number*/) != CAM_SUCCESS)
goto bad;
0/*bus_number*/) != CAM_SUCCESS) {
if(xpt_create_path(&path, xpt_periph, cam_sim_path(sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path(sim));
goto bad;
}
CAM_UNLOCK(isp);
isp->cam_sim = sim;
isp->cam_path = path;
debug(2, "cam subsystem initialized"); // XXX: add dev ...
debug(4, "sim=%p path=%p", sim, path);
return 0;
bad:
cam_sim_free(sim, /*free_devq*/TRUE);
CAM_UNLOCK(isp);
cam_sim_free(sim, /*free_devq*/TRUE);
CAM_UNLOCK(sp);
#if __FreeBSD_version >= 700000
mtx_destroy(&isp->cam_mtx);
mtx_destroy(&sp->cam_mtx);
#endif
return ENXIO;
return ENXIO;
}
sp->cam_sim = sim;
CAM_UNLOCK(sp);
sdebug(1, "cam subsystem initialized");
ic_scan(sp);
return 0;
}

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -26,7 +26,7 @@
*/
/*
| iSCSI - Session Manager
| $Id: isc_sm.c,v 1.30 2007/04/22 09:53:09 danny Exp danny $
| $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $
*/
#include <sys/cdefs.h>
@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <sys/mbuf.h>
#include <sys/bus.h>
#include <sys/sx.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@ -131,8 +132,10 @@ _scsi_rsp(isc_session_t *sp, pduq_t *pq)
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)
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));
@ -267,7 +270,7 @@ i_prepPDU(isc_session_t *sp, pduq_t *pq)
len += pp->ahs_len;
bhp->AHSLength = pp->ahs_len / 4;
}
if(sp->hdrDigest)
if(ISOK2DIG(sp->hdrDigest, pp))
len += 4;
if(pp->ds_len) {
n = pp->ds_len;
@ -283,7 +286,7 @@ i_prepPDU(isc_session_t *sp, pduq_t *pq)
n = 4 - (len & 03);
len += n;
}
if(sp->dataDigest)
if(ISOK2DIG(sp->dataDigest, pp))
len += 4;
}
@ -321,7 +324,7 @@ isc_qout(isc_session_t *sp, pduq_t *pq)
mtx_lock(&sp->io_mtx);
sp->flags |= ISC_OQNOTEMPTY;
if(sp->flags & ISC_OWAITING)
wakeup(&sp->flags);
wakeup(&sp->flags);
mtx_unlock(&sp->io_mtx);
return error;
@ -329,7 +332,7 @@ isc_qout(isc_session_t *sp, pduq_t *pq)
/*
| called when a fullPhase is restarted
*/
static void
void
ism_restart(isc_session_t *sp)
{
int lastcmd;
@ -348,30 +351,7 @@ ism_restart(isc_session_t *sp)
}
mtx_unlock(&sp->io_mtx);
sdebug(2, "restarted lastcmd=0x%x", lastcmd);
}
int
ism_fullfeature(struct cdev *dev, int flag)
{
isc_session_t *sp = (isc_session_t *)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
error = ic_fullfeature(dev);
break;
case 2: // restart
ism_restart(sp);
break;
}
return error;
sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd);
}
void
@ -384,26 +364,6 @@ ism_recv(isc_session_t *sp, pduq_t *pq)
bhs = &pq->pdu.ipdu.bhs;
statSN = ntohl(bhs->OpcodeSpecificFields[1]);
#if 0
{
/*
| this code is only for debugging.
*/
sn_t *sn = &sp->sn;
if(sp->cws == 0) {
if((sp->flags & ISC_STALLED) == 0) {
sdebug(4, "window closed: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.",
sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws);
sp->flags |= ISC_STALLED;
} else
if(sp->flags & ISC_STALLED) {
sdebug(4, "window opened: max=0x%x exp=0x%x opcode=0x%x cmd=0x%x cws=%d.",
sn->maxCmd, sn->expCmd, bhs->opcode, sn->cmd, sp->cws);
sp->flags &= ~ISC_STALLED;
}
}
}
#endif
#ifdef notyet
if(sp->sn.expCmd != sn->cmd) {
@ -454,7 +414,7 @@ ism_recv(isc_session_t *sp, pduq_t *pq)
break;
}
}
/*
| go through the out queues looking for work
| if either nothing to do, or window is closed
@ -465,11 +425,10 @@ proc_out(isc_session_t *sp)
{
sn_t *sn = &sp->sn;
pduq_t *pq;
int error, ndone;
int which;
int error, which;
debug_called(8);
error = ndone = 0;
error = 0;
while(sp->flags & ISC_LINK_UP) {
pdu_t *pp;
@ -508,7 +467,7 @@ proc_out(isc_session_t *sp)
sn->cmd++;
case ISCSI_WRITE_DATA:
bhs->ExpStSN = htonl(sn->stat);
bhs->ExpStSN = htonl(sn->stat + 1);
break;
default:
@ -523,19 +482,21 @@ proc_out(isc_session_t *sp)
bhs->opcode,
sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt);
if(pq->ccb)
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);
if((error = isc_sendPDU(sp, pq)) == 0) {
ndone++;
if(pq->ccb == NULL)
pdu_free(sp->isc, pq);
}
else {
xdebug("error=%d ndone=%d opcode=0x%x ccb=%p itt=%x",
error, ndone, bhs->opcode, pq->ccb, ntohl(bhs->itt));
if(pq->ccb)
i_remove_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;
@ -546,12 +507,12 @@ proc_out(isc_session_t *sp)
break;
default:
if(pq->ccb) {
if(pq->ccb) {
xdebug("back to cam");
pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
XPT_DONE(sp->isc, pq->ccb);
XPT_DONE(sp, pq->ccb);
pdu_free(sp->isc, pq);
}
}
else
xdebug("we lost it!");
}
@ -559,12 +520,12 @@ proc_out(isc_session_t *sp)
}
return error;
}
/*
| survives link breakdowns.
*/
static void
ism_proc(void *vp)
ism_out(void *vp)
{
isc_session_t *sp = (isc_session_t *)vp;
int error;
@ -580,8 +541,11 @@ ism_proc(void *vp)
sdebug(3, "error=%d", error);
}
}
mtx_lock(&sp->io_mtx);
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);
}
@ -589,7 +553,7 @@ ism_proc(void *vp)
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);
_nop_out(sp);
}
sp->flags &= ~ISC_OWAITING;
}
@ -600,14 +564,20 @@ ism_proc(void *vp)
sp->flags &= ~ISC_SM_RUNNING;
sdebug(3, "dropped ISC_SM_RUNNING");
wakeup(&sp->soc);
wakeup(sp); // XXX: do we need this one?
#if __FreeBSD_version >= 700000
destroy_dev(sp->dev);
#endif
wakeup(sp);
debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
#if __FreeBSD_version >= 800000
kproc_exit(0);
#else
kthread_exit(0);
#endif
}
#if 0
@ -753,12 +723,16 @@ ism_stop(isc_session_t *sp)
(void)i_pdu_flush(sp);
ic_lost_target(sp, sp->sid);
ic_destroy(sp);
mtx_lock(&sc->mtx);
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->mtx);
mtx_unlock(&sc->isc_mtx);
#if __FreeBSD_version < 700000
destroy_dev(sp->dev);
@ -771,7 +745,6 @@ ism_stop(isc_session_t *sp)
mtx_destroy(&sp->io_mtx);
i_freeopt(&sp->opt);
sc->sessions[sp->sid] = NULL;
if(sysctl_ctx_free(&sp->clist))
xdebug("sysctl_ctx_free failed");
@ -792,17 +765,11 @@ ism_start(isc_session_t *sp)
TAILQ_INIT(&sp->isnd);
TAILQ_INIT(&sp->wsnd);
TAILQ_INIT(&sp->hld);
#if 1
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);
#else
mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_SPIN);
mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_SPIN);
mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_SPIN);
mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_SPIN);
#endif
mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF);
isc_add_sysctls(sp);
@ -810,5 +777,10 @@ ism_start(isc_session_t *sp)
sp->flags |= ISC_SM_RUN;
debug(4, "starting ism_proc: sp->sid=%d", sp->sid);
return kproc_create(ism_proc, sp, &sp->stp, 0, 0, "ism_%d", sp->sid);
#if __FreeBSD_version >= 800000
return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
#else
return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid);
#endif
}

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -25,10 +25,8 @@
*
*/
/*
| iSCSI
| $Id: isc_soc.c,v 1.26 2007/05/19 06:09:01 danny Exp danny $
| $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -66,9 +64,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef USE_MBUF
static int ou_refcnt = 0;
/*
| function for freeing external storage for mbuf
*/
@ -79,7 +75,7 @@ ext_free(void *a, void *b)
if(pq->buf != NULL) {
debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, pq->buf);
free(pq->buf, M_ISCSI);
free(pq->buf, M_ISCSIBUF);
pq->buf = NULL;
}
}
@ -88,84 +84,96 @@ int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
struct mbuf *mh, **mp;
pdu_t *pp = &pq->pdu;
int len, error;
pdu_t *pp = &pq->pdu;
int len, error;
debug_called(8);
/*
| mbuf for the iSCSI header
*/
MGETHDR(mh, M_TRYWAIT, MT_DATA);
mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u);
mh->m_pkthdr.rcvif = NULL;
MH_ALIGN(mh, sizeof(union ipdu_u));
bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u));
mh->m_next = NULL;
mh->m_len = sizeof(union ipdu_u);
if(sp->hdrDigest)
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
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
| XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN
*/
bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len);
mh->m_len += pp->ahs_len;
mh->m_pkthdr.len += pp->ahs_len;
if(sp->hdrDigest)
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
if((mh->m_len + pp->ahs_len) < MHLEN) {
MH_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);
}
if(sp->hdrDigest) {
debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
/*
| Add header digest to the iSCSI hdr mbuf
| XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN
*/
bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int));
mh->m_len += sizeof(int);
mh->m_pkthdr.len += sizeof(int);
else {
MH_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(pq->pdu.ds) {
struct mbuf *md;
int off = 0;
if(pp->ds_len && pq->pdu.ds_addr) {
struct mbuf *md;
int off = 0;
len = pp->ds_len;
while(len & 03) // the specs say it must be int alligned
len++;
while(len > 0) {
int l;
int l;
MGET(md, M_TRYWAIT, MT_DATA);
md->m_ext.ref_cnt = &ou_refcnt;
l = min(MCLBYTES, len);
debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
MEXTADD(md, pp->ds + off, l, ext_free, pp->ds + off, pq, 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(sp->dataDigest) {
struct mbuf *me;
pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
MGET(me, M_TRYWAIT, MT_DATA);
me->m_len = sizeof(int);
MH_ALIGN(mh, sizeof(int));
bcopy(&pp->ds_dig, me->m_data, sizeof(int));
me->m_next = NULL;
mh->m_pkthdr.len += sizeof(int);
*mp = me;
l = min(MCLBYTES, len);
debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
MEXTADD(md, pp->ds_addr + off, l, ext_free,
#if __FreeBSD_version >= 800000
pp->ds_addr + off,
#endif
pq, 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_TRYWAIT, 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(3, "error=%d", error);
sdebug(2, "error=%d", error);
return error;
}
sp->stats.nsent++;
@ -191,39 +199,46 @@ isc_sendPDU(isc_session_t *sp, pduq_t *pq)
iv->iov_base = &pp->ipdu;
iv->iov_len = sizeof(union ipdu_u);
uio->uio_resid = pq->len;
uio->uio_resid = iv->iov_len;
iv++;
if(sp->hdrDigest)
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;
iv->iov_base = pp->ahs_addr;
iv->iov_len = pp->ahs_len;
uio->uio_resid += iv->iov_len;
iv++;
if(sp->hdrDigest)
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
if(ISOK2DIG(sp->hdrDigest, pp))
pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
}
if(sp->hdrDigest) {
debug(2, "hdr_dig=%x", pq->pdu.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) {
iv->iov_base = pp->ds;
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 alligned
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++;
}
}
if(sp->dataDigest) {
pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
iv->iov_base = &pp->ds_dig;
iv->iov_len = sizeof(int);
iv++;
}
uio->uio_iovcnt = iv - pq->iov;
sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
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",
@ -244,12 +259,12 @@ isc_sendPDU(isc_session_t *sp, pduq_t *pq)
| XXX: untested code
*/
sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
uio->uio_resid, uio->uio_iovcnt);
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;
caddr_t bp = (caddr_t)iv->iov_base;
iv->iov_len -= len;
iv->iov_base = (void *)&bp[len];
@ -265,7 +280,6 @@ isc_sendPDU(isc_session_t *sp, pduq_t *pq)
if(error == 0) {
sp->stats.nsent++;
getbintime(&sp->stats.t_sent);
}
return error;
@ -322,159 +336,197 @@ so_getbhs(isc_session_t *sp)
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",
debug(2,
#if __FreeBSD_version > 800000
"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
#else
"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd",
#endif
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",
debug(2,
#if __FreeBSD_version > 800000
"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x",
#else
"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x",
#endif
error,
sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
}
return error;
}
/*
| so_recv gets called when there is at least
| an iSCSI header in the queue
| 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)
{
struct socket *so = sp->soc;
sn_t *sn = &sp->sn;
struct uio *uio = &pq->uio;
pdu_t *pp;
pdu_t *pp = &pq->pdu;
bhs_t *bhs = &pp->ipdu.bhs;
struct iovec *iov = pq->iov;
int error;
size_t n, len;
bhs_t *bhs;
u_int len;
u_int max, exp;
int flags = MSG_WAITALL;
debug_called(8);
/*
| now calculate how much data should be in the buffer
| NOTE: digest is not verified/calculated - yet
*/
pp = &pq->pdu;
bhs = &pp->ipdu.bhs;
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(sp->hdrDigest)
len += 4;
if(bhs->DSLength) {
n = bhs->DSLength;
#if BYTE_ORDER == LITTLE_ENDIAN
pp->ds_len = ((n & 0x00ff0000) >> 16)
| (n & 0x0000ff00)
| ((n & 0x000000ff) << 16);
#else
pp->ds_len = n;
#endif
len += pp->ds_len;
while(len & 03)
len++;
if(sp->dataDigest)
len += 4;
}
if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
#if 0
xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
len, sp->opt.maxRecvDataSegmentLength);
// deep trouble here, probably all we can do is
// force a disconnect, XXX: check RFC ...
log(LOG_ERR,
"so_recv: impossible PDU length(%ld) from iSCSI %s/%s\n",
len, sp->opt.targetAddress, sp->opt.targetName);
#endif
/*
| 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;
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) {
int flags = MSG_WAITALL;
struct mbuf **mp;
mp = &pq->mp;
uio->uio_resid = len;
uio->uio_td = curthread; // why ...
if(sp->douio) {
// it's more efficient to use mbufs -- why?
if(bhs->opcode == ISCSI_READ_DATA) {
pduq_t *opq;
opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1);
if(opq != NULL) {
union ccb *ccb = opq->ccb;
struct ccb_scsiio *csio = &ccb->csio;
pdu_t *opp = &opq->pdu;
scsi_req_t *cmd = &opp->ipdu.scsi_req;
data_in_t *rcmd = &pq->pdu.ipdu.data_in;
bhs_t *bhp = &opp->ipdu.bhs;
int r;
if(bhp->opcode == ISCSI_SCSI_CMD
&& cmd->R
&& (ntohl(cmd->edtlen) >= pq->pdu.ds_len)) {
struct iovec *iov = pq->iov;
iov->iov_base = csio->data_ptr + ntohl(rcmd->bo);
iov->iov_len = pq->pdu.ds_len;
uio->uio_rw = UIO_READ;
uio->uio_segflg = UIO_SYSSPACE;
uio->uio_iov = iov;
uio->uio_iovcnt = 1;
if(len > pq->pdu.ds_len) {
pq->iov[1].iov_base = &r;
pq->iov[1].iov_len = len - pq->pdu.ds_len;
uio->uio_iovcnt++;
}
mp = NULL;
sdebug(4, "uio_resid=0x%zx itt=0x%x bp=%p bo=%x len=%x/%x",
uio->uio_resid,
ntohl(pq->pdu.ipdu.bhs.itt),
csio->data_ptr, ntohl(rcmd->bo), ntohl(cmd->edtlen), pq->pdu.ds_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,
#if __FreeBSD_version > 800000
"len=%d error=%d uio->uio_resid=%zd",
#else
"len=%d error=%d uio->uio_resid=%d",
#endif
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;
}
}
error = soreceive(so, NULL, uio, mp, NULL, &flags);
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"));
}
}
pq->len += len;
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;
@ -482,6 +534,10 @@ so_recv(isc_session_t *sp, pduq_t *pq)
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)
@ -510,8 +566,8 @@ so_input(isc_session_t *sp)
*/
pq = pdu_alloc(sp->isc, M_NOWAIT);
if(pq == NULL) { // XXX: might cause a deadlock ...
debug(3, "out of pdus, wait");
pq = pdu_alloc(sp->isc, M_NOWAIT); // OK to WAIT
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
@ -536,7 +592,7 @@ so_input(isc_session_t *sp)
| in packets from the target.
*/
static void
isc_soc(void *vp)
isc_in(void *vp)
{
isc_session_t *sp = (isc_session_t *)vp;
struct socket *so = sp->soc;
@ -545,9 +601,6 @@ isc_soc(void *vp)
debug_called(8);
sp->flags |= ISC_CON_RUNNING;
if(sp->cam_path)
ic_release(sp);
error = 0;
while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
// XXX: hunting ...
@ -559,7 +612,7 @@ isc_soc(void *vp)
if(error == 0) {
mtx_lock(&sp->io_mtx);
if(sp->flags & ISC_OWAITING) {
wakeup(&sp->flags);
wakeup(&sp->flags);
}
mtx_unlock(&sp->io_mtx);
} else if(error == EPIPE) {
@ -594,8 +647,11 @@ isc_soc(void *vp)
mtx_unlock(&sp->io_mtx);
sdebug(2, "dropped ISC_CON_RUNNING");
#if __FreeBSD_version >= 800000
kproc_exit(0);
#else
kthread_exit(0);
#endif
}
void
@ -621,7 +677,6 @@ isc_stop_receiver(isc_session_t *sp)
}
mtx_unlock(&sp->io_mtx);
if(sp->fp != NULL)
fdrop(sp->fp, sp->td);
fputsock(sp->soc);
@ -637,6 +692,10 @@ isc_start_receiver(isc_session_t *sp)
debug_called(8);
sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
kproc_create(isc_soc, sp, &sp->soc_proc, 0, 0, "iscsi%d", sp->sid);
#if __FreeBSD_version >= 800000
kproc_create
#else
kthread_create
#endif
(isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid);
}

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -26,7 +26,7 @@
*/
/*
| iSCSI
| $Id: isc_subr.c,v 1.20 2006/12/01 09:10:17 danny Exp danny $
| $Id: isc_subr.c 560 2009-05-07 07:37:49Z danny $
*/
#include <sys/cdefs.h>
@ -58,20 +58,22 @@ __FBSDID("$FreeBSD$");
#include <dev/iscsi/initiator/iscsi.h>
#include <dev/iscsi/initiator/iscsivar.h>
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_ISCSI, M_WAITOK);
p = malloc(maxlen, M_ISC, M_WAITOK);
if(copyinstr(s, p, maxlen, &len)) {
free(p, M_ISCSI);
free(p, M_ISC);
return NULL;
}
q = malloc(len, M_ISCSI, M_WAITOK);
q = malloc(len, M_ISC, M_WAITOK);
bcopy(p, q, len);
free(p, M_ISCSI);
free(p, M_ISC);
return q;
}
@ -98,50 +100,51 @@ i_setopt(isc_session_t *sp, isc_opt_t *opt)
if(opt->maxXmitDataSegmentLength > 0) {
// danny's RFC
sp->opt.maxXmitDataSegmentLength = opt->maxXmitDataSegmentLength;
sdebug(2, "maXmitDataSegmentLength=%d", sp->opt.maxXmitDataSegmentLength);
sdebug(2, "opt.maXmitDataSegmentLength=%d", sp->opt.maxXmitDataSegmentLength);
}
if(opt->maxBurstLength != 0) {
sp->opt.maxBurstLength = opt->maxBurstLength;
sdebug(2, "maxBurstLength=%d", sp->opt.maxBurstLength);
sdebug(2, "opt.maxBurstLength=%d", sp->opt.maxBurstLength);
}
if(opt->targetAddress != NULL) {
if(sp->opt.targetAddress != NULL)
free(sp->opt.targetAddress, M_ISCSI);
free(sp->opt.targetAddress, M_ISC);
sp->opt.targetAddress = i_strdupin(opt->targetAddress, 128);
sdebug(4, "opt.targetAddress='%s'", sp->opt.targetAddress);
sdebug(2, "opt.targetAddress='%s'", sp->opt.targetAddress);
}
if(opt->targetName != NULL) {
if(sp->opt.targetName != NULL)
free(sp->opt.targetName, M_ISCSI);
free(sp->opt.targetName, M_ISC);
sp->opt.targetName = i_strdupin(opt->targetName, 128);
sdebug(4, "opt.targetName='%s'", sp->opt.targetName);
sdebug(2, "opt.targetName='%s'", sp->opt.targetName);
}
if(opt->initiatorName != NULL) {
if(sp->opt.initiatorName != NULL)
free(sp->opt.initiatorName, M_ISCSI);
free(sp->opt.initiatorName, M_ISC);
sp->opt.initiatorName = i_strdupin(opt->initiatorName, 128);
sdebug(4, "opt.initiatorName='%s'", sp->opt.initiatorName);
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(4, "opt.maxluns=%d", sp->opt.maxluns);
sdebug(2, "opt.maxluns=%d", sp->opt.maxluns);
}
if(opt->headerDigest != NULL) {
sdebug(2, "opt.headerDigest='%s'", opt->headerDigest);
if(strcmp(opt->headerDigest, "CRC32C") == 0) {
sp->hdrDigest = (digest_t *)i_crc32c;
sdebug(2, "headerDigest set");
sdebug(2, "opt.headerDigest set");
}
}
if(opt->dataDigest != NULL) {
sdebug(2, "opt.dataDigest='%s'", opt->headerDigest);
if(strcmp(opt->dataDigest, "CRC32C") == 0) {
sp->dataDigest = (digest_t *)i_crc32c;
sdebug(2, "dataDigest set");
sdebug(2, "opt.dataDigest set");
}
}
@ -151,16 +154,18 @@ i_setopt(isc_session_t *sp, isc_opt_t *opt)
void
i_freeopt(isc_opt_t *opt)
{
debug_called(8);
if(opt->targetAddress != NULL) {
free(opt->targetAddress, M_ISCSI);
free(opt->targetAddress, M_ISC);
opt->targetAddress = NULL;
}
if(opt->targetName != NULL) {
free(opt->targetName, M_ISCSI);
free(opt->targetName, M_ISC);
opt->targetName = NULL;
}
if(opt->initiatorName != NULL) {
free(opt->initiatorName, M_ISCSI);
free(opt->initiatorName, M_ISC);
opt->initiatorName = NULL;
}
}

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -25,8 +25,7 @@
*
*/
/*
| iSCSI
| $Id: iscsi.c,v 1.35 2007/04/22 08:58:29 danny Exp danny $
| $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $
*/
#include <sys/cdefs.h>
@ -56,15 +55,17 @@ __FBSDID("$FreeBSD$");
#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.2.4.2";
static char *iscsi_driver_version = "2.1.0";
static struct isc_softc isc;
static struct isc_softc *isc;
MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
#ifdef ISCSI_INITIATOR_DEBUG
int iscsi_debug = ISCSI_INITIATOR_DEBUG;
@ -74,6 +75,12 @@ SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
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, MAX_SESSIONS,
"Max sessions allowed");
static int max_pdus = MAX_PDUS;
SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, &max_pdus, MAX_PDUS,
"Max pdu pool");
static char isid[6+1] = {
0x80,
@ -91,6 +98,7 @@ 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;
@ -117,39 +125,28 @@ iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
debug(7, "dev=%d", dev2unit(dev));
if(dev2unit(dev) > MAX_SESSIONS) {
if(dev2unit(dev) > max_sessions) {
// should not happen
return ENODEV;
}
if(dev2unit(dev) == MAX_SESSIONS) {
#if 1
struct isc_softc *sc = (struct isc_softc *)dev->si_drv1;
// this should be in iscsi_start
if(sc->cam_sim == NULL)
ic_init(sc);
#endif
}
return 0;
}
static int
iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
{
struct isc *sc;
isc_session_t *sp;
debug_called(8);
debug(3, "flag=%x", flag);
debug(3, "session=%d flag=%x", dev2unit(dev), flag);
sc = (struct isc *)dev->si_drv1;
if(dev2unit(dev) == MAX_SESSIONS) {
if(dev2unit(dev) == max_sessions) {
return 0;
}
sp = (isc_session_t *)dev->si_drv2;
sp = dev->si_drv2;
if(sp != NULL) {
sdebug(2, "session=%d flags=%x", dev2unit(dev), sp->flags );
sdebug(3, "sp->flags=%x", sp->flags );
/*
| if still in full phase, this probably means
| that something went realy bad.
@ -170,19 +167,19 @@ iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
static int
iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
{
struct isc *sc;
struct isc_softc *sc;
isc_session_t *sp;
isc_opt_t *opt;
int error;
sc = (struct isc *)dev->si_drv1;
debug_called(8);
error = 0;
if(dev2unit(dev) == MAX_SESSIONS) {
if(dev2unit(dev) == max_sessions) {
/*
| non Session commands
*/
sc = dev->si_drv1;
if(sc == NULL)
return ENXIO;
@ -190,18 +187,17 @@ iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *
case ISCSISETSES:
error = i_create_session(dev, (int *)arg);
if(error == 0)
break;
break;
default:
error = ENXIO; // XXX:
error = ENXIO;
}
return error;
}
sp = (isc_session_t *)dev->si_drv2;
/*
| session commands
*/
sp = dev->si_drv2;
if(sp == NULL)
return ENXIO;
@ -230,7 +226,7 @@ iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *
break;
case ISCSISTART:
error = sp->soc == NULL? ENOTCONN: ism_fullfeature(dev, 1);
error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
if(error == 0) {
sp->proc = td->td_proc;
SYSCTL_ADD_UINT(&sp->clist,
@ -243,11 +239,11 @@ iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *
break;
case ISCSIRESTART:
error = sp->soc == NULL? ENOTCONN: ism_fullfeature(dev, 2);
error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2);
break;
case ISCSISTOP:
error = ism_fullfeature(dev, 0);
error = i_fullfeature(dev, 0);
break;
case ISCSISIGNAL: {
@ -283,9 +279,9 @@ iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
pduq_t *pq;
char buf[1024];
sc = (struct isc_softc *)dev->si_drv1;
sp = (isc_session_t *)dev->si_drv2;
if(dev2unit(dev) == MAX_SESSIONS) {
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;
@ -310,10 +306,11 @@ iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
int i = 0;
struct socket *so = sp->soc;
#define pukeit(i, pq) do {\
sprintf(buf, "%03d] %06x %02x %x %ld %jd\n",\
i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
sprintf(buf, "%03d] %06x %02x %06x %06x %zd\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);\
ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
pq->ts.sec);\
} while(0)
sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
@ -418,8 +415,7 @@ i_setsoc(isc_session_t *sp, int fd, struct thread *td)
static int
i_send(struct cdev *dev, caddr_t arg, struct thread *td)
{
isc_session_t *sp = (isc_session_t *)dev->si_drv2;
struct isc_softc *sc = (struct isc_softc *)dev->si_drv1;
isc_session_t *sp = dev->si_drv2;
caddr_t bp;
pduq_t *pq;
pdu_t *pp;
@ -430,38 +426,46 @@ i_send(struct cdev *dev, caddr_t arg, struct thread *td)
if(sp->soc == NULL)
return ENOTCONN;
if((pq = pdu_alloc(sc, M_NOWAIT)) == NULL)
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;
sdebug(3, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSI, M_NOWAIT);
if(pq->buf == NULL) {
error = EAGAIN;
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, bp, n);
error = copyin(pp->ahs_addr, bp, n);
if(error != 0) {
sdebug(3, "copyin ahs: error=%d", error);
goto out;
}
pp->ahs = (ahs_t *)bp;
pp->ahs_addr = (ahs_t *)bp;
bp += n;
}
if(pp->ds_len) {
n = pp->ds_len;
error = copyin(pp->ds, bp, n);
error = copyin(pp->ds_addr, bp, n);
if(error != 0) {
sdebug(3, "copyin ds: error=%d", error);
goto out;
}
pp->ds = bp;
pp->ds_addr = bp;
bp += n;
while(n & 03) {
n++;
@ -470,24 +474,19 @@ i_send(struct cdev *dev, caddr_t arg, struct thread *td)
}
error = isc_qout(sp, pq);
#if 1
if(error == 0)
wakeup(&sp->flags); // XXX: to 'push' proc_out ...
#endif
out:
if(error)
pdu_free(sc, pq);
pdu_free(sp->isc, pq);
return error;
}
/*
| NOTE: must calculate digest if requiered.
*/
static int
i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
{
isc_session_t *sp = (isc_session_t *)dev->si_drv2;
isc_session_t *sp = dev->si_drv2;
pduq_t *pq;
pdu_t *pp, *up;
caddr_t bp;
@ -501,7 +500,6 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
if(sp->soc == NULL)
return ENOTCONN;
sdebug(3, "");
cnt = 6; // XXX: maybe the user can request a time out?
mtx_lock(&sp->rsp_mtx);
while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
@ -514,7 +512,7 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
}
mtx_unlock(&sp->rsp_mtx);
sdebug(4, "cnt=%d", cnt);
sdebug(6, "cnt=%d", cnt);
if(pq == NULL) {
error = ENOTCONN;
@ -536,19 +534,15 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
len = 0;
if(pp->ahs_len) {
len += pp->ahs_len;
if(sp->hdrDigest)
len += 4;
}
if(pp->ds_len) {
len += pp->ds_len;
if(sp->hdrDigest)
len += 4;
}
mustfree = 0;
if(len > pq->mp->m_len) {
mustfree++;
bp = malloc(len, M_ISCSI, M_WAITOK);
bp = malloc(len, M_TMP, M_WAITOK);
sdebug(4, "need mbufcopy: %d", len);
i_mbufcopy(pq->mp, bp, len);
}
@ -557,28 +551,24 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
if(pp->ahs_len) {
need = pp->ahs_len;
if(sp->hdrDigest)
need += 4;
n = MIN(up->ahs_size, need);
error = copyout(bp, (caddr_t)up->ahs, n);
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(sp->hdrDigest)
need += 4;
if((have = up->ds_size) == 0) {
have = up->ahs_size - n;
up->ds = (caddr_t)up->ahs + n;
up->ds_addr = (caddr_t)up->ahs_addr + n;
}
n = MIN(have, need);
error = copyout(bp, (caddr_t)up->ds, n);
error = copyout(bp, (caddr_t)up->ds_addr, n);
up->ds_len = n;
}
if(mustfree)
free(bp, M_ISCSI);
free(bp, M_TMP);
}
sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
@ -588,34 +578,58 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
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 = (struct isc_softc *)dev->si_drv1;
struct isc_softc *sc = dev->si_drv1;
isc_session_t *sp;
int error, n;
debug_called(8);
sp = (isc_session_t *)malloc(sizeof *sp, M_ISCSI, M_WAITOK | M_ZERO);
sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
if(sp == NULL)
return ENOMEM;
mtx_lock(&sc->mtx);
/*
| search for the lowest unused sid
*/
for(n = 0; n < MAX_SESSIONS; n++)
if(sc->sessions[n] == NULL)
break;
if(n == MAX_SESSIONS) {
mtx_unlock(&sc->mtx);
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;
}
TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
sc->nsess++;
mtx_unlock(&sc->mtx);
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);
sc->sessions[n] = sp;
sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
*ndev = sp->sid = n;
sp->isc = sc;
@ -624,10 +638,9 @@ i_create_session(struct cdev *dev, int *ndev)
sp->opt.maxRecvDataSegmentLength = 8192;
sp->opt.maxXmitDataSegmentLength = 8192;
sp->opt.maxBurstLength = 65536; // 64k
sp->opt.maxluns = ISCSI_MAX_LUNS;
sdebug(2, "sessionID=%d sp=%p", n, sp);
error = ism_start(sp);
return error;
@ -663,7 +676,7 @@ iscsi_counters(isc_session_t *sp)
static void
iscsi_shutdown(void *v)
{
struct isc_softc *sc = (struct isc_softc *)v;
struct isc_softc *sc = v;
isc_session_t *sp;
int n;
@ -672,12 +685,14 @@ iscsi_shutdown(void *v)
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);
@ -686,24 +701,6 @@ iscsi_shutdown(void *v)
debug(2, "done");
}
static int
init_pdus(struct isc_softc *sc)
{
debug_called(8);
sc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
NULL, NULL, NULL, NULL,
0, 0);
if(sc->pdu_zone == NULL) {
printf("iscsi_initiator: uma_zcreate failed");
return -1;
}
uma_zone_set_max(sc->pdu_zone, MAX_PDUS);
TAILQ_INIT(&sc->freepdu);
return 0;
}
static void
free_pdus(struct isc_softc *sc)
{
@ -724,50 +721,52 @@ free_pdus(struct isc_softc *sc)
static void
iscsi_start(void)
{
struct isc_softc *sc = &isc;
debug_called(8);
memset(sc, 0, sizeof(struct isc_softc));
TUNABLE_INT_FETCH("net.iscsi_initiator.max_sessions", &max_sessions);
TUNABLE_INT_FETCH("net.iscsi_initiator.max_pdus", &max_pdus);
sc->dev = make_dev(&iscsi_cdevsw, MAX_SESSIONS, UID_ROOT, GID_WHEEL, 0600, "iscsi");
sc->dev->si_drv1 = sc;
isc = malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
isc->dev = make_dev(&iscsi_cdevsw, max_sessions, UID_ROOT, GID_WHEEL, 0600, "iscsi");
isc->dev->si_drv1 = isc;
mtx_init(&isc->isc_mtx, "iscsi", NULL, MTX_DEF);
mtx_init(&isc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF);
TAILQ_INIT(&sc->isc_sess);
if(init_pdus(sc) != 0)
xdebug("pdu zone init failed!"); // XXX: should cause terminal failure ...
mtx_init(&sc->mtx, "iscsi", NULL, MTX_DEF);
mtx_init(&sc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF);
#if 0
// XXX: this will cause a panic if the
// module is loaded too early
if(ic_init(sc) != 0)
return;
#else
sc->cam_sim = NULL;
#endif
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);
if(isc->pdu_zone == NULL) {
xdebug("iscsi_initiator: uma_zcreate failed");
// XXX: should fail...
}
uma_zone_set_max(isc->pdu_zone, max_pdus);
TAILQ_INIT(&isc->freepdu);
isc->unit = new_unrhdr(0, max_sessions-1, NULL);
sx_init(&isc->unit_sx, "iscsi sx");
#ifdef DO_EVENTHANDLER
if((sc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
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(&sc->clist);
sc->oid = SYSCTL_ADD_NODE(&sc->clist,
sysctl_ctx_init(&isc->clist);
isc->oid = SYSCTL_ADD_NODE(&isc->clist,
SYSCTL_STATIC_CHILDREN(_net),
OID_AUTO,
"iscsi",
"iscsi_initiator",
CTLFLAG_RD,
0,
"iSCSI Subsystem");
SYSCTL_ADD_STRING(&sc->clist,
SYSCTL_CHILDREN(sc->oid),
SYSCTL_ADD_STRING(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"driver_version",
CTLFLAG_RD,
@ -775,8 +774,8 @@ iscsi_start(void)
0,
"iscsi driver version");
SYSCTL_ADD_STRING(&sc->clist,
SYSCTL_CHILDREN(sc->oid),
SYSCTL_ADD_STRING(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"isid",
CTLFLAG_RW,
@ -784,13 +783,13 @@ iscsi_start(void)
6+1,
"initiator part of the Session Identifier");
SYSCTL_ADD_INT(&sc->clist,
SYSCTL_CHILDREN(sc->oid),
SYSCTL_ADD_INT(&isc->clist,
SYSCTL_CHILDREN(isc->oid),
OID_AUTO,
"sessions",
CTLFLAG_RD,
&sc->nsess,
sizeof(sc->nsess),
&isc->nsess,
sizeof(isc->nsess),
"number of active session");
printf("iscsi: version %s\n", iscsi_driver_version);
@ -804,7 +803,6 @@ iscsi_start(void)
static void
iscsi_stop(void)
{
struct isc_softc *sc = &isc;
isc_session_t *sp, *sp_tmp;
debug_called(8);
@ -813,24 +811,26 @@ iscsi_stop(void)
| go through all the sessions
| Note: close should have done this ...
*/
TAILQ_FOREACH_SAFE(sp, &sc->isc_sess, sp_link, sp_tmp) {
TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
//XXX: check for activity ...
ism_stop(sp);
if(sp->cam_sim != NULL)
ic_destroy(sp);
}
if(sc->cam_sim != NULL)
ic_destroy(sc);
mtx_destroy(&isc->isc_mtx);
mtx_destroy(&isc->pdu_mtx);
sx_destroy(&isc->unit_sx);
mtx_destroy(&sc->mtx);
mtx_destroy(&sc->pdu_mtx);
free_pdus(sc);
free_pdus(isc);
if(sc->dev)
destroy_dev(sc->dev);
if(isc->dev)
destroy_dev(isc->dev);
if(sysctl_ctx_free(&sc->clist))
if(sysctl_ctx_free(&isc->clist))
xdebug("sysctl_ctx_free failed");
iscsi_shutdown(sc); // XXX: check EVENTHANDLER_ ...
iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
free(isc, M_ISCSI);
}
static int
@ -844,13 +844,12 @@ iscsi_modevent(module_t mod, int what, void *arg)
break;
case MOD_QUIESCE:
#if 1
if(isc.nsess) {
xdebug("iscsi module busy(nsess=%d), cannot unload", isc.nsess);
if(isc->nsess) {
xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
log(LOG_ERR, "iscsi module busy, cannot unload");
}
return isc.nsess;
#endif
return isc->nsess;
case MOD_SHUTDOWN:
break;

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -26,7 +26,7 @@
* $FreeBSD$
*/
/*
| $Id: iscsi.h,v 1.17 2006/12/01 09:10:17 danny Exp danny $
| $Id: iscsi.h 743 2009-08-08 10:54:53Z danny $
*/
#define TRUE 1
#define FALSE 0
@ -37,11 +37,7 @@ typedef int boolean_t;
#include <cam/cam.h>
#define ISCSIDEV "iscsi"
#define ISCSI_MAX_TARGETS 4 //64
#define ISCSI_MAX_LUNS 4
#define ISCSI_MAX_TARGETS 64
/*
| iSCSI commands
*/
@ -422,13 +418,13 @@ typedef struct {
*/
typedef struct {
union ipdu_u ipdu;
ahs_t *ahs;
u_int ahs_len;
u_int ahs_size; // the allocated size
u_int hdr_dig; // header digest
u_char *ds;
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
@ -474,6 +470,7 @@ typedef struct opvals {
u_char tgtChapID;
char *tgtChapDigest;
char *iqn;
char *pidfile;
} isc_opt_t;
/*
@ -498,7 +495,6 @@ typedef struct iscsi_cam {
path_id_t path_id;
target_id_t target_id;
int target_nluns;
lun_id_t target_lun[ISCSI_MAX_LUNS];
} iscsi_cam_t;
#define ISCSIGETCAM _IOR('i', 33, iscsi_cam_t)

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -25,7 +25,7 @@
*
*/
/*
| $Id: iscsi_subr.c,v 1.17 2006/11/26 14:50:43 danny Exp danny $
| $Id: iscsi_subr.c 743 2009-08-08 10:54:53Z danny $
*/
#include <sys/cdefs.h>
@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@ -122,7 +123,7 @@ iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
bs = MIN(bs, bleft);
wpq->pdu.ds_len = bs;
wpq->pdu.ds = bp;
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);
@ -188,16 +189,16 @@ getSenseData(u_int status, union ccb *ccb, pduq_t *pq)
| Some information is from SAM draft.
*/
static void
_scsi_done(struct isc_softc *isp, u_int response, u_int status, union ccb *ccb, pduq_t *pq)
_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) {
debug(3, "response=%x status=%x ccb=%p pq=%p", response, status, ccb, pq);
sdebug(3, "response=%x status=%x ccb=%p pq=%p", response, status, ccb, pq);
if(pq != NULL)
debug(3, "mp=%p buf=%p len=%d", pq->mp, pq->buf, pq->len);
sdebug(3, "mp=%p buf=%p len=%d", pq->mp, pq->buf, pq->len);
}
ccb_h->status = 0;
switch(response) {
@ -241,9 +242,9 @@ _scsi_done(struct isc_softc *isp, u_int response, u_int status, union ccb *ccb,
ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
break;
}
debug(5, "ccb_h->status=%x", ccb_h->status);
sdebug(5, "ccb_h->status=%x", ccb_h->status);
XPT_DONE(isp, ccb);
XPT_DONE(sp, ccb);
}
/*
@ -256,16 +257,17 @@ iscsi_requeue(isc_session_t *sp)
u_int i, n, last;
debug_called(8);
last = -1;
i = 0;
i = last = 0;
sp->flags |= ISC_HOLD;
while((pq = i_dqueue_hld(sp)) != NULL) {
i++;
_scsi_done(sp->isc, 0, 0x28, pq->ccb, NULL);
n = ntohl(pq->pdu.ipdu.bhs.CmdSN);
if(last > n)
last = n;
sdebug(2, "last=%x n=%x", last, n);
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;
@ -316,14 +318,22 @@ iscsi_cleanup(isc_session_t *sp)
TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, pqtmp) {
sdebug(3, "hld pq=%p", pq);
if(pq->ccb)
_scsi_done(sp->isc, 1, 0x40, pq->ccb, NULL);
_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->isc, 1, 0x40, pq->ccb, NULL);
_scsi_done(sp, 1, 0x40, pq->ccb, NULL);
if(pq->buf) {
free(pq->buf, M_ISCSIBUF);
pq->buf = NULL;
}
pdu_free(sp->isc, pq);
}
@ -338,7 +348,7 @@ iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
debug_called(8);
_scsi_done(sp->isc, cmd->response, cmd->status, opq->ccb, pq);
_scsi_done(sp, cmd->response, cmd->status, opq->ccb, pq);
pdu_free(sp->isc, opq);
}
@ -394,7 +404,7 @@ iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
debug_called(8);
//XXX: check RFC 10.17.1 (page 176)
ccb->ccb_h.status = CAM_REQ_ABORTED;
XPT_DONE(sp->isc, ccb);
XPT_DONE(sp, ccb);
pdu_free(sp->isc, opq);
}
@ -405,10 +415,8 @@ iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
static int
dwl(isc_session_t *sp, int lun, u_char *lp)
{
int i;
debug_called(8);
sdebug(4, "lun=%d", lun);
/*
| mapping LUN to iSCSI LUN
| check the SAM-2 specs
@ -429,14 +437,6 @@ dwl(isc_session_t *sp, int lun, u_char *lp)
return -1;
}
for(i = 0; i < sp->target_nluns; i++)
if(sp->target_lun[i] == lun)
return 0;
if(sp->target_nluns < ISCSI_MAX_LUNS)
sp->target_lun[sp->target_nluns++] = lun;
sdebug(3, "nluns=%d lun=%d", sp->target_nluns, lun);
return 0;
}
@ -446,8 +446,7 @@ dwl(isc_session_t *sp, int lun, u_char *lp)
int
scsi_encap(struct cam_sim *sim, union ccb *ccb)
{
struct isc_softc *isp = (struct isc_softc *)cam_sim_softc(sim);
isc_session_t *sp;
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;
@ -458,33 +457,19 @@ scsi_encap(struct cam_sim *sim, union ccb *ccb)
debug(4, "ccb->sp=%p", ccb_h->spriv_ptr0);
sp = ccb_h->spriv_ptr0;
if((pq = pdu_alloc(isp, M_NOWAIT)) == NULL) {
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(3, "waiting...");
sdebug(2, "waiting...");
#if __FreeBSD_version >= 700000
pause("isc_encap", 5*hz);
#else
tsleep(sp->isc, 0, "isc_encap", 5*hz);
#endif
}
#if 0
sdebug(3, "freezing");
ccb->ccb_h.status = CAM_REQUEUE_REQ;
ic_freeze(sp);
return 0;
#endif
}
#if 0
if((sp->flags & ISC_FFPHASE) == 0) {
ccb->ccb_h.status = CAM_DEV_NOT_THERE; // CAM_NO_NEXUS;
sdebug(3, "no active session with target %d", ccb_h->target_id);
goto bad;
}
#endif
cmd = &pq->pdu.ipdu.scsi_req;
cmd->opcode = ISCSI_SCSI_CMD;
cmd->F = 1;
@ -493,8 +478,8 @@ scsi_encap(struct cam_sim *sim, union ccb *ccb)
*/
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_ORDER; break;
case MSG_ORDERED_Q_TAG: cmd->attr = iSCSI_TASK_HOFQ; 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;
}
@ -532,7 +517,8 @@ scsi_encap(struct cam_sim *sim, union ccb *ccb)
return 1;
invalid:
ccb->ccb_h.status = CAM_REQ_INVALID;
pdu_free(isp, pq);
pdu_free(sp->isc, pq);
return 0;
}
@ -573,15 +559,15 @@ scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
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;
int offset, len = pq->pdu.ds_len;
if(pq->mp != NULL) {
caddr_t dp;
caddr_t dp;
offset = ntohl(rcmd->bo);
dp = csio->data_ptr + offset;
i_mbufcopy(pq->mp, dp, len);
}
offset = ntohl(rcmd->bo);
dp = csio->data_ptr + offset;
i_mbufcopy(pq->mp, dp, len);
}
}
else {
xdebug("edtlen=%d < ds_len=%d",
@ -592,7 +578,7 @@ scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
/*
| contains also the SCSI Status
*/
_scsi_done(sp->isc, 0, rcmd->status, opq->ccb, NULL);
_scsi_done(sp, 0, rcmd->status, opq->ccb, NULL);
return 0;
} else
return 1;

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* 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
@ -25,9 +25,18 @@
*
* $FreeBSD$
*/
/*
| $Id: iscsivar.h,v 1.30 2007/04/22 10:12:11 danny Exp danny $
| $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $
*/
#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
@ -48,13 +57,17 @@ extern int iscsi_debug;
#define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args)
#define MAX_SESSIONS ISCSI_MAX_TARGETS
#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);
MALLOC_DECLARE(M_PDU);
#define ISOK2DIG(dig, pp) ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD))
#ifndef BIT
#define BIT(n) (1 <<(n))
#endif
@ -69,15 +82,15 @@ MALLOC_DECLARE(M_PDU);
#define ISC_OQNOTEMPTY BIT(6)
#define ISC_OWAITING BIT(7)
#define ISC_FFPHASE BIT(8)
#define ISC_FFPWAIT BIT(9)
#define ISC_MEMWAIT BIT(10)
#define ISC_SIGNALED BIT(11)
#define ISC_FROZEN BIT(12)
#define ISC_STALLED BIT(13)
#define ISC_CAMDEVS BIT(9)
#define ISC_SCANWAIT BIT(10)
#define ISC_HOLD BIT(14)
#define ISC_HOLDED BIT(15)
#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)
@ -116,9 +129,7 @@ typedef struct isc_session {
struct proc *proc; // the userland process
int signal;
struct proc *soc_proc;
struct proc *stp; // the sm thread
struct isc_softc *isc;
@ -127,16 +138,13 @@ typedef struct isc_session {
digest_t *dataDigest; // the digest alg. if any
int sid; // Session ID
int targetid;
// int cid; // Connection ID
// int tsih; // target session identifier handle
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.
lun_id_t target_lun[ISCSI_MAX_LUNS];
int target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1];
struct mtx rsp_mtx;
struct mtx rsv_mtx;
@ -150,16 +158,18 @@ typedef struct isc_session {
queue_t wsnd;
queue_t hld;
/*
| negotiable values
*/
isc_opt_t opt;
isc_opt_t opt; // negotiable values
struct i_stats stats;
struct cam_path *cam_path;
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
*/
@ -180,33 +190,29 @@ typedef struct pduq {
struct iovec iov[5]; // XXX: careful ...
struct mbuf *mp;
struct bintime ts;
queue_t *pduq;
queue_t *pduq;
} pduq_t;
/*
*/
struct isc_softc {
//int state;
struct cdev *dev;
eventhandler_tag eh;
char isid[6]; // Initiator Session ID (48 bits)
struct mtx mtx;
int nsess;
struct mtx isc_mtx;
TAILQ_HEAD(,isc_session) isc_sess;
isc_session_t *sessions[MAX_SESSIONS];
int nsess;
struct cdev *dev;
char isid[6]; // Initiator Session ID (48 bits)
struct unrhdr *unit;
struct sx unit_sx;
struct mtx pdu_mtx;
uma_zone_t pdu_zone; // pool of free pdu's
TAILQ_HEAD(,pduq) freepdu;
struct mtx pdu_mtx;
#ifdef ISCSI_INITIATOR_DEBUG
int npdu_alloc, npdu_max; // for instrumentation
int npdu_alloc, npdu_max; // for instrumentation
#endif
#ifdef DO_EVENTHANDLER
eventhandler_tag eh;
#endif
#define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary
uma_zone_t pdu_zone; // pool of free pdu's
TAILQ_HEAD(,pduq) freepdu;
/*
| cam stuff
*/
struct cam_sim *cam_sim;
struct cam_path *cam_path;
struct mtx cam_mtx;
/*
| sysctl stuff
*/
@ -231,14 +237,14 @@ 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(struct isc_softc *sc);
void ic_destroy(struct isc_softc *sc);
int ic_fullfeature(struct cdev *dev);
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);
@ -250,9 +256,6 @@ void iscsi_async(isc_session_t *sp, pduq_t *pq);
void iscsi_cleanup(isc_session_t *sp);
int iscsi_requeue(isc_session_t *sp);
void ic_freeze(isc_session_t *sp);
void ic_release(isc_session_t *sp);
// Serial Number Arithmetic
#define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1
#define SNA_GT(i1, i2) ((i1 != i2) && (\
@ -269,7 +272,7 @@ void ic_release(isc_session_t *sp);
#define CAM_ULOCK(arg)
static __inline void
XPT_DONE(struct isc_softc *isp, union ccb *ccb)
XPT_DONE(isc_session_t *sp, union ccb *ccb)
{
mtx_lock(&Giant);
xpt_done(ccb);
@ -280,11 +283,11 @@ XPT_DONE(struct isc_softc *isp, union ccb *ccb)
#define CAM_UNLOCK(arg) mtx_unlock(&arg->cam_mtx)
static __inline void
XPT_DONE(struct isc_softc *isp, union ccb *ccb)
XPT_DONE(isc_session_t *sp, union ccb *ccb)
{
CAM_LOCK(isp);
CAM_LOCK(sp);
xpt_done(ccb);
CAM_UNLOCK(isp);
CAM_UNLOCK(sp);
}
#else
//__FreeBSD_version >= 600000
@ -332,7 +335,7 @@ pdu_free(struct isc_softc *isc, pduq_t *pq)
m_freem(pq->mp);
#ifdef NO_USE_MBUF
if(pq->buf != NULL)
free(pq->buf, M_ISCSI);
free(pq->buf, M_ISCSIBUF);
#endif
mtx_lock(&isc->pdu_mtx);
TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link);
@ -564,6 +567,27 @@ i_search_hld(isc_session_t *sp, int itt, int keep)
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)
{