summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2008-11-25 07:17:11 +0000
committerscottl <scottl@FreeBSD.org>2008-11-25 07:17:11 +0000
commitb0a070ce29c7f901038f9cfb6bfef9247d44075f (patch)
tree413f5b0f4f80fd3ec9f759e583d550deabbd83a4
parent910037c59a4e6f6be1f74e35e4c5ed1e72c13895 (diff)
downloadFreeBSD-src-b0a070ce29c7f901038f9cfb6bfef9247d44075f.zip
FreeBSD-src-b0a070ce29c7f901038f9cfb6bfef9247d44075f.tar.gz
Big update to the iSCSI initiator code. Highlights include IPv6 support,
many bugs fixes, many more performance improvements. Submitted by: Danny Braniss M sbin/iscontrol/iscsi.conf.5 M sbin/iscontrol/iscontrol.8 M sbin/iscontrol/iscontrol.h M sbin/iscontrol/config.c M sbin/iscontrol/fsm.c M sbin/iscontrol/login.c M sbin/iscontrol/pdu.c M sbin/iscontrol/misc.c M sbin/iscontrol/auth_subr.c M sbin/iscontrol/iscontrol.c M sys/dev/iscsi/initiator/isc_cam.c M sys/dev/iscsi/initiator/iscsi.h M sys/dev/iscsi/initiator/isc_soc.c M sys/dev/iscsi/initiator/iscsi_subr.c M sys/dev/iscsi/initiator/iscsivar.h M sys/dev/iscsi/initiator/isc_subr.c M sys/dev/iscsi/initiator/iscsi.c M sys/dev/iscsi/initiator/isc_sm.c
-rw-r--r--sbin/iscontrol/auth_subr.c3
-rw-r--r--sbin/iscontrol/config.c2
-rw-r--r--sbin/iscontrol/fsm.c97
-rw-r--r--sbin/iscontrol/iscontrol.82
-rw-r--r--sbin/iscontrol/iscontrol.c15
-rw-r--r--sbin/iscontrol/iscontrol.h9
-rw-r--r--sbin/iscontrol/iscsi.conf.52
-rw-r--r--sbin/iscontrol/login.c15
-rw-r--r--sbin/iscontrol/misc.c2
-rw-r--r--sbin/iscontrol/pdu.c3
-rw-r--r--sys/dev/iscsi/initiator/isc_cam.c36
-rw-r--r--sys/dev/iscsi/initiator/isc_sm.c136
-rw-r--r--sys/dev/iscsi/initiator/isc_soc.c282
-rw-r--r--sys/dev/iscsi/initiator/isc_subr.c4
-rw-r--r--sys/dev/iscsi/initiator/iscsi.c126
-rw-r--r--sys/dev/iscsi/initiator/iscsi.h99
-rw-r--r--sys/dev/iscsi/initiator/iscsi_subr.c69
-rw-r--r--sys/dev/iscsi/initiator/iscsivar.h63
18 files changed, 675 insertions, 290 deletions
diff --git a/sbin/iscontrol/auth_subr.c b/sbin/iscontrol/auth_subr.c
index 8381687..06c0ee5 100644
--- a/sbin/iscontrol/auth_subr.c
+++ b/sbin/iscontrol/auth_subr.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$");
#include "iscsi.h"
#include "iscontrol.h"
-#include "pdu.h"
static int
chapMD5(char id, char *cp, char *chapSecret, unsigned char *digest)
diff --git a/sbin/iscontrol/config.c b/sbin/iscontrol/config.c
index 409ed2c..d6d250d 100644
--- a/sbin/iscontrol/config.c
+++ b/sbin/iscontrol/config.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sbin/iscontrol/fsm.c b/sbin/iscontrol/fsm.c
index 6a1c529..443ebca 100644
--- a/sbin/iscontrol/fsm.c
+++ b/sbin/iscontrol/fsm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$");
#include "iscsi.h"
#include "iscontrol.h"
-#include "pdu.h"
typedef enum {
T1 = 1,
@@ -66,38 +65,40 @@ typedef enum {
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;
- struct addrinfo *res, hints;
- struct sockaddr_in sn;
- struct in_addr ipn;
- time_t sec;
+ 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(3, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected");
+ debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected");
shutdown(sess->soc, SHUT_RDWR);
//close(sess->soc);
- sleep(5); // XXX: actually should be ?
sess->soc = -1;
sess->flags &= ~SESS_CONNECTED;
if(sess->flags & SESS_REDIRECT) {
- if(sess->redirect_cnt++ > MAXREDIRECTS) {
- syslog(LOG_WARNING, "too many redirects > %d", MAXREDIRECTS);
- return 0;
- }
+ sess->redirect_cnt++;
sess->flags |= SESS_RECONNECT;
- }
- if((sess->flags & SESS_RECONNECT) == 0)
- return 0;
-
+ } 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;
@@ -117,41 +118,46 @@ tcpConnect(isess_t *sess)
return 0;
}
}
- sess->reconnect_cnt++;
- // sess->flags &= ~(SESS_RECONNECT|SESS_REDIRECT);
}
-
- if((sess->soc = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- fprintf(stderr, "tcpConnect: socket: %m");
- return 0;
+#endif
+ sess->reconnect_cnt++;
}
+ snprintf(pbuf, sizeof(pbuf), "%d", op->port);
memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_INET;
+ hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
-
- debug(3, "targetAddress=%s port=%d", op->targetAddress, op->port);
- if(inet_aton(op->targetAddress, &ipn))
- hints.ai_flags |= AI_NUMERICHOST;
- if((val = getaddrinfo(op->targetAddress, NULL, &hints, &res)) != 0) {
+ 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;
}
- memcpy(&sn, res->ai_addr, sizeof(struct sockaddr_in));
- sn.sin_port = htons(op->port);
- freeaddrinfo(res);
+ 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(sess->soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) {
+ 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));
}
- sess->flags &= ~SESS_CONNECTED;
+ 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(connect(sess->soc, (struct sockaddr *)&sn, sizeof(struct sockaddr_in)) != -1) {
#if 0
struct timeval timeout;
@@ -190,21 +196,29 @@ tcpConnect(isess_t *sess)
}
sess->flags |= SESS_CONNECTED;
return T1;
-
}
- sv_errno = errno;
+
fprintf(stderr, "errno=%d\n", sv_errno);
perror("connect");
switch(sv_errno) {
case ECONNREFUSED:
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
@@ -416,7 +430,6 @@ supervise(isess_t *sess)
}
else {
-
if(ioctl(sess->fd, ISCSIRESTART)) {
perror("ISCSIRESTART");
return -1;
@@ -554,7 +567,10 @@ doLogin(isess_t *sess)
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;
}
@@ -654,6 +670,9 @@ fsm(isc_opt_t *op)
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;
diff --git a/sbin/iscontrol/iscontrol.8 b/sbin/iscontrol/iscontrol.8
index 4ae0d3f..aaa126d 100644
--- a/sbin/iscontrol/iscontrol.8
+++ b/sbin/iscontrol/iscontrol.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007 Daniel Braniss <danny@cs.huji.ac.il>
+.\" Copyright (c) 2007-2008 Daniel Braniss <danny@cs.huji.ac.il>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
diff --git a/sbin/iscontrol/iscontrol.c b/sbin/iscontrol/iscontrol.c
index d5d5929..8cfa5fa 100644
--- a/sbin/iscontrol/iscontrol.c
+++ b/sbin/iscontrol/iscontrol.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$");
#include "iscsi.h"
#include "iscontrol.h"
-//#include "pdu.h"
#define USAGE "[-v] [-d] [-c config] [-n name] [-t target] "
#define OPTIONS "vdc:t:n:"
@@ -129,7 +128,7 @@ int
main(int cc, char **vv)
{
int ch, disco;
- char *pname, *p, *ta, *kw;
+ char *pname, *p, *q, *ta, *kw;
isc_opt_t *op;
FILE *fd;
@@ -191,12 +190,18 @@ main(int cc, char **vv)
fprintf(stderr, "No target!\n");
goto badu;
}
- if((p = strchr(op->targetAddress, ':')) != NULL) {
+ 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(op->targetAddress, ',')) != NULL)) {
+ if(p || ((p = strchr(q, ',')) != NULL)) {
*p++ = 0;
op->targetPortalGroupTag = atoi(p);
}
diff --git a/sbin/iscontrol/iscontrol.h b/sbin/iscontrol/iscontrol.h
index c93c35a..a89d7af 100644
--- a/sbin/iscontrol/iscontrol.h
+++ b/sbin/iscontrol/iscontrol.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,12 @@ int vflag;
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)
@@ -61,6 +67,7 @@ typedef struct isess {
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;
diff --git a/sbin/iscontrol/iscsi.conf.5 b/sbin/iscontrol/iscsi.conf.5
index 3388746..2edcd35 100644
--- a/sbin/iscontrol/iscsi.conf.5
+++ b/sbin/iscontrol/iscsi.conf.5
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007 Daniel Braniss <danny@cs.huji.ac.il>
+.\" Copyright (c) 2007-2008 Daniel Braniss <danny@cs.huji.ac.il>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
diff --git a/sbin/iscontrol/login.c b/sbin/iscontrol/login.c
index 44ea889..ec17f21 100644
--- a/sbin/iscontrol/login.c
+++ b/sbin/iscontrol/login.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include "iscsi.h"
#include "iscontrol.h"
-#include "pdu.h"
static char *status_class1[] = {
"Initiator error",
@@ -173,16 +172,18 @@ processParams(isess_t *sess, pdu_t *pp)
klen = eq - ptr;
if(klen > 0) {
if(strncmp(ptr, "TargetAddress", klen) == 0) {
- char *p, *q;
+ 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++;
- else
+ if((q = strchr(q, ']')) != NULL) {
+ *q++ = '\0';
+ ta = op->targetAddress;
+ op->targetAddress = strdup(ta+1);
+ } else
q = op->targetAddress;
}
if((p = strchr(q, ',')) != NULL) {
@@ -193,6 +194,8 @@ processParams(isess_t *sess, pdu_t *pp)
*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);
diff --git a/sbin/iscontrol/misc.c b/sbin/iscontrol/misc.c
index 4ac3f0a..9634a1b 100644
--- a/sbin/iscontrol/misc.c
+++ b/sbin/iscontrol/misc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sbin/iscontrol/pdu.c b/sbin/iscontrol/pdu.c
index 18dfdfc..980d20a 100644
--- a/sbin/iscontrol/pdu.c
+++ b/sbin/iscontrol/pdu.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
#include "iscsi.h"
#include "iscontrol.h"
-#include "pdu.h"
int
xmitpdu(isess_t *sess, pdu_t *pp)
diff --git a/sys/dev/iscsi/initiator/isc_cam.c b/sys/dev/iscsi/initiator/isc_cam.c
index d978db3..fbd5b3d 100644
--- a/sys/dev/iscsi/initiator/isc_cam.c
+++ b/sys/dev/iscsi/initiator/isc_cam.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -193,6 +193,23 @@ _inq(struct cam_sim *sim, union ccb *ccb, int maxluns)
cpi->ccb_h.status = CAM_REQ_CMP;
}
+static __inline int
+_scsi_encap(struct cam_sim *sim, union ccb *ccb)
+{
+ int ret;
+
+#if __FreeBSD_version < 700000
+ ret = scsi_encap(sim, ccb);
+#else
+ struct isc_softc *isp = (struct isc_softc *)cam_sim_softc(sim);
+
+ mtx_unlock(&isp->cam_mtx);
+ ret = scsi_encap(sim, ccb);
+ mtx_lock(&isp->cam_mtx);
+#endif
+ return ret;
+}
+
static void
ic_action(struct cam_sim *sim, union ccb *ccb)
{
@@ -281,17 +298,8 @@ ic_action(struct cam_sim *sim, union ccb *ccb)
ccb_h->status = CAM_LUN_INVALID;
break;
}
-#if __FreeBSD_version < 700000
- if(scsi_encap(sim, ccb) != 0)
+ if(_scsi_encap(sim, ccb) != 0)
return;
-#else
- mtx_unlock(&isp->cam_mtx);
- if(scsi_encap(sim, ccb) != 0) {
- mtx_lock(&isp->cam_mtx);
- return;
- }
- mtx_lock(&isp->cam_mtx);
-#endif
break;
}
@@ -396,7 +404,11 @@ ic_init(struct isc_softc *isp)
return ENXIO;
}
CAM_LOCK(isp);
- if(xpt_bus_register(sim, NULL, 0/*bus_number*/) != CAM_SUCCESS)
+ if(xpt_bus_register(sim,
+#if __FreeBSD_version >= 700000
+ NULL,
+#endif
+ 0/*bus_number*/) != CAM_SUCCESS)
goto bad;
if(xpt_create_path(&path, xpt_periph, cam_sim_path(sim),
diff --git a/sys/dev/iscsi/initiator/isc_sm.c b/sys/dev/iscsi/initiator/isc_sm.c
index f024aef..3f4f377 100644
--- a/sys/dev/iscsi/initiator/isc_sm.c
+++ b/sys/dev/iscsi/initiator/isc_sm.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -174,7 +174,7 @@ _nop_out(isc_session_t *sp)
/*
| only send a nop if window is closed.
*/
- if((pq = pdu_alloc(sp->isc, 0)) == NULL)
+ if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
// I guess we ran out of resources
return;
nop_out = &pq->pdu.ipdu.nop_out;
@@ -224,7 +224,6 @@ _nop_in(isc_session_t *sp, pduq_t *pq)
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;
}
@@ -318,27 +317,24 @@ isc_qout(isc_session_t *sp, pduq_t *pq)
i_nqueue_csnd(sp, pq);
sdebug(5, "enqued: pq=%p", pq);
-#ifdef ISC_OWAITING
- if(sp->flags & ISC_OWAITING) {
- mtx_lock(&sp->io_mtx); // XXX
- wakeup(&sp->flags);
- mtx_unlock(&sp->io_mtx); // XXX
- }
-#else
+
+ mtx_lock(&sp->io_mtx);
+ sp->flags |= ISC_OQNOTEMPTY;
+ if(sp->flags & ISC_OWAITING)
wakeup(&sp->flags);
-#endif
+ mtx_unlock(&sp->io_mtx);
+
return error;
}
/*
| called when a fullPhase is restarted
*/
-static int
+static void
ism_restart(isc_session_t *sp)
{
int lastcmd;
sdebug(2, "restart ...");
- sp->flags |= ISC_SM_HOLD;
lastcmd = iscsi_requeue(sp);
#if 0
if(lastcmd != sp->sn.cmd) {
@@ -346,8 +342,13 @@ ism_restart(isc_session_t *sp)
sp->sn.cmd = lastcmd;
}
#endif
- sp->flags &= ~ISC_SM_HOLD;
- return 0;
+ mtx_lock(&sp->io_mtx);
+ if(sp->flags & ISC_OWAITING) {
+ wakeup(&sp->flags);
+ }
+ mtx_unlock(&sp->io_mtx);
+
+ sdebug(2, "restarted lastcmd=0x%x", lastcmd);
}
int
@@ -367,7 +368,7 @@ ism_fullfeature(struct cdev *dev, int flag)
error = ic_fullfeature(dev);
break;
case 2: // restart
- error = ism_restart(sp);
+ ism_restart(sp);
break;
}
return error;
@@ -454,32 +455,40 @@ ism_recv(isc_session_t *sp, pduq_t *pq)
}
}
+/*
+ | 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, ndone = 0;
+ int error, ndone;
int which;
debug_called(8);
+ error = ndone = 0;
- while(1) {
+ while(sp->flags & ISC_LINK_UP) {
pdu_t *pp;
bhs_t *bhs;
-
/*
| check if there is outstanding work in:
- | 1- the Inmediate queue
+ | 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(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;
@@ -510,38 +519,45 @@ proc_out(isc_session_t *sp)
// XXX: and now?
}
- sdebug(5, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)",
+ 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(pq->ccb)
i_nqueue_hld(sp, pq);
- if((error = isc_sendPDU(sp, pq)) == 0)
+ 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(error == EPIPE) {
- // XXX: better do some error recovery ...
+ if(pq->ccb)
+ i_remove_hld(sp, pq);
+ switch(error) {
+ case EPIPE:
+ sp->flags &= ~ISC_LINK_UP;
+
+ case EAGAIN:
+ xdebug("requed");
+ i_rqueue_pdu(sp, pq);
break;
- }
-#if 0
+
+ default:
if(pq->ccb) {
- i_remove_hld(sp, pq);
- pq->ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; // some better error?
- XPT_DONE(pq->ccb);
+ xdebug("back to cam");
+ pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error?
+ XPT_DONE(sp->isc, pq->ccb);
+ pdu_free(sp->isc, pq);
}
- else {
- // XXX: now what?
- // how do we pass back an error?
+ else
+ xdebug("we lost it!");
}
-#endif
}
- if(pq->ccb == NULL || error)
- pdu_free(sp->isc, pq);
}
- return ndone;
+ return error;
}
/*
@@ -551,42 +567,46 @@ static void
ism_proc(void *vp)
{
isc_session_t *sp = (isc_session_t *)vp;
- int odone;
+ int error;
debug_called(8);
- sdebug(3, "started");
sp->flags |= ISC_SM_RUNNING;
+ sdebug(3, "started sp->flags=%x", sp->flags);
do {
- if(sp->flags & ISC_SM_HOLD)
- odone = 0;
- else
- odone = proc_out(sp);
- sdebug(7, "odone=%d", odone);
- if(odone == 0) {
+ if((sp->flags & ISC_HOLD) == 0) {
+ error = proc_out(sp);
+ if(error) {
+ sdebug(3, "error=%d", error);
+ }
+ }
mtx_lock(&sp->io_mtx);
-#ifdef ISC_OWAITING
+ if((sp->flags & ISC_LINK_UP) == 0) {
+ wakeup(&sp->soc);
+ }
+
+ if(!(sp->flags & ISC_OQNOTEMPTY)) {
sp->flags |= ISC_OWAITING;
-#endif
- if((msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK)
- && (sp->flags & ISC_CON_RUNNING))
+ if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) {
+ if(sp->flags & ISC_CON_RUNNING)
_nop_out(sp);
-#ifdef ISC_OWAITING
+ }
sp->flags &= ~ISC_OWAITING;
-#endif
- mtx_unlock(&sp->io_mtx);
}
+ 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");
#if __FreeBSD_version >= 700000
destroy_dev(sp->dev);
#endif
+ wakeup(sp);
- sdebug(3, "terminated");
+ debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid);
- wakeup(sp);
kproc_exit(0);
}
@@ -695,6 +715,13 @@ isc_add_sysctls(isc_session_t *sp)
CTLFLAG_RD,
(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
@@ -782,5 +809,6 @@ 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);
}
diff --git a/sys/dev/iscsi/initiator/isc_soc.c b/sys/dev/iscsi/initiator/isc_soc.c
index bbe891e..0150ce7 100644
--- a/sys/dev/iscsi/initiator/isc_soc.c
+++ b/sys/dev/iscsi/initiator/isc_soc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,157 +55,179 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/user.h>
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+
#include <dev/iscsi/initiator/iscsi.h>
#include <dev/iscsi/initiator/iscsivar.h>
-#ifndef USE_MBUF
+#ifndef NO_USE_MBUF
#define USE_MBUF
#endif
#ifdef USE_MBUF
+
+static int ou_refcnt = 0;
+
/*
- | a dummy function for freeing external storage for mbuf
+ | function for freeing external storage for mbuf
*/
static void
-nil_fn(void *a, void *b)
+ext_free(void *a, void *b)
{
+ pduq_t *pq = b;
+
+ if(pq->buf != NULL) {
+ debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, pq->buf);
+ free(pq->buf, M_ISCSI);
+ pq->buf = NULL;
+ }
}
-static int nil_refcnt = 0;
-#endif /* USE_MBUF */
int
isc_sendPDU(isc_session_t *sp, pduq_t *pq)
{
+ struct mbuf *mh, **mp;
pdu_t *pp = &pq->pdu;
int len, error;
-#ifdef USE_MBUF
- struct mbuf *mh, **mp;
-#else
- struct uio *uio = &pq->uio;
- struct iovec *iv;
-#endif /* USE_MBUF */
debug_called(8);
-
-#ifndef USE_MBUF
- 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 = pq->len;
- iv++;
-#else /* USE_MBUF */
- /* mbuf for the iSCSI header */
- MGETHDR(mh, M_WAIT, MT_DATA);
+ /*
+ | 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;
-#endif /* USE_MBUF */
if(sp->hdrDigest)
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
if(pp->ahs_len) {
-#ifndef USE_MBUF
- iv->iov_base = pp->ahs;
- iv->iov_len = pp->ahs_len;
- iv++;
-#else /* USE_MBUF */
- /* Add any AHS to the iSCSI hdr mbuf */
- /* XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN */
+ /*
+ | 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;
-#endif /* USE_MBUF */
+
if(sp->hdrDigest)
pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
}
if(sp->hdrDigest) {
debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
-#ifndef USE_MBUF
- iv->iov_base = &pp->hdr_dig;
- iv->iov_len = sizeof(int);
- iv++;
-#else /* USE_MBUF */
- /* Add header digest to the iSCSI hdr mbuf */
- /* XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN */
+ /*
+ | 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);
-#endif /* USE_MBUF */
}
-#ifdef USE_MBUF
mp = &mh->m_next;
-#endif /* USE_MBUF */
if(pq->pdu.ds) {
-#ifndef USE_MBUF
- iv->iov_base = pp->ds;
- iv->iov_len = pp->ds_len;
- while(iv->iov_len & 03) // the specs say it must be int alligned
- iv->iov_len++;
- iv++;
-#else /* USE_MBUF */
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) {
+ while(len > 0) {
int l;
- MGET(md, M_WAIT, MT_DATA);
- md->m_ext.ref_cnt = &nil_refcnt;
+ MGET(md, M_TRYWAIT, MT_DATA);
+ md->m_ext.ref_cnt = &ou_refcnt;
l = min(MCLBYTES, len);
- MEXTADD(md, pp->ds + off, l, nil_fn,
- pp->ds + off, NULL, 0, EXT_EXTREF);
+ 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;
}
-#endif /* USE_MBUF */
}
if(sp->dataDigest) {
-#ifdef USE_MBUF
struct mbuf *me;
-#endif /* USE_MBUF */
pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
-#ifndef USE_MBUF
- iv->iov_base = &pp->ds_dig;
- iv->iov_len = sizeof(int);
- iv++;
-#else /* USE_MBUF */
- MGET(me, M_WAIT, MT_DATA);
+
+ 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;
-#endif /* USE_MBUF */
}
+ if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
+ sdebug(3, "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 = pq->len;
+ iv++;
+ if(sp->hdrDigest)
+ pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
+ if(pp->ahs_len) {
+ iv->iov_base = pp->ahs;
+ iv->iov_len = pp->ahs_len;
+ iv++;
-#ifndef USE_MBUF
+ if(sp->hdrDigest)
+ pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig);
+ }
+ if(sp->hdrDigest) {
+ debug(2, "hdr_dig=%x", pq->pdu.hdr_dig);
+ iv->iov_base = &pp->hdr_dig;
+ iv->iov_len = sizeof(int);
+ iv++;
+ }
+ if(pq->pdu.ds) {
+ iv->iov_base = pp->ds;
+ iv->iov_len = pp->ds_len;
+ while(iv->iov_len & 03) // the specs say it must be int alligned
+ 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",
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);
@@ -243,20 +265,12 @@ isc_sendPDU(isc_session_t *sp, pduq_t *pq)
if(error == 0) {
sp->stats.nsent++;
getbintime(&sp->stats.t_sent);
-#else /* USE_MBUF */
- if ((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
- m_freem(mh);
- return (error);
-#endif /* USE_MBUF */
+
}
-#ifndef USE_MBUF
+
return error;
-#else /* USE_MBUF */
- sp->stats.nsent++;
- getbintime(&sp->stats.t_sent);
- return 0;
-#endif /* USE_MBUF */
}
+#endif /* USE_MBUF */
/*
| wait till a PDU header is received
@@ -312,10 +326,10 @@ so_getbhs(isc_session_t *sp)
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=%d iov.iov_len=%zd so_state=%x",
error,
sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
- error = EAGAIN; // EPIPE;
}
return error;
@@ -379,7 +393,7 @@ so_recv(isc_session_t *sp, pduq_t *pq)
len, sp->opt.targetAddress, sp->opt.targetName);
#endif
/*
- | XXX: this will realy screwup the stream.
+ | 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.
@@ -388,13 +402,55 @@ so_recv(isc_session_t *sp, pduq_t *pq)
goto out;
}
if(len) {
- int flags;
+ int flags = MSG_WAITALL;
+ struct mbuf **mp;
+
+ mp = &pq->mp;
uio->uio_resid = len;
uio->uio_td = curthread; // why ...
- flags = MSG_WAITALL;
-
- error = soreceive(so, NULL, uio, &pq->mp, NULL, &flags);
+ 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%x 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);
+ }
+ }
+ }
+ }
+ error = soreceive(so, NULL, uio, mp, NULL, &flags);
//if(error == EAGAIN)
// XXX: this needs work! it hangs iscontrol
if(error || uio->uio_resid)
@@ -432,6 +488,7 @@ so_recv(isc_session_t *sp, pduq_t *pq)
error = EPIPE;
return error;
}
+
/*
| wait for something to arrive.
| and if the pdu is without errors, process it.
@@ -451,7 +508,11 @@ so_input(isc_session_t *sp)
/*
| now read the rest.
*/
- pq = pdu_alloc(sp->isc, 1); // OK to WAIT
+ 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
+ }
pq->pdu.ipdu.bhs = sp->bhs;
pq->len = sizeof(bhs_t); // so far only the header was read
error = so_recv(sp, pq);
@@ -484,12 +545,11 @@ 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) {
+ 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);
@@ -497,27 +557,22 @@ isc_soc(void *vp)
}
error = so_input(sp);
if(error == 0) {
-#ifdef ISC_OWAITING
mtx_lock(&sp->io_mtx);
if(sp->flags & ISC_OWAITING) {
- sp->flags &= ~ISC_OWAITING;
- }
wakeup(&sp->flags);
+ }
mtx_unlock(&sp->io_mtx);
-#else
- wakeup(&sp->flags);
-#endif
-
- } else if(error == EPIPE)
+ } 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",
- sp->flags, so->so_count, so->so_state, error);
+ 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);
psignal(sp->proc, sp->signal);
@@ -534,36 +589,46 @@ isc_soc(void *vp)
*/
// do we need this mutex ...?
mtx_lock(&sp->io_mtx);
- sp->flags &= ~ISC_CON_RUNNING;
+ 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 = 5;
+ 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);
- sdebug(4, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
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);
fputsock(sp->soc);
sp->soc = NULL;
sp->fp = NULL;
+
+ sdebug(3, "done");
}
void
@@ -571,6 +636,7 @@ isc_start_receiver(isc_session_t *sp)
{
debug_called(8);
- sp->flags |= ISC_CON_RUN;
+ sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
+
kproc_create(isc_soc, sp, &sp->soc_proc, 0, 0, "iscsi%d", sp->sid);
}
diff --git a/sys/dev/iscsi/initiator/isc_subr.c b/sys/dev/iscsi/initiator/isc_subr.c
index 333ee72..413a0b3 100644
--- a/sys/dev/iscsi/initiator/isc_subr.c
+++ b/sys/dev/iscsi/initiator/isc_subr.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,8 +58,6 @@ __FBSDID("$FreeBSD$");
#include <dev/iscsi/initiator/iscsi.h>
#include <dev/iscsi/initiator/iscsivar.h>
-MALLOC_DEFINE(M_PDU, "iSCSI pdu", "iSCSI driver");
-
static char *
i_strdupin(char *s, size_t maxlen)
{
diff --git a/sys/dev/iscsi/initiator/iscsi.c b/sys/dev/iscsi/initiator/iscsi.c
index 1b0b00c..2296989 100644
--- a/sys/dev/iscsi/initiator/iscsi.c
+++ b/sys/dev/iscsi/initiator/iscsi.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
#include <dev/iscsi/initiator/iscsi.h>
#include <dev/iscsi/initiator/iscsivar.h>
-static char *iscsi_driver_version = "2.0.99";
+static char *iscsi_driver_version = "2.1.0";
static struct isc_softc isc;
@@ -296,6 +296,15 @@ iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName);
uiomove(buf, strlen(buf), uio);
}
+ sprintf(buf, "%d/%d /---- free -----/\n", sc->npdu_alloc, sc->npdu_max);
+ i = 0;
+ uiomove(buf, strlen(buf), uio);
+ TAILQ_FOREACH(pq, &sc->freepdu, pq_link) {
+ if(uio->uio_resid == 0)
+ return 0;
+ sprintf(buf, "%03d] %06x\n", i++, ntohl(pq->pdu.ipdu.bhs.itt));
+ uiomove(buf, strlen(buf), uio);
+ }
}
else {
int i = 0;
@@ -421,27 +430,37 @@ i_send(struct cdev *dev, caddr_t arg, struct thread *td)
if(sp->soc == NULL)
return ENOTCONN;
- if((pq = pdu_alloc(sc, 0)) == NULL)
+ if((pq = pdu_alloc(sc, M_NOWAIT)) == NULL)
return EAGAIN;
pp = &pq->pdu;
-
pq->pdu = *(pdu_t *)arg;
if((error = i_prepPDU(sp, pq)) != 0)
- return error;
+ goto out;
- sdebug(4, "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_WAITOK);
+ 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;
+ }
if(pp->ahs_len) {
n = pp->ahs_len;
- copyin(pp->ahs, bp, n);
+ error = copyin(pp->ahs, bp, n);
+ if(error != 0) {
+ sdebug(3, "copyin ahs: error=%d", error);
+ goto out;
+ }
pp->ahs = (ahs_t *)bp;
bp += n;
}
if(pp->ds_len) {
n = pp->ds_len;
- copyin(pp->ds, bp, n); // can fail ...
+ error = copyin(pp->ds, bp, n);
+ if(error != 0) {
+ sdebug(3, "copyin ds: error=%d", error);
+ goto out;
+ }
pp->ds = bp;
bp += n;
while(n & 03) {
@@ -451,6 +470,13 @@ 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);
return error;
}
@@ -475,6 +501,7 @@ 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) {
@@ -487,7 +514,7 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
}
mtx_unlock(&sp->rsp_mtx);
- sdebug(3, "cnt=%d", cnt);
+ sdebug(4, "cnt=%d", cnt);
if(pq == NULL) {
error = ENOTCONN;
@@ -600,11 +627,9 @@ i_create_session(struct cdev *dev, int *ndev)
sp->opt.maxBurstLength = 65536; // 64k
- sdebug(2, "sessionID=%d", n);
+ sdebug(2, "sessionID=%d sp=%p", n, sp);
error = ism_start(sp);
- sdebug(2, "error=%d", error);
-
return error;
}
@@ -648,7 +673,7 @@ iscsi_shutdown(void *v)
return;
}
if(sc->eh == NULL)
- debug(2, "sc->eh is NULL!");
+ debug(2, "sc->eh is NULL");
else {
EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
debug(2, "done n=%d", sc->nsess);
@@ -658,6 +683,42 @@ iscsi_shutdown(void *v)
debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
n++;
}
+ 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)
+{
+ pduq_t *pq;
+
+ debug_called(8);
+
+ if(sc->pdu_zone != NULL) {
+ TAILQ_FOREACH(pq, &sc->freepdu, pq_link) {
+ TAILQ_REMOVE(&sc->freepdu, pq, pq_link);
+ uma_zfree(sc->pdu_zone, pq);
+ }
+ uma_zdestroy(sc->pdu_zone);
+ sc->pdu_zone = NULL;
+ }
}
static void
@@ -673,15 +734,9 @@ iscsi_start(void)
sc->dev->si_drv1 = sc;
TAILQ_INIT(&sc->isc_sess);
+ if(init_pdus(sc) != 0)
+ xdebug("pdu zone init failed!"); // XXX: should cause terminal failure ...
- 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");
- // XXX: and now what?
- }
- uma_zone_set_max(sc->pdu_zone, MAX_PDUS*2+1);
mtx_init(&sc->mtx, "iscsi", NULL, MTX_DEF);
mtx_init(&sc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF);
@@ -693,9 +748,12 @@ iscsi_start(void)
#else
sc->cam_sim = NULL;
#endif
+
+#ifdef DO_EVENTHANDLER
if((sc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
xdebug("shutdown event registration failed\n");
+#endif
/*
| sysctl stuff
*/
@@ -734,6 +792,8 @@ iscsi_start(void)
&sc->nsess,
sizeof(sc->nsess),
"number of active session");
+
+ printf("iscsi: version %s\n", iscsi_driver_version);
}
/*
@@ -762,13 +822,15 @@ iscsi_stop(void)
mtx_destroy(&sc->mtx);
mtx_destroy(&sc->pdu_mtx);
- uma_zdestroy(sc->pdu_zone);
+ free_pdus(sc);
if(sc->dev)
destroy_dev(sc->dev);
if(sysctl_ctx_free(&sc->clist))
xdebug("sysctl_ctx_free failed");
+
+ iscsi_shutdown(sc); // XXX: check EVENTHANDLER_ ...
}
static int
@@ -801,11 +863,27 @@ iscsi_modevent(module_t mod, int what, void *arg)
}
return 0;
}
+
moduledata_t iscsi_mod = {
"iscsi",
(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, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_DEPEND(iscsi, cam, 1, 1, 1);
diff --git a/sys/dev/iscsi/initiator/iscsi.h b/sys/dev/iscsi/initiator/iscsi.h
index cbd9f22..2eace68 100644
--- a/sys/dev/iscsi/initiator/iscsi.h
+++ b/sys/dev/iscsi/initiator/iscsi.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -294,6 +294,103 @@ typedef struct async {
} 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
+ 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;
diff --git a/sys/dev/iscsi/initiator/iscsi_subr.c b/sys/dev/iscsi/initiator/iscsi_subr.c
index 6abe1f6..9ef92d5 100644
--- a/sys/dev/iscsi/initiator/iscsi_subr.c
+++ b/sys/dev/iscsi/initiator/iscsi_subr.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -93,11 +93,20 @@ iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
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, 1);
+ wpq = pdu_alloc(sp->isc, M_NOWAIT); // testing ...
if(wpq == NULL) {
- // should not happen if above is 1
- sdebug(1, "now what?");
- return;
+ 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...");
+#if __FreeBSD_version >= 700000
+ pause("isc_r2t", 5*hz);
+#else
+ tsleep(sp->isc, 0, "isc_r2t", 5*hz);
+#endif
+ }
}
cmd = &wpq->pdu.ipdu.data_out;
cmd->opcode = ISCSI_WRITE_DATA;
@@ -220,7 +229,7 @@ _scsi_done(struct isc_softc *isp, u_int response, u_int status, union ccb *ccb,
//case 0x22: // Command Terminated
//case 0x30: // ACA Active
//case 0x40: // Task Aborted
- ccb_h->status = CAM_REQ_ABORTED;
+ ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED;
}
break;
@@ -249,6 +258,7 @@ iscsi_requeue(isc_session_t *sp)
debug_called(8);
last = -1;
i = 0;
+ sp->flags |= ISC_HOLD;
while((pq = i_dqueue_hld(sp)) != NULL) {
i++;
_scsi_done(sp->isc, 0, 0x28, pq->ccb, NULL);
@@ -258,6 +268,7 @@ iscsi_requeue(isc_session_t *sp)
sdebug(2, "last=%x n=%x", last, n);
pdu_free(sp->isc, pq);
}
+ sp->flags &= ~ISC_HOLD;
return i? last: sp->sn.cmd;
}
@@ -284,6 +295,10 @@ i_pdu_flush(isc_session_t *sp)
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;
@@ -329,6 +344,14 @@ iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
}
// 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)
{
@@ -341,17 +364,22 @@ iscsi_async(isc_session_t *sp, pduq_t *pq)
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);
+ isc_stop_receiver(sp); // XXX: temporary solution
break;
case 4: // target request parameter negotiation
break;
+
default:
break;
}
@@ -430,12 +458,26 @@ 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, 1)) == NULL) { // cannot happen
+ if((pq = pdu_alloc(isp, 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...");
+#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;
@@ -523,21 +565,24 @@ scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq)
switch(pq->pdu.ipdu.bhs.opcode) {
case ISCSI_READ_DATA: // SCSI Data in
{
- caddr_t bp = mtod(pq->mp, caddr_t);
+ 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",
- csio->data_ptr, bp,
- ntohl(cmd->edtlen), pq->pdu.ds_len);
+ 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);
diff --git a/sys/dev/iscsi/initiator/iscsivar.h b/sys/dev/iscsi/initiator/iscsivar.h
index fa54b19..128a745 100644
--- a/sys/dev/iscsi/initiator/iscsivar.h
+++ b/sys/dev/iscsi/initiator/iscsivar.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2005-2007 Daniel Braniss <danny@cs.huji.ac.il>
+ * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@ extern int iscsi_debug;
#define sdebug(level, fmt, args...)
#endif /* ISCSI_INITIATOR_DEBUG */
-#define xdebug(fmt, args...) printf("%s: " fmt "\n", __func__ , ##args)
+#define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args)
#define MAX_SESSIONS ISCSI_MAX_TARGETS
@@ -61,13 +61,13 @@ MALLOC_DECLARE(M_PDU);
#define ISC_SM_RUN BIT(0)
#define ISC_SM_RUNNING BIT(1)
-#define ISC_SM_HOLD BIT(2)
+#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_IWAITING BIT(6)
-//#define ISC_OWAITING BIT(7)
+#define ISC_OQNOTEMPTY BIT(6)
+#define ISC_OWAITING BIT(7)
#define ISC_FFPHASE BIT(8)
#define ISC_FFPWAIT BIT(9)
@@ -76,6 +76,9 @@ MALLOC_DECLARE(M_PDU);
#define ISC_FROZEN BIT(12)
#define ISC_STALLED BIT(13)
+#define ISC_HOLD BIT(14)
+#define ISC_HOLDED BIT(15)
+
#define ISC_SHUTDOWN BIT(31)
/*
@@ -100,6 +103,9 @@ struct i_stats {
/*
| one per 'session'
*/
+
+typedef TAILQ_HEAD(, pduq) queue_t;
+
typedef struct isc_session {
TAILQ_ENTRY(isc_session) sp_link;
int flags;
@@ -137,13 +143,13 @@ typedef struct isc_session {
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;
- TAILQ_HEAD(,pduq) rsp;
- TAILQ_HEAD(,pduq) rsv;
- TAILQ_HEAD(,pduq) csnd;
- TAILQ_HEAD(,pduq) isnd;
- TAILQ_HEAD(,pduq) wsnd;
- TAILQ_HEAD(,pduq) hld;
/*
| negotiable values
*/
@@ -159,6 +165,7 @@ typedef struct isc_session {
*/
struct sysctl_ctx_list clist;
struct sysctl_oid *oid;
+ int douio; //XXX: turn on/off uio on read
} isc_session_t;
typedef struct pduq {
@@ -173,6 +180,7 @@ typedef struct pduq {
struct iovec iov[5]; // XXX: careful ...
struct mbuf *mp;
struct bintime ts;
+ queue_t *pduq;
} pduq_t;
struct isc_softc {
@@ -190,8 +198,9 @@ struct isc_softc {
#ifdef ISCSI_INITIATOR_DEBUG
int npdu_alloc, npdu_max; // for instrumentation
#endif
-#define MAX_PDUS 256 // XXX: at the moment this is arbitrary
+#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
*/
@@ -291,11 +300,17 @@ pdu_alloc(struct isc_softc *isc, int wait)
{
pduq_t *pq;
- pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait? M_WAITOK: M_NOWAIT);
- if(pq == NULL) {
- // will not happend if M_WAITOK ...
+ mtx_lock(&isc->pdu_mtx);
+ if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) {
+ mtx_unlock(&isc->pdu_mtx);
+ pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/);
+ }
+ else {
+ TAILQ_REMOVE(&isc->freepdu, pq, pq_link);
mtx_unlock(&isc->pdu_mtx);
- debug(1, "out of mem");
+ }
+ if(pq == NULL) {
+ debug(7, "out of mem");
return NULL;
}
#ifdef ISCSI_INITIATOR_DEBUG
@@ -315,10 +330,12 @@ 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_ISCSI);
+#endif
mtx_lock(&isc->pdu_mtx);
- uma_zfree(isc->pdu_zone, pq);
+ TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link);
#ifdef ISCSI_INITIATOR_DEBUG
isc->npdu_alloc--;
#endif
@@ -460,20 +477,32 @@ i_dqueue_snd(isc_session_t *sp, int which)
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 :-)
*/
OpenPOWER on IntegriCloud