Module Name: src
Committed By: mlelstv
Date: Sun May 29 13:51:16 UTC 2016
Modified Files:
src/sys/dev/iscsi: iscsi_globals.h iscsi_ioctl.c iscsi_main.c
iscsi_rcv.c iscsi_send.c iscsi_text.c iscsi_utils.c
Log Message:
Several improvements to the ISCSI driver.
- Enable debug messages but set log level to be quiet. Provide a
system (hw.iscsi.debug) to set the log level at run time.
- Replace old tsleep/wakeup synchronization with mutexes and condvars.
- Defer actions from callouts (basically timeouts) to the cleanup thread.
- Protect lists and unique ids with mutexes. protect connection usecount
by using atomic operations.
- Assert kernel lock when calling into scsipi and network code.
- Use this to make send/receive/cleanup threads MPSAFE.
- Fix handling of out-of-CCB/out-of-PDU conditions against the scsipi layer.
- Bump number of PDUs to 128 to avoid virtually all out-of-PDU conditions
- Make use of softc structure for attach/detach operations.
- Track open file handles to prevent detach when busy.
- Move some global variables to make them static.
- Fix 'Overlapping Commands Attempted' error by marking commands as
simply ordered (ATTR_SIMPLE) like FreeBSD.
To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/dev/iscsi/iscsi_globals.h \
src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/iscsi/iscsi_main.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/iscsi/iscsi_rcv.c
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/iscsi/iscsi_send.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/iscsi/iscsi_text.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/iscsi/iscsi_utils.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/iscsi/iscsi_globals.h
diff -u src/sys/dev/iscsi/iscsi_globals.h:1.13 src/sys/dev/iscsi/iscsi_globals.h:1.14
--- src/sys/dev/iscsi/iscsi_globals.h:1.13 Sat May 30 20:09:47 2015
+++ src/sys/dev/iscsi/iscsi_globals.h Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_globals.h,v 1.13 2015/05/30 20:09:47 joerg Exp $ */
+/* $NetBSD: iscsi_globals.h,v 1.14 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
/* ------------------------ Code selection constants ------------------------ */
-/* #define ISCSI_DEBUG 1 */
+#define ISCSI_DEBUG 0
/* ------------------------- Global Constants ----------------------------- */
@@ -96,7 +96,7 @@ now only in iscsi_send.c.
high values of First/MaxBurstLength and small values of
MaxRecvDataSegmentLength of the target.
*/
-#define PDUS_PER_CONNECTION 64 /* ToDo: Reasonable number?? */
+#define PDUS_PER_CONNECTION 128 /* ToDo: Reasonable number?? */
/* max outstanding serial nums before we give up on the connection */
#define SERNUM_BUFFER_LENGTH (CCBS_PER_SESSION / 2) /* ToDo: Reasonable?? */
@@ -181,7 +181,6 @@ typedef enum {
typedef enum {
PDUDISP_UNUSED, /* 0 = In free pool */
- PDUDISP_SIGNAL, /* Free this PDU when done and wakeup(pdu) */
PDUDISP_FREE, /* Free this PDU when done */
PDUDISP_WAIT /* Waiting for acknowledge */
} pdu_disp_t;
@@ -253,6 +252,7 @@ struct ccb_s {
ccb_disp_t disp; /* what to do with this ccb */
struct callout timeout; /* To make sure it isn't lost */
+ TAILQ_ENTRY(ccb_s) tchain;
int num_timeouts;
/* How often we've sent out SNACK without answer */
int total_tries;
@@ -309,6 +309,11 @@ typedef struct ccb_list_s ccb_list_t;
struct connection_s {
TAILQ_ENTRY(connection_s) connections;
+ kmutex_t lock;
+ kcondvar_t conn_cv;
+ kcondvar_t ccb_cv;
+ kcondvar_t idle_cv;
+
pdu_list_t pdu_pool; /* the free PDU pool */
ccb_list_t ccbs_waiting;
@@ -358,7 +363,7 @@ struct connection_s {
/* if closing down: status */
int recover; /* recovery count */
/* (reset on first successful data transfer) */
- int usecount; /* number of active CCBs */
+ unsigned usecount; /* number of active CCBs */
bool destroy; /* conn will be destroyed */
bool in_session;
@@ -367,6 +372,7 @@ struct connection_s {
/* status of logout (for recovery) */
struct callout timeout;
/* Timeout for checking if connection is dead */
+ TAILQ_ENTRY(connection_s) tchain;
int num_timeouts;
/* How often we've sent out a NOP without answer */
uint32_t idle_timeout_val;
@@ -402,6 +408,10 @@ struct session_s {
/* local stuff */
TAILQ_ENTRY(session_s) sessions; /* the list of sessions */
+ kmutex_t lock;
+ kcondvar_t sess_cv;
+ kcondvar_t ccb_cv;
+
ccb_list_t ccb_pool; /* The free CCB pool */
ccb_list_t ccbs_throttled;
/* CCBs waiting for MaxCmdSN to increase */
@@ -457,18 +467,6 @@ typedef struct session_list_s session_li
/*
- The softc structure. This driver doesn't really need one, because there's
- always just one instance, and for the time being it's only loaded as
- an LKM (which doesn't create a softc), but we need one to put into the
- scsipi interface structures, so here it is.
-*/
-
-typedef struct iscsi_softc {
- device_t sc_dev;
-} iscsi_softc_t;
-
-
-/*
Event notification structures
*/
@@ -502,7 +500,9 @@ typedef struct event_handler_list_s even
/* /dev/iscsi0 state */
struct iscsifd {
- char dummy;
+ TAILQ_ENTRY(iscsifd) link;
+ device_t dev;
+ int unit;
};
/* ------------------------- Global Variables ----------------------------- */
@@ -512,12 +512,7 @@ struct iscsifd {
extern struct cfattach iscsi_ca; /* the device attach structure */
extern session_list_t iscsi_sessions; /* the list of sessions */
-
-extern connection_list_t iscsi_cleanupc_list; /* connections to clean up */
-extern session_list_t iscsi_cleanups_list; /* sessions to clean up */
extern bool iscsi_detaching; /* signal to cleanup thread it should exit */
-extern struct lwp *iscsi_cleanproc; /* pointer to cleanup proc */
-
extern uint32_t iscsi_num_send_threads; /* the number of active send threads */
extern uint8_t iscsi_InitiatorName[ISCSI_STRING_LENGTH];
@@ -539,7 +534,7 @@ extern int iscsi_debug_level; /* How muc
#define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
conn ? conn->session->id : -1, \
conn ? conn->id : -1); printf x ;}}
-void dump(void *buf, int len);
+void iscsi_hexdump(void *buf, int len);
#define STATIC static
@@ -548,7 +543,7 @@ void dump(void *buf, int len);
#define DEBOUT(x)
#define DEB(lev,x)
#define DEBC(conn,lev,x)
-#define dump(a,b)
+#define iscsi_hexdump(a,b)
#define STATIC static
@@ -634,6 +629,11 @@ sn_a_le_b(uint32_t a, uint32_t b)
/* in iscsi_ioctl.c */
+void iscsi_init_cleanup(void);
+void iscsi_destroy_cleanup(void);
+void iscsi_notify_cleanup(void);
+
+
/* Parameter for logout is reason code in logout PDU, -1 for don't send logout */
#define NO_LOGOUT -1
#define LOGOUT_SESSION 0
@@ -646,7 +646,7 @@ void kill_connection(connection_t *, uin
void kill_session(session_t *, uint32_t, int, bool);
void kill_all_sessions(void);
void handle_connection_error(connection_t *, uint32_t, int);
-void iscsi_cleanup_thread(void *);
+void add_connection_cleanup(connection_t *);
#ifndef ISCSI_MINIMAL
uint32_t map_databuf(struct proc *, void **, uint32_t);
@@ -664,7 +664,7 @@ connection_t *find_connection(session_t
int iscsidetach(device_t, int);
void iscsi_done(ccb_t *);
-int map_session(session_t *);
+int map_session(session_t *, device_t);
int unmap_session(session_t *);
/* in iscsi_send.c */
@@ -694,8 +694,11 @@ void send_command(ccb_t *, ccb_disp_t, b
int send_io_command(session_t *, uint64_t, scsireq_t *, bool, uint32_t);
#endif
-void connection_timeout(void *);
-void ccb_timeout(void *);
+void connection_timeout_co(void *);
+void ccb_timeout_co(void *);
+
+void connection_timeout(connection_t *);
+void ccb_timeout(ccb_t *);
/* in iscsi_rcv.c */
Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.13 src/sys/dev/iscsi/iscsi_ioctl.c:1.14
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.13 Sat Sep 19 18:32:42 2015
+++ src/sys/dev/iscsi/iscsi_ioctl.c Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_ioctl.c,v 1.13 2015/09/19 18:32:42 dholland Exp $ */
+/* $NetBSD: iscsi_ioctl.c,v 1.14 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -40,12 +40,29 @@
#include <uvm/uvm_pmap.h>
#endif
+static kmutex_t iscsi_cleanup_mtx;
+static kcondvar_t iscsi_cleanup_cv;
+static kcondvar_t iscsi_event_cv;
+static struct lwp *iscsi_cleanproc = NULL;
+
static uint16_t current_id = 0; /* Global session ID counter */
/* list of event handlers */
static event_handler_list_t event_handlers =
TAILQ_HEAD_INITIALIZER(event_handlers);
+static connection_list_t iscsi_timeout_conn_list =
+ TAILQ_HEAD_INITIALIZER(iscsi_timeout_conn_list);
+
+static ccb_list_t iscsi_timeout_ccb_list =
+ TAILQ_HEAD_INITIALIZER(iscsi_timeout_ccb_list);
+
+static session_list_t iscsi_cleanups_list =
+ TAILQ_HEAD_INITIALIZER(iscsi_cleanups_list);
+
+static connection_list_t iscsi_cleanupc_list =
+ TAILQ_HEAD_INITIALIZER(iscsi_cleanupc_list);
+
static uint32_t handler_id = 0; /* Handler ID counter */
/* -------------------------------------------------------------------------- */
@@ -64,11 +81,13 @@ static uint32_t handler_id = 0; /* Handl
*/
-STATIC event_handler_t *
+static event_handler_t *
find_handler(uint32_t id)
{
event_handler_t *curr;
+ KASSERT(mutex_owned(&iscsi_cleanup_mtx));
+
TAILQ_FOREACH(curr, &event_handlers, link)
if (curr->id == id)
break;
@@ -85,12 +104,11 @@ find_handler(uint32_t id)
* par The parameter.
*/
-STATIC void
+static void
register_event(iscsi_register_event_parameters_t *par)
{
event_handler_t *handler;
int was_empty;
- int s;
handler = malloc(sizeof(event_handler_t), M_DEVBUF, M_WAITOK | M_ZERO);
if (handler == NULL) {
@@ -101,21 +119,19 @@ register_event(iscsi_register_event_para
TAILQ_INIT(&handler->events);
+ mutex_enter(&iscsi_cleanup_mtx);
/* create a unique ID */
- s = splbio();
do {
++handler_id;
} while (!handler_id || find_handler(handler_id) != NULL);
par->event_id = handler->id = handler_id;
was_empty = TAILQ_FIRST(&event_handlers) == NULL;
-
TAILQ_INSERT_TAIL(&event_handlers, handler, link);
+ mutex_exit(&iscsi_cleanup_mtx);
- if (was_empty) {
- wakeup(&iscsi_cleanupc_list);
- }
- splx(s);
+ if (was_empty)
+ iscsi_notify_cleanup();
par->status = ISCSI_STATUS_SUCCESS;
DEB(5, ("Register Event OK, ID %d\n", par->event_id));
@@ -130,27 +146,27 @@ register_event(iscsi_register_event_para
* par The parameter.
*/
-STATIC void
+static void
deregister_event(iscsi_register_event_parameters_t *par)
{
event_handler_t *handler;
event_t *evt;
- int s;
+ mutex_enter(&iscsi_cleanup_mtx);
handler = find_handler(par->event_id);
if (handler == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEB(1, ("Deregister Event ID %d not found\n", par->event_id));
par->status = ISCSI_STATUS_INVALID_EVENT_ID;
return;
}
- s = splbio();
TAILQ_REMOVE(&event_handlers, handler, link);
- splx(s);
+ mutex_exit(&iscsi_cleanup_mtx);
if (handler->waiter != NULL) {
handler->waiter->status = ISCSI_STATUS_EVENT_DEREGISTERED;
- wakeup(handler->waiter);
+ cv_broadcast(&iscsi_event_cv);
}
while ((evt = TAILQ_FIRST(&handler->events)) != NULL) {
@@ -173,19 +189,23 @@ deregister_event(iscsi_register_event_pa
* wait Wait for event if true
*/
-STATIC void
+static void
check_event(iscsi_wait_event_parameters_t *par, bool wait)
{
event_handler_t *handler;
event_t *evt;
+ int rc;
+ mutex_enter(&iscsi_cleanup_mtx);
handler = find_handler(par->event_id);
if (handler == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Wait Event ID %d not found\n", par->event_id));
par->status = ISCSI_STATUS_INVALID_EVENT_ID;
return;
}
if (handler->waiter != NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Wait Event ID %d already waiting\n", par->event_id));
par->status = ISCSI_STATUS_EVENT_WAITING;
return;
@@ -194,27 +214,27 @@ check_event(iscsi_wait_event_parameters_
DEB(99, ("Wait Event ID %d\n", par->event_id));
do {
- int s = splbio();
evt = TAILQ_FIRST(&handler->events);
if (evt != NULL) {
TAILQ_REMOVE(&handler->events, evt, link);
- splx(s);
} else {
if (!wait) {
- splx(s);
par->status = ISCSI_STATUS_LIST_EMPTY;
return;
}
if (par->status != ISCSI_STATUS_SUCCESS) {
- splx(s);
return;
}
handler->waiter = par;
- splx(s);
- if (tsleep(par, PRIBIO | PCATCH, "iscsievtwait", 0))
+ rc = cv_wait_sig(&iscsi_event_cv, &iscsi_cleanup_mtx);
+ if (rc) {
+ mutex_exit(&iscsi_cleanup_mtx);
+ par->status = ISCSI_STATUS_LIST_EMPTY;
return;
+ }
}
} while (evt == NULL);
+ mutex_exit(&iscsi_cleanup_mtx);
par->connection_id = evt->connection_id;
par->session_id = evt->session_id;
@@ -242,16 +262,16 @@ add_event(iscsi_event_t kind, uint32_t s
{
event_handler_t *curr;
event_t *evt;
- int s;
DEB(9, ("Add_event kind %d, sid %d, cid %d, reason %d\n",
kind, sid, cid, reason));
- s = splbio();
+ mutex_enter(&iscsi_cleanup_mtx);
TAILQ_FOREACH(curr, &event_handlers, link) {
- evt = malloc(sizeof(*evt), M_TEMP, M_WAITOK);
+ evt = malloc(sizeof(*evt), M_TEMP, M_NOWAIT);
if (evt == NULL) {
- panic("iSCSI: add_event failed to alloc memory");
+ DEBOUT(("Cannot allocate event\n"));
+ break;
}
evt->event_kind = kind;
evt->session_id = sid;
@@ -260,11 +280,11 @@ add_event(iscsi_event_t kind, uint32_t s
TAILQ_INSERT_TAIL(&curr->events, evt, link);
if (curr->waiter != NULL) {
- wakeup(curr->waiter);
curr->waiter = NULL;
+ cv_broadcast(&iscsi_event_cv);
}
}
- splx(s);
+ mutex_exit(&iscsi_cleanup_mtx);
}
@@ -280,15 +300,16 @@ add_event(iscsi_event_t kind, uint32_t s
* Note that this will not detect dead handlers if no events are pending,
* but we don't care as long as events don't accumulate in the list.
*
- * this function must be called at splbio
*/
-STATIC void
+static void
check_event_handlers(void)
{
event_handler_t *curr, *next;
event_t *evt;
+ KASSERT(mutex_owned(&iscsi_cleanup_mtx));
+
for (curr = TAILQ_FIRST(&event_handlers); curr != NULL; curr = next) {
next = TAILQ_NEXT(curr, link);
evt = TAILQ_FIRST(&curr->events);
@@ -322,7 +343,7 @@ check_event_handlers(void)
*
*/
-STATIC int
+static int
get_socket(int fdes, struct file **fpp)
{
struct file *fp;
@@ -352,7 +373,7 @@ get_socket(int fdes, struct file **fpp)
*
*/
-STATIC void
+static void
release_socket(struct file *fp)
{
/* Add the reference */
@@ -375,14 +396,13 @@ session_t *
find_session(uint32_t id)
{
session_t *curr;
- int s;
- s = splbio();
+ KASSERT(mutex_owned(&iscsi_cleanup_mtx));
+
TAILQ_FOREACH(curr, &iscsi_sessions, sessions)
if (curr->id == id) {
break;
}
- splx(s);
return curr;
}
@@ -400,14 +420,13 @@ connection_t *
find_connection(session_t *session, uint32_t id)
{
connection_t *curr;
- int s;
- s = splbio();
+ KASSERT(mutex_owned(&iscsi_cleanup_mtx));
+
TAILQ_FOREACH(curr, &session->conn_list, connections)
if (curr->id == id) {
break;
}
- splx(s);
return curr;
}
@@ -427,12 +446,12 @@ void
kill_connection(connection_t *conn, uint32_t status, int logout, bool recover)
{
session_t *sess = conn->session;
- int s;
DEBC(conn, 1, ("Kill_connection: terminating=%d, status=%d, logout=%d, "
"state=%d\n",
conn->terminating, status, logout, conn->state));
+ mutex_enter(&iscsi_cleanup_mtx);
if (recover &&
!conn->destroy &&
conn->recover > MAX_RECOVERY_ATTEMPTS) {
@@ -443,13 +462,11 @@ kill_connection(connection_t *conn, uint
if (!recover || conn->destroy) {
- s = splbio();
if (conn->in_session) {
conn->in_session = FALSE;
TAILQ_REMOVE(&sess->conn_list, conn, connections);
sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
}
- splx(s);
if (!conn->destroy) {
DEBC(conn, 1, ("Kill_connection setting destroy flag\n"));
@@ -457,14 +474,17 @@ kill_connection(connection_t *conn, uint
}
/* in case it was already terminated earlier and rcv/send-threads */
/* are waiting */
- wakeup(conn);
+ cv_broadcast(&conn->idle_cv);
}
/* Don't recurse */
if (conn->terminating) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBC(conn, 1, ("Kill_connection exiting (already terminating)\n"));
return;
}
+ conn->terminating = status;
+ mutex_exit(&iscsi_cleanup_mtx);
if (conn->state == ST_FULL_FEATURE) {
sess->active_connections--;
@@ -488,6 +508,7 @@ kill_connection(connection_t *conn, uint
logout = LOGOUT_SESSION;
}
if (!send_logout(conn, conn, logout, FALSE)) {
+ conn->terminating = ISCSI_STATUS_SUCCESS;
return;
}
/*
@@ -499,11 +520,10 @@ kill_connection(connection_t *conn, uint
}
}
- conn->terminating = status;
conn->state = ST_SETTLING;
/* let send thread take over next step of cleanup */
- wakeup(&conn->pdus_to_send);
+ cv_broadcast(&conn->conn_cv);
DEBC(conn, 5, ("kill_connection returns\n"));
}
@@ -525,19 +545,28 @@ kill_session(session_t *session, uint32_
{
connection_t *curr;
ccb_t *ccb;
- int s;
DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n",
session->id, status, logout, recover));
+ mutex_enter(&iscsi_cleanup_mtx);
+ if (session->terminating) {
+ mutex_exit(&iscsi_cleanup_mtx);
+ DEB(5, ("Session is being killed with status %d\n",session->terminating));
+ return;
+ }
+
/*
* don't do anything if session isn't established yet, termination will be
* handled elsewhere
*/
if (session->sessions.tqe_next == NULL &&
session->sessions.tqe_prev == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
return;
}
+ session->terminating = status;
+ mutex_exit(&iscsi_cleanup_mtx);
if (recover) {
/*
@@ -553,35 +582,31 @@ kill_session(session_t *session, uint32_
}
/* don't allow the session to disappear when the target */
/* requested the logout */
+ session->terminating = ISCSI_STATUS_SUCCESS;
return;
}
/* remove from session list */
- s = splbio();
+ mutex_enter(&iscsi_cleanup_mtx);
TAILQ_REMOVE(&iscsi_sessions, session, sessions);
- splx(s);
session->sessions.tqe_next = NULL;
session->sessions.tqe_prev = NULL;
+ mutex_exit(&iscsi_cleanup_mtx);
/* complete any throttled CCBs */
- s = splbio();
+ mutex_enter(&session->lock);
while ((ccb = TAILQ_FIRST(&session->ccbs_throttled)) != NULL) {
throttle_ccb(ccb, FALSE);
- splx(s);
+ mutex_exit(&session->lock);
wake_ccb(ccb, ISCSI_STATUS_LOGOUT);
- s = splbio();
+ mutex_enter(&session->lock);
}
- splx(s);
+ mutex_exit(&session->lock);
/*
- * unmap first to give the system an opportunity to flush its buffers,
- * but don't try to unmap if it's a forced termination (connection is dead)
- * to avoid waiting for pending commands that can't complete anyway.
+ * unmap first to give the system an opportunity to flush its buffers
*/
- if (logout >= 0) {
- unmap_session(session);
- DEB(5, ("Unmap Returns\n"));
- }
+ unmap_session(session);
/* kill all connections */
while ((curr = TAILQ_FIRST(&session->conn_list)) != NULL) {
@@ -609,12 +634,12 @@ kill_session(session_t *session, uint32_
* <0 on failure, connection is still terminating
*/
-STATIC int
+static int
create_connection(iscsi_login_parameters_t *par, session_t *session,
struct lwp *l)
{
connection_t *connection;
- int rc, s;
+ int rc;
DEB(1, ("Create Connection for Session %d\n", session->id));
@@ -633,13 +658,14 @@ create_connection(iscsi_login_parameters
return EIO;
}
+ mutex_enter(&iscsi_cleanup_mtx);
/* create a unique ID */
do {
++session->conn_id;
} while (!session->conn_id ||
find_connection(session, session->conn_id) != NULL);
-
par->connection_id = connection->id = session->conn_id;
+ mutex_exit(&iscsi_cleanup_mtx);
DEB(99, ("Connection ID = %d\n", connection->id));
connection->session = session;
@@ -648,8 +674,13 @@ create_connection(iscsi_login_parameters
TAILQ_INIT(&connection->pdus_to_send);
TAILQ_INIT(&connection->pdu_pool);
- callout_init(&connection->timeout, 0);
- callout_setfunc(&connection->timeout, connection_timeout, connection);
+ mutex_init(&connection->lock, MUTEX_DEFAULT, IPL_BIO);
+ cv_init(&connection->conn_cv, "conn");
+ cv_init(&connection->ccb_cv, "ccbwait");
+ cv_init(&connection->idle_cv, "idle");
+
+ callout_init(&connection->timeout, CALLOUT_MPSAFE);
+ callout_setfunc(&connection->timeout, connection_timeout_co, connection);
connection->idle_timeout_val = CONNECTION_IDLE_TIMEOUT;
init_sernum(&connection->StatSN_buf);
@@ -658,6 +689,10 @@ create_connection(iscsi_login_parameters
if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
DEBOUT(("Invalid socket %d\n", par->socket));
+ cv_destroy(&connection->idle_cv);
+ cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->conn_cv);
+ mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
par->status = ISCSI_STATUS_INVALID_SOCKET;
return rc;
@@ -671,19 +706,23 @@ create_connection(iscsi_login_parameters
connection->threadobj = l;
connection->login_par = par;
- /*DEBOUT (("Creating receive thread\n")); */
- if ((rc = kthread_create(PRI_NONE, 0, NULL, iscsi_rcv_thread,
+ DEB(5, ("Creating receive thread\n"));
+ if ((rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_rcv_thread,
connection, &connection->rcvproc,
"ConnRcv")) != 0) {
DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
release_socket(connection->sock);
+ cv_destroy(&connection->idle_cv);
+ cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->conn_cv);
+ mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
par->status = ISCSI_STATUS_NO_RESOURCES;
return rc;
}
- /*DEBOUT (("Creating send thread\n")); */
- if ((rc = kthread_create(PRI_NONE, 0, NULL, iscsi_send_thread,
+ DEB(5, ("Creating send thread\n"));
+ if ((rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_send_thread,
connection, &connection->sendproc,
"ConnSend")) != 0) {
DEBOUT(("Can't create send thread (rc %d)\n", rc));
@@ -702,9 +741,13 @@ create_connection(iscsi_login_parameters
closef(connection->sock);
/* give receive thread time to exit */
- tsleep(connection, PWAIT, "settle", 2 * hz);
+ kpause("settle", false, 2 * hz, NULL);
release_socket(connection->sock);
+ cv_destroy(&connection->idle_cv);
+ cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->conn_cv);
+ mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
par->status = ISCSI_STATUS_NO_RESOURCES;
return rc;
@@ -724,14 +767,12 @@ create_connection(iscsi_login_parameters
return -1;
}
- s = splbio();
connection->state = ST_FULL_FEATURE;
TAILQ_INSERT_TAIL(&session->conn_list, connection, connections);
connection->in_session = TRUE;
session->total_connections++;
session->active_connections++;
session->mru_connection = connection;
- splx(s);
DEBC(connection, 5, ("Connection created successfully!\n"));
return 0;
@@ -752,11 +793,11 @@ create_connection(iscsi_login_parameters
* <0 on failure, connection is still terminating
*/
-STATIC int
+static int
recreate_connection(iscsi_login_parameters_t *par, session_t *session,
connection_t *connection, struct lwp *l)
{
- int rc, s;
+ int rc;
ccb_t *ccb;
ccb_list_t old_waiting;
@@ -801,12 +842,10 @@ recreate_connection(iscsi_login_paramete
session->active_connections++;
TAILQ_INIT(&old_waiting);
- s = splbio();
TAILQ_CONCAT(&old_waiting, &connection->ccbs_waiting, chain);
- splx(s);
init_sernum(&connection->StatSN_buf);
- wakeup(connection);
+ cv_broadcast(&connection->idle_cv);
if ((rc = send_login(connection)) != 0) {
DEBOUT(("Login failed (rc %d)\n", rc));
@@ -823,20 +862,17 @@ recreate_connection(iscsi_login_paramete
DEBC(connection, 9, ("Re-Login successful\n"));
par->status = ISCSI_STATUS_SUCCESS;
- s = splbio();
connection->state = ST_FULL_FEATURE;
session->mru_connection = connection;
- splx(s);
while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
TAILQ_REMOVE(&old_waiting, ccb, chain);
- s = splbio();
suspend_ccb(ccb, TRUE);
- splx(s);
rc = send_task_management(connection, ccb, NULL, TASK_REASSIGN);
/* if we get an error on reassign, restart the original request */
if (rc && ccb->pdu_waiting != NULL) {
+ mutex_enter(&session->lock);
if (ccb->CmdSN < session->ExpCmdSN) {
pdu_t *pdu = ccb->pdu_waiting;
@@ -848,15 +884,16 @@ recreate_connection(iscsi_login_paramete
session->CmdSN++;
pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
}
+ mutex_exit(&session->lock);
resend_pdu(ccb);
} else {
callout_schedule(&ccb->timeout, COMMAND_TIMEOUT);
}
}
- wakeup(session);
+ cv_broadcast(&session->sess_cv);
- DEBC(connection, 5, ("Connection ReCreated successfully - status %d\n",
+ DEBC(connection, 0, ("Connection ReCreated successfully - status %d\n",
par->status));
return 0;
@@ -875,7 +912,7 @@ recreate_connection(iscsi_login_paramete
* Returns: 0 on success, else an error code.
*/
-STATIC int
+static int
check_login_pars(iscsi_login_parameters_t *par)
{
int i, n;
@@ -947,11 +984,11 @@ check_login_pars(iscsi_login_parameters_
* l IN: The lwp pointer of the caller
*/
-STATIC void
-login(iscsi_login_parameters_t *par, struct lwp *l)
+static void
+login(iscsi_login_parameters_t *par, struct lwp *l, device_t dev)
{
session_t *session;
- int rc, s;
+ int rc;
DEB(99, ("ISCSI: login\n"));
@@ -975,11 +1012,17 @@ login(iscsi_login_parameters_t *par, str
TAILQ_INIT(&session->ccb_pool);
TAILQ_INIT(&session->ccbs_throttled);
+ mutex_init(&session->lock, MUTEX_DEFAULT, IPL_BIO);
+ cv_init(&session->sess_cv, "session");
+ cv_init(&session->ccb_cv, "ccb");
+
+ mutex_enter(&iscsi_cleanup_mtx);
/* create a unique ID */
do {
++current_id;
} while (!current_id || find_session(current_id) != NULL);
par->session_id = session->id = current_id;
+ mutex_exit(&iscsi_cleanup_mtx);
create_ccbs(session);
session->login_type = par->login_type;
@@ -987,20 +1030,25 @@ login(iscsi_login_parameters_t *par, str
if ((rc = create_connection(par, session, l)) != 0) {
if (rc > 0) {
+ cv_destroy(&session->ccb_cv);
+ cv_destroy(&session->sess_cv);
+ mutex_destroy(&session->lock);
free(session, M_DEVBUF);
}
return;
}
- s = splbio();
+ mutex_enter(&iscsi_cleanup_mtx);
TAILQ_INSERT_HEAD(&iscsi_sessions, session, sessions);
- splx(s);
+ mutex_exit(&iscsi_cleanup_mtx);
/* Session established, map LUNs? */
if (par->login_type == ISCSI_LOGINTYPE_MAP) {
copyinstr(par->TargetName, session->tgtname,
sizeof(session->tgtname), NULL);
- if (!map_session(session)) {
+ DEB(1, ("Login: map session %d\n", session->id));
+ if (!map_session(session, dev)) {
+ DEB(1, ("Login: map session %d failed\n", session->id));
kill_session(session, ISCSI_STATUS_MAP_FAILED,
LOGOUT_SESSION, FALSE);
par->status = ISCSI_STATUS_MAP_FAILED;
@@ -1018,18 +1066,21 @@ login(iscsi_login_parameters_t *par, str
* par IN/OUT: The login parameters
*/
-STATIC void
+static void
logout(iscsi_logout_parameters_t *par)
{
session_t *session;
DEB(5, ("ISCSI: logout session %d\n", par->session_id));
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
+ mutex_exit(&iscsi_cleanup_mtx);
/* If the session exists, this always succeeds */
par->status = ISCSI_STATUS_SUCCESS;
@@ -1046,21 +1097,26 @@ logout(iscsi_logout_parameters_t *par)
* l IN: The lwp pointer of the caller
*/
-STATIC void
+static void
add_connection(iscsi_login_parameters_t *par, struct lwp *l)
{
session_t *session;
DEB(5, ("ISCSI: add_connection to session %d\n", par->session_id));
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
+ mutex_exit(&iscsi_cleanup_mtx);
if ((par->status = check_login_pars(par)) == 0) {
create_connection(par, session, l);
}
+
+ iscsi_notify_cleanup();
}
@@ -1072,7 +1128,7 @@ add_connection(iscsi_login_parameters_t
* par IN/OUT: The remove parameters
*/
-STATIC void
+static void
remove_connection(iscsi_remove_parameters_t *par)
{
connection_t *conn;
@@ -1081,18 +1137,22 @@ remove_connection(iscsi_remove_parameter
DEB(5, ("ISCSI: remove_connection %d from session %d\n",
par->connection_id, par->session_id));
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
if ((conn = find_connection(session, par->connection_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Connection %d not found in session %d\n",
par->connection_id, par->session_id));
par->status = ISCSI_STATUS_INVALID_CONNECTION_ID;
} else {
+ mutex_exit(&iscsi_cleanup_mtx);
kill_connection(conn, ISCSI_STATUS_LOGOUT, LOGOUT_CONNECTION,
FALSE);
par->status = ISCSI_STATUS_SUCCESS;
@@ -1109,7 +1169,7 @@ remove_connection(iscsi_remove_parameter
* l IN: The lwp pointer of the caller
*/
-STATIC void
+static void
restore_connection(iscsi_login_parameters_t *par, struct lwp *l)
{
session_t *session;
@@ -1118,18 +1178,22 @@ restore_connection(iscsi_login_parameter
DEB(1, ("ISCSI: restore_connection %d of session %d\n",
par->connection_id, par->session_id));
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
if ((connection = find_connection(session, par->connection_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Connection %d not found in session %d\n",
par->connection_id, par->session_id));
par->status = ISCSI_STATUS_INVALID_CONNECTION_ID;
return;
}
+ mutex_exit(&iscsi_cleanup_mtx);
if ((par->status = check_login_pars(par)) == 0) {
recreate_connection(par, session, connection, l);
@@ -1234,7 +1298,7 @@ unmap_databuf(struct proc *p, void *buf,
* l IN: The lwp pointer of the caller
*/
-STATIC void
+static void
io_command(iscsi_iocommand_parameters_t *par, struct lwp *l)
{
uint32_t datalen = par->req.datalen;
@@ -1242,11 +1306,14 @@ io_command(iscsi_iocommand_parameters_t
session_t *session;
DEB(9, ("ISCSI: io_command, SID=%d, lun=%" PRIu64 "\n", par->session_id, par->lun));
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
+ mutex_exit(&iscsi_cleanup_mtx);
par->req.senselen_used = 0;
par->req.datalen_used = 0;
@@ -1306,18 +1373,21 @@ io_command(iscsi_iocommand_parameters_t
* par IN/OUT: The send_targets parameters
*/
-STATIC void
+static void
send_targets(iscsi_send_targets_parameters_t *par)
{
int rc;
uint32_t rlen, cplen;
session_t *session;
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
DEBOUT(("Session %d not found\n", par->session_id));
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
+ mutex_exit(&iscsi_cleanup_mtx);
DEB(9, ("ISCSI: send_targets, rsp_size=%d; Saved list: %p\n",
par->response_size, session->target_list));
@@ -1355,7 +1425,7 @@ send_targets(iscsi_send_targets_paramete
* par IN/OUT: The set_node_name parameters
*/
-STATIC void
+static void
set_node_name(iscsi_set_node_name_parameters_t *par)
{
@@ -1392,13 +1462,15 @@ set_node_name(iscsi_set_node_name_parame
* par IN/OUT: The status parameters
*/
-STATIC void
+static void
connection_status(iscsi_conn_status_parameters_t *par)
{
connection_t *conn;
session_t *session;
+ mutex_enter(&iscsi_cleanup_mtx);
if ((session = find_session(par->session_id)) == NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
par->status = ISCSI_STATUS_INVALID_SESSION_ID;
return;
}
@@ -1410,6 +1482,7 @@ connection_status(iscsi_conn_status_para
}
par->status = (conn == NULL) ? ISCSI_STATUS_INVALID_CONNECTION_ID :
ISCSI_STATUS_SUCCESS;
+ mutex_exit(&iscsi_cleanup_mtx);
DEB(9, ("ISCSI: connection_status, session %d connection %d --> %d\n",
par->session_id, par->connection_id, par->status));
}
@@ -1423,7 +1496,7 @@ connection_status(iscsi_conn_status_para
* par IN/OUT: The version parameters
*/
-STATIC void
+static void
get_version(iscsi_get_version_parameters_t *par)
{
par->status = ISCSI_STATUS_SUCCESS;
@@ -1447,10 +1520,14 @@ kill_all_sessions(void)
{
session_t *sess;
+ mutex_enter(&iscsi_cleanup_mtx);
while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) {
+ mutex_exit(&iscsi_cleanup_mtx);
kill_session(sess, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION,
FALSE);
+ mutex_enter(&iscsi_cleanup_mtx);
}
+ mutex_exit(&iscsi_cleanup_mtx);
}
/*
@@ -1479,60 +1556,109 @@ handle_connection_error(connection_t *co
}
}
+/*
+ * add a connection to the cleanup list
+ */
+void
+add_connection_cleanup(connection_t *conn)
+{
+ mutex_enter(&iscsi_cleanup_mtx);
+ TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections);
+ mutex_exit(&iscsi_cleanup_mtx);
+}
+
+/*
+ * callout wrappers for timeouts, the work is done by the cleanup thread
+ */
+void
+connection_timeout_co(void *par)
+{
+ connection_t *conn = par;
+
+ mutex_enter(&iscsi_cleanup_mtx);
+ TAILQ_INSERT_TAIL(&iscsi_timeout_conn_list, conn, tchain);
+ mutex_exit(&iscsi_cleanup_mtx);
+ iscsi_notify_cleanup();
+}
+
+void
+ccb_timeout_co(void *par)
+{
+ ccb_t *ccb = par;
+
+ mutex_enter(&iscsi_cleanup_mtx);
+ TAILQ_INSERT_TAIL(&iscsi_timeout_ccb_list, ccb, tchain);
+ mutex_exit(&iscsi_cleanup_mtx);
+ iscsi_notify_cleanup();
+}
/*
* iscsi_cleanup_thread
* Global thread to handle connection and session cleanup after termination.
*/
-void
+static void
iscsi_cleanup_thread(void *par)
{
int s, rc;
connection_t *conn;
+ ccb_t *ccb;
session_t *sess, *nxt;
uint32_t status;
+#ifdef ISCSI_DEBUG
+ int last_usecount;
+#endif
- s = splbio();
+ mutex_enter(&iscsi_cleanup_mtx);
while ((conn = TAILQ_FIRST(&iscsi_cleanupc_list)) != NULL ||
iscsi_num_send_threads ||
!iscsi_detaching) {
if (conn != NULL) {
TAILQ_REMOVE(&iscsi_cleanupc_list, conn, connections);
- splx(s);
+ mutex_exit(&iscsi_cleanup_mtx);
sess = conn->session;
status = conn->terminating;
+ /*
+ * This implies that connection cleanup only runs when
+ * the send/recv threads have been killed
+ */
DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n"));
while (conn->sendproc || conn->rcvproc)
- tsleep(conn, PWAIT, "termwait", hz);
+ kpause("termwait", false, hz, NULL);
- while (conn->usecount > 0)
- tsleep(conn, PWAIT, "finalwait", hz);
+ last_usecount = 0;
+ while (conn->usecount > 0) {
+ if (conn->usecount != last_usecount) {
+ DEBC(conn, 5,("Cleanup: %d CCBs busy\n", conn->usecount));
+ last_usecount = conn->usecount;
+ }
+ kpause("finalwait", false, hz, NULL);
+ }
callout_halt(&conn->timeout, NULL);
closef(conn->sock);
+ cv_destroy(&conn->idle_cv);
+ cv_destroy(&conn->ccb_cv);
+ cv_destroy(&conn->conn_cv);
+ mutex_destroy(&conn->lock);
free(conn, M_DEVBUF);
--sess->total_connections;
- s = splbio();
TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, sessions, nxt) {
if (sess->total_connections != 0)
continue;
TAILQ_REMOVE(&iscsi_cleanups_list, sess, sessions);
- splx(s);
DEB(1, ("Cleanup: Unmap session %d\n", sess->id));
rc = unmap_session(sess);
if (rc == 0) {
DEB(1, ("Cleanup: Unmap session %d failed\n", sess->id));
- s = splbio();
TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, sessions);
- splx(s);
}
if (sess->target_list != NULL)
@@ -1540,43 +1666,97 @@ iscsi_cleanup_thread(void *par)
/* notify event handlers of session shutdown */
add_event(ISCSI_SESSION_TERMINATED, sess->id, 0, status);
DEB(1, ("Cleanup: session ended %d\n", sess->id));
- free(sess, M_DEVBUF);
- s = splbio();
+ cv_destroy(&sess->ccb_cv);
+ cv_destroy(&sess->sess_cv);
+ mutex_destroy(&sess->lock);
+ free(sess, M_DEVBUF);
}
- splx(s);
-
DEB(5, ("Cleanup: Done\n"));
- s = splbio();
+ mutex_enter(&iscsi_cleanup_mtx);
+
} else {
/* Go to sleep, but wake up every 30 seconds to
* check for dead event handlers */
- splx(s);
- rc = tsleep(&iscsi_cleanupc_list, PWAIT, "cleanup",
+ rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx,
(TAILQ_FIRST(&event_handlers)) ? 30 * hz : 0);
- s = splbio();
+
+ /* handle ccb timeouts */
+ while ((ccb = TAILQ_FIRST(&iscsi_timeout_ccb_list)) != NULL) {
+ TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, tchain);
+ mutex_exit(&iscsi_cleanup_mtx);
+ ccb_timeout(ccb);
+ mutex_enter(&iscsi_cleanup_mtx);
+ }
+ /* handle connection timeouts */
+ while ((conn = TAILQ_FIRST(&iscsi_timeout_conn_list)) != NULL) {
+ TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, tchain);
+ mutex_exit(&iscsi_cleanup_mtx);
+ connection_timeout(conn);
+ mutex_enter(&iscsi_cleanup_mtx);
+ }
+
/* if timed out, not woken up */
if (rc == EWOULDBLOCK)
check_event_handlers();
}
}
- splx(s);
+ mutex_exit(&iscsi_cleanup_mtx);
add_event(ISCSI_DRIVER_TERMINATING, 0, 0, ISCSI_STATUS_DRIVER_UNLOAD);
/*
- * Wait for all event handlers to deregister, but don't wait more
- * than 1 minute (assume registering app has died if it takes longer).
+ * Wait for all event handlers to deregister, but don't wait more
+ * than 1 minute (assume registering app has died if it takes longer).
*/
+ mutex_enter(&iscsi_cleanup_mtx);
for (s = 0; TAILQ_FIRST(&event_handlers) != NULL && s < 60; s++)
- tsleep(&s, PWAIT, "waiteventclr", hz);
+ kpause("waiteventclr", true, hz, &iscsi_cleanup_mtx);
+ mutex_exit(&iscsi_cleanup_mtx);
iscsi_cleanproc = NULL;
DEB(5, ("Cleanup thread exits\n"));
kthread_exit(0);
}
+void
+iscsi_init_cleanup()
+{
+
+ mutex_init(&iscsi_cleanup_mtx, MUTEX_DEFAULT, IPL_BIO);
+ cv_init(&iscsi_cleanup_cv, "cleanup");
+ cv_init(&iscsi_event_cv, "iscsievtwait");
+
+ if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_cleanup_thread,
+ NULL, &iscsi_cleanproc, "iscsi_cleanup") != 0) {
+ panic("Can't create cleanup thread!");
+ }
+}
+
+void
+iscsi_destroy_cleanup()
+{
+
+ iscsi_detaching = true;
+ mutex_enter(&iscsi_cleanup_mtx);
+ while (iscsi_cleanproc != NULL) {
+ iscsi_notify_cleanup();
+ kpause("detach_wait", false, hz, &iscsi_cleanup_mtx);
+ }
+ mutex_exit(&iscsi_cleanup_mtx);
+
+ cv_destroy(&iscsi_event_cv);
+ cv_destroy(&iscsi_cleanup_cv);
+ mutex_destroy(&iscsi_cleanup_mtx);
+}
+
+void
+iscsi_notify_cleanup()
+{
+ cv_signal(&iscsi_cleanup_cv);
+}
+
/* -------------------------------------------------------------------- */
@@ -1585,7 +1765,7 @@ iscsi_cleanup_thread(void *par)
* Driver ioctl entry.
*
* Parameter:
- * dev The device (ignored)
+ * file File structure
* cmd The ioctl Command
* addr IN/OUT: The command parameter
* flag Flags (ignored)
@@ -1596,6 +1776,7 @@ int
iscsiioctl(struct file *fp, u_long cmd, void *addr)
{
struct lwp *l = curlwp;
+ struct iscsifd *d = fp->f_iscsi;
DEB(1, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
@@ -1605,7 +1786,7 @@ iscsiioctl(struct file *fp, u_long cmd,
break;
case ISCSI_LOGIN:
- login((iscsi_login_parameters_t *) addr, l);
+ login((iscsi_login_parameters_t *) addr, l, d->dev);
break;
case ISCSI_ADD_CONNECTION:
Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.17 src/sys/dev/iscsi/iscsi_main.c:1.18
--- src/sys/dev/iscsi/iscsi_main.c:1.17 Thu Aug 20 14:40:18 2015
+++ src/sys/dev/iscsi/iscsi_main.c Sun May 29 13:51:16 2016
@@ -36,6 +36,7 @@
#include <sys/filedesc.h>
#include <sys/kmem.h>
#include <sys/socketvar.h>
+#include <sys/sysctl.h>
#include "ioconf.h"
@@ -47,19 +48,11 @@ extern struct cfdriver iscsi_cd;
int iscsi_debug_level = ISCSI_DEBUG;
#endif
-/* Device Structure */
-iscsi_softc_t *sc = NULL;
+bool iscsi_detaching;
/* the list of sessions */
session_list_t iscsi_sessions = TAILQ_HEAD_INITIALIZER(iscsi_sessions);
-/* connections to clean up */
-connection_list_t iscsi_cleanupc_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanupc_list);
-session_list_t iscsi_cleanups_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanups_list);
-
-bool iscsi_detaching = FALSE;
-struct lwp *iscsi_cleanproc = NULL;
-
/* the number of active send threads (for cleanup thread) */
uint32_t iscsi_num_send_threads = 0;
@@ -78,6 +71,11 @@ static void iscsi_attach(device_t parent
static int iscsi_match(device_t, cfdata_t, void *);
static int iscsi_detach(device_t, int);
+struct iscsi_softc {
+ device_t dev;
+ kmutex_t lock;
+ TAILQ_HEAD(, iscsifd) fds;
+};
CFATTACH_DECL_NEW(iscsi, sizeof(struct iscsi_softc), iscsi_match, iscsi_attach,
iscsi_detach, NULL);
@@ -126,15 +124,35 @@ int
iscsiopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct iscsifd *d;
+ struct iscsi_softc *sc;
struct file *fp;
- int error, fd;
+ int error, fd, unit;
+
+ unit = minor(dev);
+
+ DEB(99, ("ISCSI Open unit=%d\n",unit));
- DEB(99, ("ISCSI Open\n"));
+ sc = device_lookup_private(&iscsi_cd, unit);
+ if (sc == NULL)
+ return ENXIO;
if ((error = fd_allocfile(&fp, &fd)) != 0)
return error;
d = kmem_alloc(sizeof(*d), KM_SLEEP);
+ d->dev = sc->dev;
+ d->unit = unit;
+
+ mutex_enter(&sc->lock);
+ if (iscsi_detaching) {
+ mutex_exit(&sc->lock);
+ kmem_free(d, sizeof(*d));
+ DEB(99, ("ISCSI Open aborting\n"));
+ fd_abort(curproc, fp, fd);
+ return ENXIO;
+ }
+ TAILQ_INSERT_TAIL(&sc->fds, d, link);
+ mutex_exit(&sc->lock);
return fd_clone(fp, fd, flag, &iscsi_fileops, d);
}
@@ -143,6 +161,17 @@ static int
iscsiclose(struct file *fp)
{
struct iscsifd *d = fp->f_iscsi;
+ struct iscsi_softc *sc;
+
+ sc = device_lookup_private(&iscsi_cd, d->unit);
+ if (sc == NULL) {
+ DEBOUT(("%s: Cannot find private data\n",__func__));
+ return ENXIO;
+ }
+
+ mutex_enter(&sc->lock);
+ TAILQ_REMOVE(&sc->fds, d, link);
+ mutex_exit(&sc->lock);
kmem_free(d, sizeof(*d));
fp->f_iscsi = NULL;
@@ -208,15 +237,19 @@ iscsiattach(int n)
static void
iscsi_attach(device_t parent, device_t self, void *aux)
{
+ struct iscsi_softc *sc;
- DEBOUT(("ISCSI: iscsi_attach, parent=%p, self=%p, aux=%p\n", parent,
+ DEB(1, ("ISCSI: iscsi_attach, parent=%p, self=%p, aux=%p\n", parent,
self, aux));
- sc = (iscsi_softc_t *) device_private(self);
- sc->sc_dev = self;
- if (kthread_create(PRI_NONE, 0, NULL, iscsi_cleanup_thread,
- NULL, &iscsi_cleanproc, "Cleanup") != 0) {
- panic("Can't create cleanup thread!");
- }
+ sc = (struct iscsi_softc *) device_private(self);
+ sc->dev = self;
+
+ TAILQ_INIT(&sc->fds);
+ mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
+
+ iscsi_detaching = false;
+ iscsi_init_cleanup();
+
aprint_normal("%s: attached. major = %d\n", iscsi_cd.cd_name,
cdevsw_lookup_major(&iscsi_cdevsw));
}
@@ -228,14 +261,24 @@ iscsi_attach(device_t parent, device_t s
static int
iscsi_detach(device_t self, int flags)
{
+ struct iscsi_softc *sc;
- DEBOUT(("ISCSI: detach\n"));
- kill_all_sessions();
- iscsi_detaching = TRUE;
- while (iscsi_cleanproc != NULL) {
- wakeup(&iscsi_cleanupc_list);
- tsleep(&iscsi_cleanupc_list, PWAIT, "detach_wait", 20 * hz);
+ DEB(1, ("ISCSI: detach\n"));
+ sc = (struct iscsi_softc *) device_private(self);
+
+ mutex_enter(&sc->lock);
+ if (!TAILQ_EMPTY(&sc->fds)) {
+ mutex_exit(&sc->lock);
+ return EBUSY;
}
+ iscsi_detaching = true;
+ mutex_exit(&sc->lock);
+
+ kill_all_sessions();
+ iscsi_destroy_cleanup();
+
+ mutex_destroy(&sc->lock);
+
return 0;
}
@@ -299,22 +342,16 @@ getquirks(const char *iqn)
*/
int
-map_session(session_t *session)
+map_session(session_t *session, device_t dev)
{
struct scsipi_adapter *adapt = &session->sc_adapter;
struct scsipi_channel *chan = &session->sc_channel;
const quirktab_t *tgt;
- if (sc == NULL) {
- /* we haven't gone through the config process */
- /* (shouldn't happen) */
- DEBOUT(("Map: No device pointer!\n"));
- return 0;
- }
/*
* Fill in the scsipi_adapter.
*/
- adapt->adapt_dev = sc->sc_dev;
+ adapt->adapt_dev = dev;
adapt->adapt_nchannels = 1;
adapt->adapt_request = iscsi_scsipi_request;
adapt->adapt_minphys = iscsi_minphys;
@@ -337,7 +374,7 @@ map_session(session_t *session)
chan->chan_nluns = 16; /* ToDo: ??? */
chan->chan_id = session->id;
- session->child_dev = config_found(sc->sc_dev, chan, scsiprint);
+ session->child_dev = config_found(dev, chan, scsiprint);
return session->child_dev != NULL;
}
@@ -405,10 +442,10 @@ iscsi_scsipi_request(struct scsipi_chann
}
/*
* NOTE: It appears that XS_CTL_DATA_UIO is not actually used anywhere.
- * Since it really would complicate matters to handle offsets
- * into scatter-gather lists, and a number of other drivers don't
- * handle uio-based data as well, XS_CTL_DATA_UIO isn't
- * implemented in this driver (at least for now).
+ * Since it really would complicate matters to handle offsets
+ * into scatter-gather lists, and a number of other drivers don't
+ * handle uio-based data as well, XS_CTL_DATA_UIO isn't
+ * implemented in this driver (at least for now).
*/
if (flags & XS_CTL_DATA_UIO) {
xs->error = XS_DRIVER_STUFFUP;
@@ -422,7 +459,7 @@ iscsi_scsipi_request(struct scsipi_chann
return;
case ADAPTER_REQ_GROW_RESOURCES:
- DEBOUT(("ISCSI: scsipi_request GROW_RESOURCES\n"));
+ DEB(5, ("ISCSI: scsipi_request GROW_RESOURCES\n"));
return;
case ADAPTER_REQ_SET_XFER_MODE:
@@ -468,35 +505,36 @@ void
iscsi_done(ccb_t *ccb)
{
struct scsipi_xfer *xs = ccb->xs;
- /*DEBOUT (("iscsi_done\n")); */
+ DEB(9, ("iscsi_done\n"));
if (xs != NULL) {
xs->resid = ccb->residual;
switch (ccb->status) {
case ISCSI_STATUS_SUCCESS:
- xs->error = 0;
+ xs->error = XS_NOERROR;
+ xs->status = SCSI_OK;
break;
case ISCSI_STATUS_CHECK_CONDITION:
xs->error = XS_SENSE;
-#ifdef ISCSI_DEBUG
- {
- uint8_t *s = (uint8_t *) (&xs->sense);
- DEB(5, ("Scsipi_done, error=XS_SENSE, sense data=%02x "
- "%02x %02x %02x...\n",
- s[0], s[1], s[2], s[3]));
- }
-#endif
+ xs->status = SCSI_CHECK;
break;
case ISCSI_STATUS_TARGET_BUSY:
xs->error = XS_BUSY;
+ xs->status = SCSI_BUSY;
break;
case ISCSI_STATUS_SOCKET_ERROR:
case ISCSI_STATUS_TIMEOUT:
xs->error = XS_SELTIMEOUT;
+ xs->status = SCSI_BUSY;
+ break;
+
+ case ISCSI_STATUS_NO_RESOURCES:
+ xs->error = XS_BUSY;
+ xs->status = SCSI_QUEUE_FULL;
break;
default:
@@ -505,11 +543,37 @@ iscsi_done(ccb_t *ccb)
}
DEB(99, ("Calling scsipi_done (%p), err = %d\n", xs, xs->error));
+ KERNEL_LOCK(1, curlwp);
scsipi_done(xs);
+ KERNEL_UNLOCK_ONE(curlwp);
DEB(99, ("scsipi_done returned\n"));
+ } else {
+ DEBOUT(("ISCSI: iscsi_done CCB %p without XS\n", ccb));
}
}
+SYSCTL_SETUP(sysctl_iscsi_setup, "ISCSI subtree setup")
+{
+ const struct sysctlnode *node = NULL;
+
+ sysctl_createv(clog, 0, NULL, &node,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "iscsi",
+ SYSCTL_DESCR("iscsi controls"),
+ NULL, 0, NULL, 0,
+ CTL_HW, CTL_CREATE, CTL_EOL);
+
+#ifdef ISCSI_DEBUG
+ sysctl_createv(clog, 0, &node, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "debug",
+ SYSCTL_DESCR("debug level"),
+ NULL, 0, &iscsi_debug_level, sizeof(iscsi_debug_level),
+ CTL_CREATE, CTL_EOL);
+#endif
+}
+
+
/* Kernel Module support */
#include <sys/module.h>
@@ -545,6 +609,7 @@ iscsi_modcmd(modcmd_t cmd, void *arg)
#ifdef _MODULE
devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR;
int error;
+ static struct sysctllog *clog;
#endif
switch (cmd) {
@@ -590,12 +655,16 @@ iscsi_modcmd(modcmd_t cmd, void *arg)
config_cfdriver_detach(&iscsi_cd);
return ENXIO;
}
+
+ sysctl_iscsi_setup(&clog);
#endif
return 0;
break;
case MODULE_CMD_FINI:
#ifdef _MODULE
+ sysctl_teardown(&clog);
+
error = config_cfdata_detach(iscsi_cfdata);
if (error)
return error;
Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.10 src/sys/dev/iscsi/iscsi_rcv.c:1.11
--- src/sys/dev/iscsi/iscsi_rcv.c:1.10 Sat May 30 18:09:31 2015
+++ src/sys/dev/iscsi/iscsi_rcv.c Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_rcv.c,v 1.10 2015/05/30 18:09:31 joerg Exp $ */
+/* $NetBSD: iscsi_rcv.c,v 1.11 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -59,7 +59,9 @@ my_soo_read(connection_t *conn, struct u
DEBC(conn, 99, ("soo_read req: %zu\n", resid));
+ KERNEL_LOCK(1, curlwp);
ret = soreceive(so, NULL, u, NULL, NULL, &flags);
+ KERNEL_UNLOCK_ONE(curlwp);
if (ret || (flags != MSG_DONTWAIT && u->uio_resid)) {
DEBC(conn, 1, ("Read failed (ret: %d, req: %zu, out: %zu)\n", ret, resid,
@@ -159,7 +161,7 @@ read_pdu_data(pdu_t *pdu, uint8_t *data,
int i, pad;
connection_t *conn = pdu->connection;
- DEBOUT(("read_pdu_data: data segment length = %d\n",
+ DEB(1, ("read_pdu_data: data segment length = %d\n",
ntoh3(pdu->pdu.DataSegmentLength)));
if (!(len = ntoh3(pdu->pdu.DataSegmentLength))) {
return 0;
@@ -168,7 +170,8 @@ read_pdu_data(pdu_t *pdu, uint8_t *data,
if (pad) {
pad = 4 - pad;
}
- assert((data != NULL) || (offset == 0));
+
+ KASSERT(data != NULL || offset == 0);
if (data == NULL) {
/*
@@ -542,7 +545,7 @@ receive_logout_pdu(connection_t *conn, p
callout_stop(&conn->timeout);
/* let send thread take over next step of cleanup */
- wakeup(&conn->pdus_to_send);
+ cv_broadcast(&conn->conn_cv);
}
return !otherconn;
@@ -990,7 +993,7 @@ receive_pdu(connection_t *conn, pdu_t *p
{
ccb_t *req_ccb;
ccb_list_t waiting;
- int rc, s;
+ int rc;
uint32_t MaxCmdSN, digest;
session_t *sess = conn->session;
@@ -1101,20 +1104,22 @@ receive_pdu(connection_t *conn, pdu_t *p
* Un-throttle - wakeup all CCBs waiting for MaxCmdSN to increase.
* We have to handle wait/nowait CCBs a bit differently.
*/
+ mutex_enter(&sess->lock);
if (MaxCmdSN != sess->MaxCmdSN) {
sess->MaxCmdSN = MaxCmdSN;
- if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL)
+ if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL) {
+ mutex_exit(&sess->lock);
return 0;
+ }
DEBC(conn, 1, ("Unthrottling - MaxCmdSN = %d\n", MaxCmdSN));
- s = splbio();
TAILQ_INIT(&waiting);
while ((req_ccb = TAILQ_FIRST(&sess->ccbs_throttled)) != NULL) {
throttle_ccb(req_ccb, FALSE);
TAILQ_INSERT_TAIL(&waiting, req_ccb, chain);
}
- splx(s);
+ mutex_exit(&sess->lock);
while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
TAILQ_REMOVE(&waiting, req_ccb, chain);
@@ -1122,12 +1127,13 @@ receive_pdu(connection_t *conn, pdu_t *p
DEBC(conn, 1, ("Unthrottling - ccb = %p, disp = %d\n",
req_ccb, req_ccb->disp));
- if (req_ccb->flags & CCBF_WAITING)
- wakeup(req_ccb);
- else
+ if (req_ccb->flags & CCBF_WAITING) {
+ cv_broadcast(&conn->ccb_cv);
+ } else
send_command(req_ccb, req_ccb->disp, FALSE, FALSE);
}
- }
+ } else
+ mutex_exit(&sess->lock);
return 0;
}
@@ -1185,9 +1191,11 @@ iscsi_rcv_thread(void *par)
break;
}
}
+ mutex_enter(&conn->lock);
if (!conn->destroy) {
- tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
+ cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT);
}
+ mutex_exit(&conn->lock);
} while (!conn->destroy);
conn->rcvproc = NULL;
Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.15 src/sys/dev/iscsi/iscsi_send.c:1.16
--- src/sys/dev/iscsi/iscsi_send.c:1.15 Thu Dec 24 03:41:03 2015
+++ src/sys/dev/iscsi/iscsi_send.c Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_send.c,v 1.15 2015/12/24 03:41:03 knakahara Exp $ */
+/* $NetBSD: iscsi_send.c,v 1.16 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -34,6 +34,7 @@
#include <sys/filedesc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/atomic.h>
/*#define LUN_1 1 */
@@ -57,11 +58,13 @@ my_soo_write(connection_t *conn, struct
int ret;
#ifdef ISCSI_DEBUG
size_t resid = u->uio_resid;
-
- assert(resid != 0);
#endif
+ KASSERT(u->uio_resid != 0);
+
+ KERNEL_LOCK(1, curlwp);
ret = sosend(so, NULL, u, NULL, NULL, 0, conn->threadobj);
+ KERNEL_UNLOCK_ONE(curlwp);
DEB(99, ("soo_write done: len = %zu\n", u->uio_resid));
@@ -90,8 +93,10 @@ assign_connection(session_t *session, bo
{
connection_t *conn, *next;
+ mutex_enter(&session->lock);
do {
if ((conn = session->mru_connection) == NULL) {
+ mutex_exit(&session->lock);
return NULL;
}
next = conn;
@@ -105,15 +110,17 @@ assign_connection(session_t *session, bo
if (next->state != ST_FULL_FEATURE) {
if (waitok) {
- tsleep(session, PRIBIO, "iscsi_assign_connection", 0);
+ cv_wait(&session->sess_cv, &session->lock);
next = TAILQ_FIRST(&session->conn_list);
} else {
+ mutex_exit(&session->lock);
return NULL;
}
} else {
session->mru_connection = next;
}
} while (next != NULL && next->state != ST_FULL_FEATURE);
+ mutex_exit(&session->lock);
return next;
}
@@ -138,7 +145,6 @@ reassign_tasks(connection_t *oldconn)
pdu_t *opdu;
int no_tm = 1;
int rc = 1;
- int s;
if ((conn = assign_connection(sess, FALSE)) == NULL) {
DEB(1, ("Reassign_tasks of Session %d, connection %d failed, "
@@ -163,7 +169,7 @@ reassign_tasks(connection_t *oldconn)
if (!no_tm && oldconn->Time2Wait) {
DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n",
oldconn->Time2Wait, hz));
- tsleep(&no_tm, PRIBIO, "Time2Wait", oldconn->Time2Wait * hz);
+ kpause("Time2Wait", false, oldconn->Time2Wait * hz, NULL);
}
}
@@ -214,7 +220,7 @@ reassign_tasks(connection_t *oldconn)
/* fixup reference counts */
oldconn->usecount--;
- conn->usecount++;
+ atomic_inc_uint(&conn->usecount);
DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
ccb, opdu, pdu));
@@ -226,9 +232,7 @@ reassign_tasks(connection_t *oldconn)
free_pdu(opdu);
/* put ready CCB into waiting list of new connection */
- s = splbio();
suspend_ccb(ccb, TRUE);
- splx(s);
}
if (pdu == NULL) {
@@ -248,6 +252,7 @@ reassign_tasks(connection_t *oldconn)
}
/* if we get an error on reassign, restart the original request */
if (no_tm || rc) {
+ mutex_enter(&sess->lock);
if (ccb->CmdSN < sess->ExpCmdSN) {
pdu = ccb->pdu_waiting;
@@ -260,6 +265,7 @@ reassign_tasks(connection_t *oldconn)
}
pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
}
+ mutex_exit(&sess->lock);
resend_pdu(ccb);
} else {
callout_schedule(&ccb->timeout, COMMAND_TIMEOUT);
@@ -287,29 +293,21 @@ iscsi_send_thread(void *par)
ccb_t *ccb, *nccb;
pdu_t *pdu;
struct file *fp;
- int s;
sess = conn->session;
/* so cleanup thread knows there's someone left */
iscsi_num_send_threads++;
do {
+ mutex_enter(&conn->lock);
while (!conn->terminating) {
- s = splbio();
while (!conn->terminating &&
(pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
pdu->flags &= ~PDUF_INQUEUE;
- splx(s);
+ mutex_exit(&conn->lock);
-#ifdef ISCSI_DEBUG
- if (!pdu->uio.uio_resid) {
- DEBOUT(("uio.resid = 0 in iscsi_send_thread! pdu=%p\n",
- pdu));
- assert(pdu->uio.uio_resid != 0);
- }
-#endif
- /*DEB (99,("Send thread woke up, pdu = %x)\n", (int)pdu)); */
+ KASSERT(!pdu->uio.uio_resid);
/* update ExpStatSN here to avoid discontinuities */
/* and delays in updating target */
@@ -317,26 +315,20 @@ iscsi_send_thread(void *par)
if (conn->HeaderDigest)
pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE);
+ DEBC(conn, 99, ("Send thread transmitting data\n"));
my_soo_write(conn, &pdu->uio);
if (pdu->disp <= PDUDISP_FREE) {
free_pdu(pdu);
} else {
- pdu->flags &= ~PDUF_BUSY;
- }
- s = splbio();
+ pdu->flags &= ~PDUF_BUSY; }
+ mutex_enter(&conn->lock);
}
- /*DEB (99,("Send thread done, waiting (conn->terminating = %d)\n", */
- /* conn->terminating)); */
-
- if (!conn->terminating) {
- tsleep(&conn->pdus_to_send, PRIBIO,
- "iscsisend", 0);
- }
-
- splx(s);
+ if (!conn->terminating)
+ cv_wait(&conn->conn_cv, &conn->lock);
}
+ mutex_exit(&conn->lock);
/* ------------------------------------------------------------------------
* Here this thread takes over cleanup of the terminating connection.
@@ -369,15 +361,19 @@ iscsi_send_thread(void *par)
}
/* clean out anything left in send queue */
+ mutex_enter(&conn->lock);
while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY);
+ mutex_exit(&conn->lock);
/* if it's not attached to a waiting CCB, free it */
if (pdu->owner == NULL ||
pdu->owner->pdu_waiting != pdu) {
free_pdu(pdu);
}
+ mutex_enter(&conn->lock);
}
+ mutex_exit(&conn->lock);
/* If there's another connection available, transfer pending tasks */
if (sess->active_connections &&
@@ -386,7 +382,7 @@ iscsi_send_thread(void *par)
reassign_tasks(conn);
} else if (!conn->destroy && conn->Time2Wait) {
DEBC(conn, 1, ("Time2Wait\n"));
- tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz);
+ kpause("Time2Wait", false, conn->Time2Wait * hz, NULL);
DEBC(conn, 1, ("Time2Wait\n"));
}
/* notify event handlers of connection shutdown */
@@ -396,32 +392,31 @@ iscsi_send_thread(void *par)
sess->id, conn->id, conn->terminating);
DEBC(conn, 1, ("Waiting for conn_idle\n"));
+ mutex_enter(&conn->lock);
if (!conn->destroy)
- tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
+ cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT);
+ mutex_exit(&conn->lock);
DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy));
} while (!conn->destroy);
/* wake up anyone waiting for a PDU */
- wakeup(&conn->pdu_pool);
+ cv_broadcast(&conn->conn_cv);
/* wake up any waiting CCBs */
while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
+ KASSERT(ccb->disp >= CCBDISP_NOWAIT);
wake_ccb(ccb, conn->terminating);
/* NOTE: wake_ccb will remove the CCB from the queue */
}
- s = splbio();
if (conn->in_session) {
conn->in_session = FALSE;
TAILQ_REMOVE(&sess->conn_list, conn, connections);
sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
}
- TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections);
- splx(s);
-
- wakeup(&iscsi_cleanupc_list);
+ add_connection_cleanup(conn);
conn->sendproc = NULL;
DEBC(conn, 1, ("Send thread exits\n"));
@@ -448,7 +443,6 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
{
connection_t *conn = pdu->connection;
ccb_disp_t prev_cdisp = 0;
- int s;
if (ccb != NULL) {
prev_cdisp = ccb->disp;
@@ -463,7 +457,7 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n",
ccb, prev_cdisp, cdisp, pdu, pdisp));
- s = splbio();
+ mutex_enter(&conn->lock);
if (pdisp == PDUDISP_WAIT) {
ccb->pdu_waiting = pdu;
@@ -480,8 +474,9 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
else
TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
+ mutex_exit(&conn->lock);
- wakeup(&conn->pdus_to_send);
+ cv_broadcast(&conn->conn_cv);
if (cdisp != CCBDISP_NOWAIT) {
callout_schedule(&ccb->timeout, COMMAND_TIMEOUT);
@@ -489,10 +484,16 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
if (prev_cdisp <= CCBDISP_NOWAIT)
suspend_ccb(ccb, TRUE);
- if (cdisp == CCBDISP_WAIT)
- tsleep(ccb, PWAIT, "sendpdu", 0);
+ mutex_enter(&conn->lock);
+ while (ccb->disp == CCBDISP_WAIT) {
+ DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n",
+ ccb, ccb->disp));
+ cv_wait(&conn->ccb_cv, &conn->lock);
+ DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n",
+ ccb, ccb->disp));
+ }
+ mutex_exit(&conn->lock);
}
- splx(s);
}
@@ -509,15 +510,14 @@ resend_pdu(ccb_t *ccb)
{
connection_t *conn = ccb->connection;
pdu_t *pdu = ccb->pdu_waiting;
- int s;
- s = splbio ();
+ mutex_enter(&conn->lock);
if (pdu == NULL || (pdu->flags & PDUF_BUSY)) {
- splx (s);
+ mutex_exit(&conn->lock);
return;
}
pdu->flags |= PDUF_BUSY;
- splx (s);
+ mutex_exit(&conn->lock);
/* restore UIO and IOVEC */
pdu->uio = pdu->save_uio;
@@ -525,8 +525,7 @@ resend_pdu(ccb_t *ccb)
DEBC(conn, 8, ("ReSend_pdu ccb=%p, pdu=%p\n", ccb, pdu));
- s = splbio ();
-
+ mutex_enter(&conn->lock);
/* Enqueue for sending */
pdu->flags |= PDUF_INQUEUE;
@@ -536,9 +535,9 @@ resend_pdu(ccb_t *ccb)
TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
}
callout_schedule(&ccb->timeout, COMMAND_TIMEOUT);
- splx (s);
+ mutex_exit(&conn->lock);
- wakeup(&conn->pdus_to_send);
+ cv_broadcast(&conn->conn_cv);
}
@@ -1278,7 +1277,7 @@ send_data_out(connection_t *conn, pdu_t
uint32_t totlen, len, offs, sn;
pdu_t *tx_pdu;
- assert(conn->max_transfer != 0);
+ KASSERT(conn->max_transfer != 0);
if (rx_pdu) {
offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset);
@@ -1294,7 +1293,7 @@ send_data_out(connection_t *conn, pdu_t
tx_pdu = get_pdu(conn, waitok);
if (tx_pdu == NULL) {
- DEBOUT(("No PDU in send_data_out\n"));
+ DEBC(conn, 5, ("No PDU in send_data_out\n"));
tx_ccb->disp = disp;
tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
@@ -1348,9 +1347,8 @@ send_command(ccb_t *ccb, ccb_disp_t disp
session_t *sess = ccb->session;
pdu_t *ppdu;
pdu_header_t *pdu;
- int s;
- s = splbio();
+ mutex_enter(&sess->lock);
while (/*CONSTCOND*/ISCSI_THROTTLING_ENABLED &&
/*CONSTCOND*/!ISCSI_SERVER_TRUSTED &&
!sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
@@ -1361,18 +1359,23 @@ send_command(ccb_t *ccb, ccb_disp_t disp
throttle_ccb(ccb, TRUE);
if (!waitok) {
- splx(s);
+ DEBOUT(("Throttling send_command, ccb = %p\n",ccb));
return;
}
- tsleep(ccb, PWAIT, "waitMaxCmd", 0);
+ cv_wait(&sess->ccb_cv, &sess->lock);
+
+ DEBOUT(("Resuming send_command, ccb = %p\n",ccb));
throttle_ccb(ccb, FALSE);
ccb->flags &= ~CCBF_WAITING;
}
- splx(s);
+ mutex_exit(&sess->lock);
+
ppdu = get_pdu(conn, FALSE);
if (ppdu == NULL) {
+ DEBOUT(("No PDU for send_command, ccb = %p\n",ccb));
+ ccb->disp = disp;
wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES);
return;
}
@@ -1401,6 +1404,9 @@ send_command(ccb_t *ccb, ccb_disp_t disp
}
}
+ /* currently ignoring tag type and id */
+ pdu->Flags |= ATTR_SIMPLE;
+
if (!totlen)
pdu->Flags |= FLAG_FINAL;
@@ -1412,11 +1418,11 @@ send_command(ccb_t *ccb, ccb_disp_t disp
ccb->residual = 0;
ccb->flags |= CCBF_REASSIGN;
- s = splbio();
+ mutex_enter(&sess->lock);
ccb->CmdSN = sess->CmdSN;
if (!immed)
sess->CmdSN++;
- splx(s);
+ mutex_exit(&sess->lock);
pdu->p.command.CmdSN = htonl(ccb->CmdSN);
@@ -1473,8 +1479,7 @@ send_run_xfer(session_t *session, struct
ccb = get_ccb(conn, waitok);
if (ccb == NULL) {
xs->error = XS_BUSY;
- xs->status = SCSI_QUEUE_FULL;
- DEBC(conn, 0, ("No CCB in run_xfer\n"));
+ DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->usecount));
scsipi_done(xs);
return;
}
@@ -1579,13 +1584,12 @@ send_io_command(session_t *session, uint
* before those time out.
*
* Parameter:
- * par The connection
+ * conn The connection
*/
void
-connection_timeout(void *par)
+connection_timeout(connection_t *conn)
{
- connection_t *conn = (connection_t *) par;
if (++conn->num_timeouts > MAX_CONN_TIMEOUTS)
handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT);
@@ -1602,17 +1606,19 @@ connection_timeout(void *par)
* Handle timeout of a sent command.
*
* Parameter:
- * par The CCB
+ * ccb The CCB
*/
void
-ccb_timeout(void *par)
+ccb_timeout(ccb_t *ccb)
{
- ccb_t *ccb = (ccb_t *) par;
connection_t *conn = ccb->connection;
ccb->total_tries++;
+ DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n",
+ ccb->num_timeouts+1, ccb->total_tries, ccb->disp));
+
if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
ccb->total_tries > MAX_CCB_TRIES ||
ccb->disp <= CCBDISP_FREE ||
@@ -1631,3 +1637,4 @@ ccb_timeout(void *par)
callout_schedule(&ccb->timeout, COMMAND_TIMEOUT);
}
}
+
Index: src/sys/dev/iscsi/iscsi_text.c
diff -u src/sys/dev/iscsi/iscsi_text.c:1.9 src/sys/dev/iscsi/iscsi_text.c:1.10
--- src/sys/dev/iscsi/iscsi_text.c:1.9 Sat May 30 16:12:34 2015
+++ src/sys/dev/iscsi/iscsi_text.c Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_text.c,v 1.9 2015/05/30 16:12:34 joerg Exp $ */
+/* $NetBSD: iscsi_text.c,v 1.10 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
@@ -34,6 +34,9 @@
#include <sys/md5.h>
#include <sys/cprng.h>
+/* define to send T_BIGNUM in hex format instead of base64 */
+/* #define ISCSI_HEXBIGNUMS */
+
#define isdigit(x) ((x) >= '0' && (x) <= '9')
#define toupper(x) ((x) & ~0x20)
@@ -107,12 +110,6 @@ typedef enum
/* maximum known key */
#define MAX_KEY K_TargetPortalGroupTag
-
-#undef DEBOUT
-#define DEBOUT(x) printf x
-
-
-
/* value types */
typedef enum
{ /* Value is... */
@@ -636,7 +633,22 @@ my_strcpy(uint8_t *dest, const uint8_t *
STATIC unsigned
put_bignumval(negotiation_parameter_t *par, uint8_t *buf)
{
+#ifdef ISCSI_HEXBIGNUMS
+ int k, c;
+
+ my_strcpy(buf, "0x");
+ for (k=0; k<par->list_num; ++k) {
+ c = par->val.sval[k] >> 4;
+ buf[2+2*k] = c < 10 ? '0' + c : 'a' + (c-10);
+ c = par->val.sval[k] & 0xf;
+ buf[2+2*k+1] = c < 10 ? '0' + c : 'a' + (c-10);
+ }
+ buf[2+2*k] = '\0';
+
+ return 2+2*par->list_num;
+#else
return base64_encode(par->val.sval, par->list_num, buf);
+#endif
}
/*
@@ -817,7 +829,11 @@ parameter_size(negotiation_parameter_t *
case T_BIGNUM:
/* list_num holds value size */
+#ifdef ISCSI_HEXBIGNUMS
+ size += 2 + 2*par->list_num;
+#else
size += base64_enclen(par->list_num);
+#endif
i = par->list_num;
break;
@@ -839,11 +855,13 @@ parameter_size(negotiation_parameter_t *
break;
case T_RANGE:
- assert((i + 1) < par->list_num);
- size += snprintf(buf, sizeof(buf), "%d~%d",
- par->val.nval[i],
- par->val.nval[i + 1]);
- i++;
+ if (i+1 < par->list_num) {
+ size += snprintf(buf, sizeof(buf), "%d~%d",
+ par->val.nval[i],
+ par->val.nval[i + 1]);
+ i++;
+ } else
+ DEBOUT(("Incomplete range parameter\n"));
break;
case T_SESS:
Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.8 src/sys/dev/iscsi/iscsi_utils.c:1.9
--- src/sys/dev/iscsi/iscsi_utils.c:1.8 Sat May 30 18:12:09 2015
+++ src/sys/dev/iscsi/iscsi_utils.c Sun May 29 13:51:16 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_utils.c,v 1.8 2015/05/30 18:12:09 joerg Exp $ */
+/* $NetBSD: iscsi_utils.c,v 1.9 2016/05/29 13:51:16 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -34,13 +34,14 @@
#include <sys/buf.h>
#include <sys/socketvar.h>
#include <sys/bswap.h>
+#include <sys/atomic.h>
#ifdef ISCSI_DEBUG
/* debug helper routine */
void
-dump(void *buff, int len)
+iscsi_hexdump(void *buff, int len)
{
uint8_t *bp = (uint8_t *) buff;
int i;
@@ -219,23 +220,23 @@ get_ccb(connection_t *conn, bool waitok)
{
ccb_t *ccb;
session_t *sess = conn->session;
- int s;
+ mutex_enter(&sess->lock);
do {
- s = splbio();
ccb = TAILQ_FIRST(&sess->ccb_pool);
- if (ccb != NULL)
- TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
- splx(s);
-
DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
- if (ccb == NULL) {
+
+ if (ccb != NULL) {
+ TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
+ } else {
if (!waitok || conn->terminating) {
+ mutex_exit(&sess->lock);
return NULL;
}
- tsleep(&sess->ccb_pool, PWAIT, "get_ccb", 0);
+ cv_wait(&sess->ccb_cv, &sess->lock);
}
} while (ccb == NULL);
+ mutex_exit(&sess->lock);
ccb->flags = 0;
ccb->xs = NULL;
@@ -245,7 +246,11 @@ get_ccb(connection_t *conn, bool waitok)
ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24);
ccb->disp = CCBDISP_NOWAIT;
ccb->connection = conn;
- conn->usecount++;
+ atomic_inc_uint(&conn->usecount);
+
+ DEBC(conn, 5, (
+ "get_ccb: ccb = %p, usecount = %d\n",
+ ccb, conn->usecount));
return ccb;
}
@@ -262,14 +267,21 @@ free_ccb(ccb_t *ccb)
{
session_t *sess = ccb->session;
pdu_t *pdu;
- int s;
+
+ DEBC(ccb->connection, 5, (
+ "free_ccb: ccb = %p, usecount = %d\n",
+ ccb, ccb->connection->usecount-1));
KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
- ccb->connection->usecount--;
+ atomic_dec_uint(&ccb->connection->usecount);
ccb->connection = NULL;
+ if (ccb->disp > CCBDISP_NOWAIT) {
+ DEBOUT(("Freeing CCB with disp %d\n",ccb->disp));
+ }
+
ccb->disp = CCBDISP_UNUSED;
/* free temporary data */
@@ -285,11 +297,11 @@ free_ccb(ccb_t *ccb)
free_pdu(pdu);
}
- s = splbio();
+ mutex_enter(&sess->lock);
TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
- splx(s);
+ mutex_exit(&sess->lock);
- wakeup(&sess->ccb_pool);
+ cv_broadcast(&sess->ccb_cv);
}
/*
@@ -314,10 +326,10 @@ create_ccbs(session_t *sess)
ccb->ITT = i | sid;
ccb->session = sess;
- callout_init(&ccb->timeout, 0);
- callout_setfunc(&ccb->timeout, ccb_timeout, ccb);
+ callout_init(&ccb->timeout, CALLOUT_MPSAFE);
+ callout_setfunc(&ccb->timeout, ccb_timeout_co, ccb);
- /*DEB (9, ("Create_ccbs: ccb %x itt %x\n", ccb, ccb->ITT)); */
+ DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ITT));
TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain);
}
}
@@ -353,6 +365,8 @@ throttle_ccb(ccb_t *ccb, bool yes)
{
session_t *sess;
+ KASSERT(mutex_owned(&sess->lock));
+
sess = ccb->session;
if (yes) {
KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
@@ -381,7 +395,6 @@ wake_ccb(ccb_t *ccb, uint32_t status)
{
ccb_disp_t disp;
connection_t *conn;
- int s;
conn = ccb->connection;
@@ -392,11 +405,11 @@ wake_ccb(ccb_t *ccb, uint32_t status)
callout_stop(&ccb->timeout);
- s = splbio();
+ mutex_enter(&conn->lock);
disp = ccb->disp;
if (disp <= CCBDISP_NOWAIT ||
(disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
- splx(s);
+ mutex_exit(&conn->lock);
return;
}
@@ -406,7 +419,7 @@ wake_ccb(ccb_t *ccb, uint32_t status)
/* change the disposition so nobody tries this again */
ccb->disp = CCBDISP_BUSY;
ccb->status = status;
- splx(s);
+ mutex_exit(&conn->lock);
switch (disp) {
case CCBDISP_FREE:
@@ -414,7 +427,7 @@ wake_ccb(ccb_t *ccb, uint32_t status)
break;
case CCBDISP_WAIT:
- wakeup(ccb);
+ cv_broadcast(&conn->ccb_cv);
break;
case CCBDISP_SCSIPI:
@@ -451,22 +464,24 @@ pdu_t *
get_pdu(connection_t *conn, bool waitok)
{
pdu_t *pdu;
- int s;
+ mutex_enter(&conn->lock);
do {
- s = splbio();
pdu = TAILQ_FIRST(&conn->pdu_pool);
if (pdu != NULL)
TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
- splx(s);
DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
+
if (pdu == NULL) {
- if (!waitok || conn->terminating)
+ if (!waitok || conn->terminating) {
+ mutex_exit(&conn->lock);
return NULL;
- tsleep(&conn->pdu_pool, PWAIT, "get_pdu_c", 0);
+ }
+ cv_wait(&conn->conn_cv, &conn->lock);
}
} while (pdu == NULL);
+ mutex_exit(&conn->lock);
memset(pdu, 0, sizeof(pdu_t));
pdu->connection = conn;
@@ -487,29 +502,27 @@ free_pdu(pdu_t *pdu)
{
connection_t *conn = pdu->connection;
pdu_disp_t pdisp;
- int s;
if (PDUDISP_UNUSED == (pdisp = pdu->disp))
return;
pdu->disp = PDUDISP_UNUSED;
+ mutex_enter(&conn->lock);
if (pdu->flags & PDUF_INQUEUE) {
TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
pdu->flags &= ~PDUF_INQUEUE;
}
-
- if (pdisp == PDUDISP_SIGNAL)
- wakeup(pdu);
+ mutex_exit(&conn->lock);
/* free temporary data in this PDU */
if (pdu->temp_data)
free(pdu->temp_data, M_TEMP);
- s = splbio();
+ mutex_enter(&conn->lock);
TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
- splx(s);
+ mutex_exit(&conn->lock);
- wakeup(&conn->pdu_pool);
+ cv_broadcast(&conn->conn_cv);
}
/*