Module Name: src
Committed By: mlelstv
Date: Sat Dec 29 11:05:30 UTC 2012
Modified Files:
src/sys/dev/iscsi: iscsi_globals.h iscsi_ioctl.c iscsi_main.c
iscsi_rcv.c iscsi_send.c iscsi_test.c iscsi_utils.c
Log Message:
- defer session cleanup to not force detachments
- use more and explicit locking
- improve connection recovery
- use larger timeouts
- handle ccb buffer underflow correctly
- simplify throttling code
Sessions can now temporarily exist without a valid
connection, you also need to update iscsid(8).
To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/iscsi/iscsi_globals.h \
src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/iscsi/iscsi_main.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/iscsi/iscsi_rcv.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/iscsi/iscsi_send.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/iscsi/iscsi_test.c
cvs rdiff -u -r1.4 -r1.5 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.5 src/sys/dev/iscsi/iscsi_globals.h:1.6
--- src/sys/dev/iscsi/iscsi_globals.h:1.5 Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_globals.h Sat Dec 29 11:05:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_globals.h,v 1.5 2012/08/12 13:26:18 mlelstv Exp $ */
+/* $NetBSD: iscsi_globals.h,v 1.6 2012/12/29 11:05:29 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -84,7 +84,7 @@ ExpCmdSN in iscsi_send.c, and is enabled
effectively says "don't bother testing these values", and is used right
now only in iscsi_send.c.
*/
-#define ISCSI_TROTTLING_ENABLED 1
+#define ISCSI_THROTTLING_ENABLED 1
#define ISCSI_SERVER_TRUSTED 1
/*
@@ -131,14 +131,15 @@ now only in iscsi_send.c.
/* CCB Flags */
-#define CCBF_COMPLETE 0x01 /* received status */
-#define CCBF_RESENT 0x02 /* ccb was resent */
-#define CCBF_SENDTARGET 0x04 /* SendTargets text request, not negotiation */
-#define CCBF_WAITING 0x08 /* CCB is waiting for MaxCmdSN, wake it up */
-#define CCBF_GOT_RSP 0x10 /* Got at least one response to this request */
-#define CCBF_REASSIGN 0x20 /* Command can be reassigned */
-#define CCBF_OTHERCONN 0x40 /* a logout for a different connection */
-
+#define CCBF_COMPLETE 0x0001 /* received status */
+#define CCBF_RESENT 0x0002 /* ccb was resent */
+#define CCBF_SENDTARGET 0x0004 /* SendTargets text request, not negotiation */
+#define CCBF_WAITING 0x0008 /* CCB is waiting for MaxCmdSN, wake it up */
+#define CCBF_GOT_RSP 0x0010 /* Got at least one response to this request */
+#define CCBF_REASSIGN 0x0020 /* Command can be reassigned */
+#define CCBF_OTHERCONN 0x0040 /* a logout for a different connection */
+#define CCBF_WAITQUEUE 0x0080 /* CCB is on waiting queue */
+#define CCBF_THROTTLING 0x0100 /* CCB is on throttling queue */
/* --------------------------- Global Types ------------------------------- */
@@ -543,7 +544,8 @@ extern struct cfattach iscsi_ca; /* the
extern session_list_t iscsi_sessions; /* the list of sessions */
-extern connection_list_t iscsi_cleanup_list; /* connections to clean up */
+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 */
@@ -602,9 +604,6 @@ void dump(void *buf, int len);
/* Critical section macros */
-#define CS_BEGIN { int s = splbio ();
-#define CS_END splx (s); }
-
/* misc stuff */
#define min(a, b) ((a) < (b)) ? (a) : (b)
#define max(a, b) ((a) < (b)) ? (b) : (a)
@@ -757,7 +756,7 @@ int iscsidetach(device_t, int);
void iscsi_done(ccb_t *);
int map_session(session_t *);
-void unmap_session(session_t *);
+int unmap_session(session_t *);
/* in iscsi_send.c */
@@ -801,12 +800,12 @@ uint32_t gen_digest_2(void *, int, void
void create_ccbs(session_t *);
ccb_t *get_ccb(connection_t *, bool);
void free_ccb(ccb_t *);
-void wake_ccb(ccb_t *);
-void complete_ccb(ccb_t *);
+void suspend_ccb(ccb_t *, bool);
+void throttle_ccb(ccb_t *, bool);
+void wake_ccb(ccb_t *, uint32_t);
void create_pdus(connection_t *);
-pdu_t *get_pdu(connection_t *);
-pdu_t *get_pdu_c(connection_t *, bool);
+pdu_t *get_pdu(connection_t *, bool);
void free_pdu(pdu_t *);
void init_sernum(sernum_buffer_t *);
Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.5 src/sys/dev/iscsi/iscsi_ioctl.c:1.6
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.5 Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_ioctl.c Sat Dec 29 11:05:29 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_ioctl.c,v 1.5 2012/08/12 13:26:18 mlelstv Exp $ */
+/* $NetBSD: iscsi_ioctl.c,v 1.6 2012/12/29 11:05:29 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -90,6 +90,7 @@ register_event(iscsi_register_event_para
{
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,7 +102,7 @@ register_event(iscsi_register_event_para
TAILQ_INIT(&handler->events);
/* create a unique ID */
- CS_BEGIN;
+ s = splbio();
do {
++handler_id;
} while (!handler_id || find_handler(handler_id) != NULL);
@@ -112,9 +113,9 @@ register_event(iscsi_register_event_para
TAILQ_INSERT_TAIL(&event_handlers, handler, link);
if (was_empty) {
- wakeup(&iscsi_cleanup_list);
+ wakeup(&iscsi_cleanupc_list);
}
- CS_END;
+ splx(s);
par->status = ISCSI_STATUS_SUCCESS;
DEB(5, ("Register Event OK, ID %d\n", par->event_id));
@@ -134,6 +135,7 @@ deregister_event(iscsi_register_event_pa
{
event_handler_t *handler;
event_t *evt;
+ int s;
handler = find_handler(par->event_id);
if (handler == NULL) {
@@ -141,9 +143,11 @@ deregister_event(iscsi_register_event_pa
par->status = ISCSI_STATUS_INVALID_EVENT_ID;
return;
}
- CS_BEGIN;
+
+ s = splbio();
TAILQ_REMOVE(&event_handlers, handler, link);
- CS_END;
+ splx(s);
+
if (handler->waiter != NULL) {
handler->waiter->status = ISCSI_STATUS_EVENT_DEREGISTERED;
wakeup(handler->waiter);
@@ -238,10 +242,12 @@ 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();
TAILQ_FOREACH(curr, &event_handlers, link) {
evt = malloc(sizeof(*evt), M_TEMP, M_WAITOK);
if (evt == NULL) {
@@ -251,14 +257,14 @@ add_event(iscsi_event_t kind, uint32_t s
evt->session_id = sid;
evt->connection_id = cid;
evt->reason = reason;
- CS_BEGIN;
+
TAILQ_INSERT_TAIL(&curr->events, evt, link);
if (curr->waiter != NULL) {
wakeup(curr->waiter);
curr->waiter = NULL;
}
- CS_END;
}
+ splx(s);
}
@@ -273,6 +279,8 @@ add_event(iscsi_event_t kind, uint32_t s
* list has changed at all. If not, the event is deregistered.
* 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
@@ -367,11 +375,14 @@ session_t *
find_session(uint32_t id)
{
session_t *curr;
+ int s;
+ s = splbio();
TAILQ_FOREACH(curr, &iscsi_sessions, sessions)
if (curr->id == id) {
break;
}
+ splx(s);
return curr;
}
@@ -389,11 +400,14 @@ connection_t *
find_connection(session_t *session, uint32_t id)
{
connection_t *curr;
+ int s;
+ s = splbio();
TAILQ_FOREACH(curr, &session->conn_list, connections)
if (curr->id == id) {
break;
}
+ splx(s);
return curr;
}
@@ -413,6 +427,7 @@ 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",
@@ -427,13 +442,15 @@ kill_connection(connection_t *conn, uint
}
if (!recover || conn->destroy) {
- CS_BEGIN;
+
+ 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);
}
- CS_END;
+ splx(s);
+
if (!conn->destroy) {
DEBC(conn, 1, ("Kill_connection setting destroy flag\n"));
conn->destroy = TRUE;
@@ -512,6 +529,7 @@ 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));
@@ -543,16 +561,21 @@ kill_session(session_t *session, uint32_
}
/* remove from session list */
+ s = splbio();
TAILQ_REMOVE(&iscsi_sessions, session, sessions);
+ splx(s);
session->sessions.tqe_next = NULL;
session->sessions.tqe_prev = NULL;
/* complete any throttled CCBs */
+ s = splbio();
while ((ccb = TAILQ_FIRST(&session->ccbs_throttled)) != NULL) {
- ccb->status = ISCSI_STATUS_LOGOUT;
- TAILQ_REMOVE(&session->ccbs_throttled, ccb, chain);
- complete_ccb(ccb);
+ throttle_ccb(ccb, FALSE);
+ splx(s);
+ wake_ccb(ccb, ISCSI_STATUS_LOGOUT);
+ s = splbio();
}
+ splx(s);
/*
* unmap first to give the system an opportunity to flush its buffers,
@@ -595,7 +618,7 @@ create_connection(iscsi_login_parameters
PTHREADOBJ p)
{
connection_t *connection;
- int rc;
+ int rc, s;
DEB(1, ("Create Connection for Session %d\n", session->id));
@@ -683,7 +706,7 @@ create_connection(iscsi_login_parameters
closef(connection->sock);
/* give receive thread time to exit */
- tsleep(connection, PWAIT, "settle", 20);
+ tsleep(connection, PWAIT, "settle", 2 * hz);
release_socket(connection->sock);
free(connection, M_DEVBUF);
@@ -709,15 +732,14 @@ create_connection(iscsi_login_parameters
return -1;
}
- CS_BEGIN;
+ 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;
- CS_END;
+ splx(s);
DEBC(connection, 5, ("Connection created successfully!\n"));
return 0;
@@ -742,7 +764,7 @@ STATIC int
recreate_connection(iscsi_login_parameters_t *par, session_t *session,
connection_t *connection, PTHREADOBJ p)
{
- int rc;
+ int rc, s;
ccb_t *ccb;
ccb_list_t old_waiting;
@@ -758,11 +780,19 @@ recreate_connection(iscsi_login_paramete
return EIO;
}
+ /* close old socket */
+ if (connection->sock != NULL) {
+ closef(connection->sock);
+ connection->sock = NULL;
+ }
+
if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
DEBOUT(("Invalid socket %d\n", par->socket));
par->status = ISCSI_STATUS_INVALID_SOCKET;
return rc;
}
+ DEBC(connection, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
+ par->socket, connection->sock));
/* close the file descriptor */
fd_close(par->socket);
@@ -773,14 +803,15 @@ recreate_connection(iscsi_login_paramete
connection->recover++;
connection->num_timeouts = 0;
connection->state = ST_SEC_NEG;
+ connection->HeaderDigest = 0;
+ connection->DataDigest = 0;
session->active_connections++;
TAILQ_INIT(&old_waiting);
- while ((ccb = TAILQ_FIRST(&connection->ccbs_waiting)) != NULL) {
- TAILQ_REMOVE(&connection->ccbs_waiting, ccb, chain);
- TAILQ_INSERT_TAIL(&old_waiting, ccb, chain);
- }
+ s = splbio();
+ TAILQ_CONCAT(&old_waiting, &connection->ccbs_waiting, chain);
+ splx(s);
init_sernum(&connection->StatSN_buf);
wakeup(connection);
@@ -789,8 +820,7 @@ recreate_connection(iscsi_login_paramete
DEBOUT(("Login failed (rc %d)\n", rc));
while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
TAILQ_REMOVE(&old_waiting, ccb, chain);
- ccb->status = rc;
- complete_ccb(ccb);
+ wake_ccb(ccb, rc);
}
/* Don't attempt to recover, there seems to be something amiss */
kill_connection(connection, rc, NO_LOGOUT, FALSE);
@@ -800,14 +830,17 @@ recreate_connection(iscsi_login_paramete
DEBC(connection, 9, ("Re-Login successful\n"));
par->status = ISCSI_STATUS_SUCCESS;
- CS_BEGIN;
+
+ s = splbio();
connection->state = ST_FULL_FEATURE;
session->mru_connection = connection;
- CS_END;
+ splx(s);
while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
TAILQ_REMOVE(&old_waiting, ccb, chain);
- TAILQ_INSERT_TAIL(&connection->ccbs_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 */
@@ -926,7 +959,7 @@ STATIC void
login(iscsi_login_parameters_t *par, PTHREADOBJ p)
{
session_t *session;
- int rc;
+ int rc, s;
DEB(99, ("ISCSI: login\n"));
@@ -967,9 +1000,9 @@ login(iscsi_login_parameters_t *par, PTH
return;
}
- CS_BEGIN;
+ s = splbio();
TAILQ_INSERT_HEAD(&iscsi_sessions, session, sessions);
- CS_END;
+ splx(s);
/* Session established, map LUNs? */
if (par->login_type == ISCSI_LOGINTYPE_MAP) {
@@ -1090,7 +1123,7 @@ restore_connection(iscsi_login_parameter
session_t *session;
connection_t *connection;
- DEB(5, ("ISCSI: restore_connection %d of session %d\n",
+ DEB(1, ("ISCSI: restore_connection %d of session %d\n",
par->connection_id, par->session_id));
if ((session = find_session(par->session_id)) == NULL) {
@@ -1470,15 +1503,15 @@ iscsi_cleanup_thread(void *par)
{
int s, rc;
connection_t *conn;
- session_t *sess;
+ session_t *sess, *nxt;
uint32_t status;
s = splbio();
- while ((conn = TAILQ_FIRST(&iscsi_cleanup_list)) != NULL ||
+ while ((conn = TAILQ_FIRST(&iscsi_cleanupc_list)) != NULL ||
iscsi_num_send_threads ||
!iscsi_detaching) {
if (conn != NULL) {
- TAILQ_REMOVE(&iscsi_cleanup_list, conn, connections);
+ TAILQ_REMOVE(&iscsi_cleanupc_list, conn, connections);
splx(s);
sess = conn->session;
@@ -1486,41 +1519,54 @@ iscsi_cleanup_thread(void *par)
DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n"));
while (conn->sendproc || conn->rcvproc)
- tsleep(conn, PWAIT, "termwait", 20);
+ tsleep(conn, PWAIT, "termwait", hz);
while (conn->usecount > 0)
- tsleep(conn, PWAIT, "finalwait", 20);
+ tsleep(conn, PWAIT, "finalwait", hz);
callout_stop(&conn->timeout);
closef(conn->sock);
free(conn, M_DEVBUF);
- if (!(--sess->total_connections)) {
- /* just in case */
- unmap_session(sess);
-
- /* unlink and free the session */
- if (sess->sessions.tqe_next != NULL ||
- sess->sessions.tqe_prev != NULL)
- TAILQ_REMOVE(&iscsi_sessions, sess, sessions);
+ --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)
free(sess->target_list, M_TEMP);
-
/* notify event handlers of session shutdown */
add_event(ISCSI_SESSION_TERMINATED, sess->id, 0, status);
-
free(sess, M_DEVBUF);
+
+ DEB(1, ("Cleanup: session ended %d\n", sess->id));
+ s = splbio();
}
+ splx(s);
DEB(5, ("Cleanup: Done\n"));
s = splbio();
} else {
- /* Go to sleep, but wake up every 30 seconds to check for */
- /* dead event handlers */
+ /* Go to sleep, but wake up every 30 seconds to
+ * check for dead event handlers */
splx(s);
- rc = tsleep(&iscsi_cleanup_list, PWAIT, "cleanup",
+ rc = tsleep(&iscsi_cleanupc_list, PWAIT, "cleanup",
(TAILQ_FIRST(&event_handlers)) ? 30 * hz : 0);
s = splbio();
/* if timed out, not woken up */
@@ -1563,7 +1609,7 @@ int
iscsiioctl(dev_t dev, u_long cmd, void *addr, int flag, PTHREADOBJ p)
{
- DEB(99, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
+ DEB(1, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
switch (cmd) {
case ISCSI_GET_VERSION:
Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.6 src/sys/dev/iscsi/iscsi_main.c:1.7
--- src/sys/dev/iscsi/iscsi_main.c:1.6 Sun Aug 12 13:26:18 2012
+++ src/sys/dev/iscsi/iscsi_main.c Sat Dec 29 11:05:30 2012
@@ -55,7 +55,9 @@ iscsi_softc_t *sc = NULL;
session_list_t iscsi_sessions = TAILQ_HEAD_INITIALIZER(iscsi_sessions);
/* connections to clean up */
-connection_list_t iscsi_cleanup_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanup_list);
+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;
@@ -207,8 +209,8 @@ iscsi_detach(device_t self, int flags)
kill_all_sessions();
iscsi_detaching = TRUE;
while (iscsi_cleanproc != NULL) {
- wakeup(&iscsi_cleanup_list);
- tsleep(&iscsi_cleanup_list, PWAIT, "detach_wait", 20);
+ wakeup(&iscsi_cleanupc_list);
+ tsleep(&iscsi_cleanupc_list, PWAIT, "detach_wait", 20 * hz);
}
return 0;
}
@@ -329,17 +331,23 @@ map_session(session_t *session)
* telling the config system that the adapter has detached.
*
* Parameter: the session pointer
+ *
+ * Returns: 1 on success, 0 on failure
*/
-void
+int
unmap_session(session_t *session)
{
device_t dev;
+ int rv = 1;
if ((dev = session->child_dev) != NULL) {
session->child_dev = NULL;
- config_detach(dev, DETACH_FORCE);
+ if (config_detach(dev, 0))
+ rv = 0;
}
+
+ return rv;
}
/******************************************************************************/
@@ -361,6 +369,7 @@ iscsi_scsipi_request(struct scsipi_chann
struct scsipi_xfer *xs;
session_t *session;
int flags;
+ struct scsipi_xfer_mode *xm;
session = (session_t *) adapt; /* adapter is first field in session */
@@ -400,6 +409,9 @@ iscsi_scsipi_request(struct scsipi_chann
case ADAPTER_REQ_SET_XFER_MODE:
DEB(5, ("ISCSI: scsipi_request SET_XFER_MODE\n"));
+ xm = (struct scsipi_xfer_mode *)arg;
+ xm->xm_mode = PERIPH_CAP_TQING;
+ scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm);
return;
default:
@@ -478,8 +490,6 @@ iscsi_done(ccb_t *ccb)
scsipi_done(xs);
DEB(99, ("scsipi_done returned\n"));
}
-
- free_ccb(ccb);
}
/* Kernel Module support */
Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.3 src/sys/dev/iscsi/iscsi_rcv.c:1.4
--- src/sys/dev/iscsi/iscsi_rcv.c:1.3 Sun Jun 24 17:01:35 2012
+++ src/sys/dev/iscsi/iscsi_rcv.c Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_rcv.c,v 1.3 2012/06/24 17:01:35 mlelstv Exp $ */
+/* $NetBSD: iscsi_rcv.c,v 1.4 2012/12/29 11:05:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -278,7 +278,9 @@ collect_text_data(pdu_t *pdu, ccb_t *req
nlen = req_ccb->text_len + pdu->temp_data_len;
/* Note: allocate extra 2 bytes for text terminator */
if ((newp = malloc(nlen + 2, M_TEMP, M_WAITOK)) == NULL) {
+ DEBOUT(("Collect Text Data: Out of Memory, ccb = %p\n", req_ccb));
req_ccb->status = ISCSI_STATUS_NO_RESOURCES;
+ /* XXX where is CCB freed? */
return 1;
}
memcpy(newp, req_ccb->text_data, req_ccb->text_len);
@@ -374,8 +376,7 @@ check_CmdSN(connection_t *conn, uint32_t
uint32_t sn = ntohl(nw_sn);
ccb_t *ccb, *nxt;
- for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nxt) {
- nxt = TAILQ_NEXT(ccb, chain);
+ TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nxt) {
DEBC(conn, 10,
("CheckCmdSN - CmdSN=%d, ExpCmdSn=%d, waiting=%p, flags=%x\n",
ccb->CmdSN, sn, ccb->pdu_waiting, ccb->flags));
@@ -429,10 +430,7 @@ receive_login_pdu(connection_t *conn, pd
DEBC(conn, 1, ("Login problem - Class = %x, Detail = %x\n",
pdu->pdu.p.login_rsp.StatusClass,
pdu->pdu.p.login_rsp.StatusDetail));
-
- req_ccb->status = ISCSI_STATUS_LOGIN_FAILED;
- /* XXX */
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, ISCSI_STATUS_LOGIN_FAILED);
return 0;
}
@@ -511,6 +509,7 @@ receive_logout_pdu(connection_t *conn, p
{
bool otherconn;
uint8_t response;
+ uint32_t status;
otherconn = (req_ccb != NULL) ? (req_ccb->flags & CCBF_OTHERCONN) != 0 : 1;
response = pdu->pdu.OpcodeSpecific [0];
@@ -526,16 +525,16 @@ receive_logout_pdu(connection_t *conn, p
switch (response) {
case 0:
- req_ccb->status = ISCSI_STATUS_SUCCESS;
+ status = ISCSI_STATUS_SUCCESS;
break;
case 1:
- req_ccb->status = ISCSI_STATUS_LOGOUT_CID_NOT_FOUND;
+ status = ISCSI_STATUS_LOGOUT_CID_NOT_FOUND;
break;
case 2:
- req_ccb->status = ISCSI_STATUS_LOGOUT_RECOVERY_NS;
+ status = ISCSI_STATUS_LOGOUT_RECOVERY_NS;
break;
default:
- req_ccb->status = ISCSI_STATUS_LOGOUT_ERROR;
+ status = ISCSI_STATUS_LOGOUT_ERROR;
break;
}
@@ -546,7 +545,7 @@ receive_logout_pdu(connection_t *conn, p
refconn->Time2Retain = ntohs(pdu->pdu.p.logout_rsp.Time2Retain);
}
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, status);
if (!otherconn && conn->state == ST_LOGOUT_SENT) {
conn->terminating = ISCSI_STATUS_LOGOUT;
@@ -641,14 +640,13 @@ receive_data_in_pdu(connection_t *conn,
/* successful transfer, reset recover count */
conn->recover = 0;
- if (done) {
- wake_ccb(req_ccb);
- }
- if (check_StatSN(conn, pdu->pdu.p.data_in.StatSN, done)) {
+ if (done)
+ wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
+ if (check_StatSN(conn, pdu->pdu.p.data_in.StatSN, done))
return -1;
- }
+
} else if (done && (req_ccb->flags & CCBF_COMPLETE)) {
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
}
/* else wait for command response */
@@ -699,6 +697,7 @@ receive_command_response_pdu(connection_
{
int len, rc;
bool done;
+ uint32_t status;
/* Read any provided data */
if (pdu->temp_data_len && req_ccb != NULL && req_ccb->sense_len_req) {
@@ -726,23 +725,23 @@ receive_command_response_pdu(connection_
conn->recover = 0; /* successful transfer, reset recover count */
if (pdu->pdu.OpcodeSpecific[0]) { /* Response */
- req_ccb->status = ISCSI_STATUS_TARGET_FAILURE;
+ status = ISCSI_STATUS_TARGET_FAILURE;
} else {
switch (pdu->pdu.OpcodeSpecific[1]) { /* Status */
case 0x00:
- /* success */
+ status = ISCSI_STATUS_SUCCESS;
break;
case 0x02:
- req_ccb->status = ISCSI_STATUS_CHECK_CONDITION;
+ status = ISCSI_STATUS_CHECK_CONDITION;
break;
case 0x08:
- req_ccb->status = ISCSI_STATUS_TARGET_BUSY;
+ status = ISCSI_STATUS_TARGET_BUSY;
break;
default:
- req_ccb->status = ISCSI_STATUS_TARGET_ERROR;
+ status = ISCSI_STATUS_TARGET_ERROR;
break;
}
}
@@ -750,7 +749,7 @@ receive_command_response_pdu(connection_
if (pdu->pdu.Flags & (FLAG_OVERFLOW | FLAG_UNDERFLOW))
req_ccb->residual = ntohl(pdu->pdu.p.response.ResidualCount);
- done = req_ccb->status || sn_empty(&req_ccb->DataSN_buf);
+ done = status || sn_empty(&req_ccb->DataSN_buf);
DEBC(conn, 10, ("Rx Command Response rsp = %x, status = %x\n",
pdu->pdu.OpcodeSpecific[0], pdu->pdu.OpcodeSpecific[1]));
@@ -758,7 +757,7 @@ receive_command_response_pdu(connection_
rc = check_StatSN(conn, pdu->pdu.p.response.StatSN, done);
if (done)
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, status);
return rc;
}
@@ -836,6 +835,7 @@ receive_reject_pdu(connection_t *conn, p
{
pdu_header_t *hpdu;
ccb_t *req_ccb;
+ uint32_t status;
DEBOUT(("Received Reject PDU, reason = %x, data_len = %d\n",
pdu->pdu.OpcodeSpecific[0], pdu->temp_data_len));
@@ -864,23 +864,23 @@ receive_reject_pdu(connection_t *conn, p
case REJECT_SNACK:
case REJECT_PROTOCOL_ERROR:
- req_ccb->status = ISCSI_STATUS_PROTOCOL_ERROR;
+ status = ISCSI_STATUS_PROTOCOL_ERROR;
break;
case REJECT_CMD_NOT_SUPPORTED:
- req_ccb->status = ISCSI_STATUS_CMD_NOT_SUPPORTED;
+ status = ISCSI_STATUS_CMD_NOT_SUPPORTED;
break;
case REJECT_INVALID_PDU_FIELD:
- req_ccb->status = ISCSI_STATUS_PDU_ERROR;
+ status = ISCSI_STATUS_PDU_ERROR;
break;
default:
- req_ccb->status = ISCSI_STATUS_GENERAL_ERROR;
+ status = ISCSI_STATUS_GENERAL_ERROR;
break;
}
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, status);
handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR,
LOGOUT_CONNECTION);
}
@@ -901,6 +901,7 @@ receive_reject_pdu(connection_t *conn, p
STATIC int
receive_task_management_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb)
{
+ uint32_t status;
DEBC(conn, 2, ("Received Task Management PDU, response %d, req_ccb %p\n",
pdu->pdu.OpcodeSpecific[0], req_ccb));
@@ -908,34 +909,34 @@ receive_task_management_pdu(connection_t
if (req_ccb != NULL) {
switch (pdu->pdu.OpcodeSpecific[0]) { /* Response */
case 0:
- req_ccb->status = ISCSI_STATUS_SUCCESS;
+ status = ISCSI_STATUS_SUCCESS;
break;
case 1:
- req_ccb->status = ISCSI_STATUS_TASK_NOT_FOUND;
+ status = ISCSI_STATUS_TASK_NOT_FOUND;
break;
case 2:
- req_ccb->status = ISCSI_STATUS_LUN_NOT_FOUND;
+ status = ISCSI_STATUS_LUN_NOT_FOUND;
break;
case 3:
- req_ccb->status = ISCSI_STATUS_TASK_ALLEGIANT;
+ status = ISCSI_STATUS_TASK_ALLEGIANT;
break;
case 4:
- req_ccb->status = ISCSI_STATUS_CANT_REASSIGN;
+ status = ISCSI_STATUS_CANT_REASSIGN;
break;
case 5:
- req_ccb->status = ISCSI_STATUS_FUNCTION_UNSUPPORTED;
+ status = ISCSI_STATUS_FUNCTION_UNSUPPORTED;
break;
case 6:
- req_ccb->status = ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED;
+ status = ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED;
break;
case 255:
- req_ccb->status = ISCSI_STATUS_FUNCTION_REJECTED;
+ status = ISCSI_STATUS_FUNCTION_REJECTED;
break;
default:
- req_ccb->status = ISCSI_STATUS_UNKNOWN_REASON;
+ status = ISCSI_STATUS_UNKNOWN_REASON;
break;
}
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, status);
}
check_StatSN(conn, pdu->pdu.p.task_rsp.StatSN, TRUE);
@@ -982,7 +983,7 @@ receive_nop_in_pdu(connection_t *conn, p
/* and advance StatSN */
check_CmdSN(conn, pdu->pdu.p.nop_in.ExpCmdSN);
- wake_ccb(req_ccb);
+ wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS);
check_StatSN(conn, pdu->pdu.p.nop_in.StatSN, TRUE);
}
@@ -1007,7 +1008,7 @@ receive_pdu(connection_t *conn, pdu_t *p
{
ccb_t *req_ccb;
ccb_list_t waiting;
- int rc;
+ int rc, s;
uint32_t MaxCmdSN, digest;
session_t *sess = conn->session;
@@ -1131,24 +1132,22 @@ receive_pdu(connection_t *conn, pdu_t *p
*/
if (MaxCmdSN != sess->MaxCmdSN) {
sess->MaxCmdSN = MaxCmdSN;
-#if 0
-/* XXX - agc */
- if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL ||
- !sn_a_lt_b(sess->CmdSN, MaxCmdSN))
- return 0;
-#else
if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL)
return 0;
-#endif
DEBC(conn, 1, ("Unthrottling - MaxCmdSN = %d\n", MaxCmdSN));
- CS_BEGIN;
+ s = splbio();
TAILQ_INIT(&waiting);
- TAILQ_CONCAT(&waiting, &sess->ccbs_throttled, chain);
- CS_END;
+ while ((req_ccb = TAILQ_FIRST(&sess->ccbs_throttled)) != NULL) {
+ throttle_ccb(req_ccb, FALSE);
+ TAILQ_INSERT_TAIL(&waiting, req_ccb, chain);
+ }
+ splbio();
+
while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
TAILQ_REMOVE(&waiting, req_ccb, chain);
+
DEBC(conn, 1, ("Unthrottling - ccb = %p, disp = %d\n",
req_ccb, req_ccb->disp));
@@ -1181,7 +1180,7 @@ iscsi_rcv_thread(void *par)
do {
while (!conn->terminating) {
- pdu = get_pdu(conn);
+ pdu = get_pdu(conn, TRUE);
pdu->uio.uio_iov = pdu->io_vec;
UIO_SETUP_SYSSPACE(&pdu->uio);
pdu->uio.uio_iovcnt = 1;
@@ -1216,7 +1215,7 @@ iscsi_rcv_thread(void *par)
}
}
if (!conn->destroy) {
- tsleep(conn, PRIBIO, "conn_idle", 0);
+ tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
}
} while (!conn->destroy);
Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.7 src/sys/dev/iscsi/iscsi_send.c:1.8
--- src/sys/dev/iscsi/iscsi_send.c:1.7 Sun Sep 9 06:06:29 2012
+++ src/sys/dev/iscsi/iscsi_send.c Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_send.c,v 1.7 2012/09/09 06:06:29 mhitch Exp $ */
+/* $NetBSD: iscsi_send.c,v 1.8 2012/12/29 11:05:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -140,11 +140,13 @@ 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, "
"no active connection\n",
sess->id, oldconn->id));
+ /* XXX here we need to abort the waiting CCBs */
return;
}
@@ -170,13 +172,21 @@ reassign_tasks(connection_t *oldconn)
DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n",
sess->id, oldconn->id, conn->id, no_tm));
- TAILQ_FOREACH(ccb, &oldconn->ccbs_waiting, chain) {
+
+ /* XXX reassign waiting CCBs to new connection */
+
+ while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
/* Copy PDU contents (PDUs are bound to connection) */
- if ((pdu = get_pdu(conn)) == NULL) {
+ if ((pdu = get_pdu(conn, TRUE)) == NULL) {
break;
}
+
+ /* adjust CCB and clone PDU for new connection */
+ TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
+
opdu = ccb->pdu_waiting;
*pdu = *opdu;
+
/* restore overwritten back ptr */
pdu->connection = conn;
@@ -196,34 +206,45 @@ reassign_tasks(connection_t *oldconn)
pdu->save_iovec [0].iov_len =
(conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
+
+ /* link new PDU into old CCB */
ccb->pdu_waiting = pdu;
+ /* link new CCB into new connection */
ccb->connection = conn;
+ /* reset timeouts */
ccb->num_timeouts = 0;
+
+ /* fixup reference counts */
oldconn->usecount--;
conn->usecount++;
DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
ccb, opdu, pdu));
- /* free the old PDU */
+ /* kill temp pointer that is now referenced by the new PDU */
opdu->temp_data = NULL;
+
+ /* and free the old PDU */
free_pdu(opdu);
+
+ /* put ready CCB into waiting list of new connection */
+ s = splbio();
+ suspend_ccb(ccb, TRUE);
+ splx(s);
}
if (pdu == NULL) {
DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n"));
/* give up recovering, the other connection is screwed up as well... */
while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
- ccb->status = oldconn->terminating;
- wake_ccb(ccb);
+ wake_ccb(ccb, oldconn->terminating);
}
+ /* XXX some CCBs might have been moved to new connection, but how is the
+ * new connection handled or killed ? */
return;
}
- while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
- TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
- TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
-
+ TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) {
if (!no_tm) {
rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN);
}
@@ -347,19 +368,17 @@ iscsi_send_thread(void *par)
* We shutdown the socket here to force the receive
* thread to wake up
*/
- DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
+ DEBC(conn, 1, ("Closing Socket %p\n", conn->sock));
solock((struct socket *) fp->f_data);
soshutdown((struct socket *) fp->f_data, SHUT_RDWR);
sounlock((struct socket *) fp->f_data);
/* wake up any non-reassignable waiting CCBs */
- for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) {
- nccb = TAILQ_NEXT(ccb, chain);
+ TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nccb) {
if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) {
- DEBC(conn, 9, ("Terminating CCB %p (t=%p)\n",
+ DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n",
ccb,&ccb->timeout));
- ccb->status = conn->terminating;
- wake_ccb(ccb);
+ wake_ccb(ccb, conn->terminating);
} else {
callout_stop(&ccb->timeout);
ccb->num_timeouts = 0;
@@ -377,20 +396,26 @@ iscsi_send_thread(void *par)
}
}
- /* If there's another connection available, transfer pending tasks */
+ /* If there's another connection available, transfer pending tasks */
if (sess->active_connections &&
TAILQ_FIRST(&conn->ccbs_waiting) != NULL) {
- reassign_tasks (conn);
+ DEBC(conn, 1, ("Reassign Tasks\n"));
+ reassign_tasks(conn);
} else if (!conn->destroy && conn->Time2Wait) {
+ DEBC(conn, 1, ("Time2Wait\n"));
tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz);
+ DEBC(conn, 1, ("Time2Wait\n"));
}
/* notify event handlers of connection shutdown */
+ DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER"));
add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED
: ISCSI_RECOVER_CONNECTION,
sess->id, conn->id, conn->terminating);
+ DEBC(conn, 1, ("Waiting for conn_idle\n"));
if (!conn->destroy)
- tsleep(conn, PRIBIO, "conn_idle", 0);
+ tsleep(conn, PRIBIO, "conn_idle", 30 * hz);
+ DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy));
} while (!conn->destroy);
@@ -399,8 +424,7 @@ iscsi_send_thread(void *par)
/* wake up any waiting CCBs */
while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
- ccb->status = conn->terminating;
- wake_ccb(ccb);
+ wake_ccb(ccb, conn->terminating);
/* NOTE: wake_ccb will remove the CCB from the queue */
}
@@ -411,13 +435,13 @@ iscsi_send_thread(void *par)
sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
}
- TAILQ_INSERT_TAIL(&iscsi_cleanup_list, conn, connections);
+ TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections);
splx(s);
- wakeup(&iscsi_cleanup_list);
+ wakeup(&iscsi_cleanupc_list);
conn->sendproc = NULL;
- DEBC(conn, 5, ("Send thread exits\n"));
+ DEBC(conn, 1, ("Send thread exits\n"));
iscsi_num_send_threads--;
kthread_exit(0);
}
@@ -441,6 +465,7 @@ 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;
@@ -455,7 +480,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));
- CS_BEGIN;
+ s = splbio();
if (pdisp == PDUDISP_WAIT) {
ccb->pdu_waiting = pdu;
@@ -479,12 +504,12 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
if (prev_cdisp <= CCBDISP_NOWAIT)
- TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
+ suspend_ccb(ccb, TRUE);
if (cdisp == CCBDISP_WAIT)
tsleep(ccb, PWAIT, "sendpdu", 0);
}
- CS_END;
+ splx(s);
}
@@ -671,11 +696,11 @@ negotiate_login(connection_t *conn, pdu_
set_negotiated_parameters(tx_ccb);
DEBC(conn, 5, ("Login Successful!\n"));
- wake_ccb(tx_ccb);
+ wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
return;
}
- tx_pdu = get_pdu(conn);
+ tx_pdu = get_pdu(conn, TRUE);
if (tx_pdu == NULL)
return;
@@ -699,8 +724,7 @@ negotiate_login(connection_t *conn, pdu_
}
if (rc > 0) {
- tx_ccb->status = rc;
- wake_ccb(tx_ccb);
+ wake_ccb(tx_ccb, rc);
free_pdu(tx_pdu);
} else {
init_login_pdu(conn, tx_pdu, next);
@@ -754,7 +778,7 @@ acknowledge_text(connection_t *conn, pdu
{
pdu_t *tx_pdu;
- tx_pdu = get_pdu(conn);
+ tx_pdu = get_pdu(conn, TRUE);
if (tx_pdu == NULL)
return;
@@ -786,7 +810,7 @@ start_text_negotiation(connection_t *con
ccb = get_ccb(conn, TRUE);
if (ccb == NULL)
return;
- pdu = get_pdu(conn);
+ pdu = get_pdu(conn, TRUE);
if (pdu == NULL) {
free_ccb(ccb);
return;
@@ -830,10 +854,10 @@ negotiate_text(connection_t *conn, pdu_t
tx_ccb->text_data = rx_pdu->temp_data;
tx_ccb->text_len = rx_pdu->temp_data_len;
rx_pdu->temp_data = NULL;
- wake_ccb(tx_ccb);
+ wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
} else {
if (!(rx_pdu->pdu.Flags & FLAG_FINAL))
- tx_pdu = get_pdu(conn);
+ tx_pdu = get_pdu(conn, TRUE);
else
tx_pdu = NULL;
@@ -850,7 +874,7 @@ negotiate_text(connection_t *conn, pdu_t
send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
} else {
set_negotiated_parameters(tx_ccb);
- wake_ccb(tx_ccb);
+ wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS);
}
}
}
@@ -886,7 +910,7 @@ send_send_targets(session_t *session, ui
ccb = get_ccb(conn, TRUE);
if (ccb == NULL)
return conn->terminating;
- pdu = get_pdu(conn);
+ pdu = get_pdu(conn, TRUE);
if (pdu == NULL) {
free_ccb(ccb);
return conn->terminating;
@@ -939,7 +963,7 @@ send_nop_out(connection_t *conn, pdu_t *
if (rx_pdu != NULL) {
ccb = NULL;
- ppdu = get_pdu(conn);
+ ppdu = get_pdu(conn, TRUE);
if (ppdu == NULL)
return 1;
} else {
@@ -948,7 +972,7 @@ send_nop_out(connection_t *conn, pdu_t *
DEBOUT(("Can't get CCB in send_nop_out\n"));
return 1;
}
- ppdu = get_pdu_c(conn, FALSE);
+ ppdu = get_pdu(conn, FALSE);
if (ppdu == NULL) {
free_ccb(ccb);
DEBOUT(("Can't get PDU in send_nop_out\n"));
@@ -1001,7 +1025,7 @@ snack_missing(connection_t *conn, ccb_t
PDEBC(conn, 1, ("SNACK Missing type = %d, BegRun %d RunLength %d\n",
type, BegRun, RunLength));
- ppdu = get_pdu(conn);
+ ppdu = get_pdu(conn, TRUE);
if (ppdu == NULL)
return;
pdu = &ppdu->pdu;
@@ -1041,7 +1065,7 @@ send_snack(connection_t *conn, pdu_t *rx
PDEBC(conn, 1, ("Send SNACK type = %d\n", type));
- ppdu = get_pdu(conn);
+ ppdu = get_pdu(conn, TRUE);
if (ppdu == NULL)
return;
pdu = &ppdu->pdu;
@@ -1108,7 +1132,7 @@ send_login(connection_t *conn)
/* only if terminating (which couldn't possibly happen here, but...) */
if (ccb == NULL)
return conn->terminating;
- pdu = get_pdu(conn);
+ pdu = get_pdu(conn, TRUE);
if (pdu == NULL) {
free_ccb(ccb);
return conn->terminating;
@@ -1154,7 +1178,7 @@ send_logout(connection_t *conn, connecti
/* can only happen if terminating... */
if (ccb == NULL)
return conn->terminating;
- ppdu = get_pdu(conn);
+ ppdu = get_pdu(conn, TRUE);
if (ppdu == NULL) {
free_ccb(ccb);
return conn->terminating;
@@ -1221,7 +1245,7 @@ send_task_management(connection_t *conn,
/* can only happen if terminating... */
if (ccb == NULL)
return conn->terminating;
- ppdu = get_pdu(conn);
+ ppdu = get_pdu(conn, TRUE);
if (ppdu == NULL) {
free_ccb(ccb);
return conn->terminating;
@@ -1290,10 +1314,11 @@ send_data_out(connection_t *conn, pdu_t
while (totlen) {
len = min(totlen, conn->max_transfer);
- tx_pdu = get_pdu_c(conn, waitok);
+ tx_pdu = get_pdu(conn, waitok);
if (tx_pdu == NULL) {
DEBOUT(("No PDU in send_data_out\n"));
+ tx_ccb->disp = disp;
tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT);
@@ -1351,52 +1376,45 @@ send_command(ccb_t *ccb, ccb_disp_t disp
PERF_BEGIN(ccb, !waitok);
- if (!waitok) {
- s = splbio();
- if (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
- /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
- !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
- ccb->disp = disp;
- TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
+ s = splbio();
+ while (/*CONSTCOND*/ISCSI_THROTTLING_ENABLED &&
+ /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
+ !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
+
+ ccb->disp = disp;
+ if (waitok)
+ ccb->flags |= CCBF_WAITING;
+ throttle_ccb(ccb, TRUE);
+
+ PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
+ sess->CmdSN, sess->MaxCmdSN));
+ if (!waitok) {
splx(s);
- PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
- sess->CmdSN, sess->MaxCmdSN));
- return;
- }
- splx(s);
- ppdu = get_pdu_c(conn, FALSE);
- if (ppdu == NULL) {
- ccb->status = ISCSI_STATUS_NO_RESOURCES;
- iscsi_done(ccb);
return;
}
- } else {
- s = splbio();
- while (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
- /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
- !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
- ccb->disp = disp;
- ccb->flags |= CCBF_WAITING;
- TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
- PDEBOUT(("Throttling W - CmdSN = %d, MaxCmdSN = %d\n",
- sess->CmdSN, sess->MaxCmdSN));
- tsleep(ccb, PWAIT, "waitMaxCmd", 0);
- splbio();
- }
- splx(s);
- ppdu = get_pdu(conn);
+
+ tsleep(ccb, PWAIT, "waitMaxCmd", 0);
+
+ throttle_ccb(ccb, FALSE);
+ ccb->flags &= ~CCBF_WAITING;
+ }
+ splx(s);
+ ppdu = get_pdu(conn, FALSE);
+ if (ppdu == NULL) {
+ wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES);
+ return;
}
+ totlen = len = ccb->data_len;
+
pdu = &ppdu->pdu;
pdu->LUN = htonq(ccb->lun);
memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen);
- totlen = len = ccb->data_len;
pdu->Opcode = IOP_SCSI_Command;
if (immed)
pdu->Opcode |= OP_IMMEDIATE;
pdu->p.command.ExpectedDataTransferLength = htonl(totlen);
-
if (totlen) {
if (ccb->data_in) {
pdu->Flags = FLAG_READ;
@@ -1436,7 +1454,6 @@ send_command(ccb_t *ccb, ccb_disp_t disp
PERF_PDUSET(ppdu, ccb, PERF_BEGIN_PDUWRITECMD);
setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in);
-
send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT);
if (totlen)
@@ -1485,7 +1502,8 @@ send_run_xfer(session_t *session, struct
ccb = get_ccb(conn, waitok);
if (ccb == NULL) {
- xs->error = XS_RESOURCE_SHORTAGE;
+ xs->error = XS_BUSY;
+ xs->status = SCSI_QUEUE_FULL;
DEBC(conn, 0, ("No CCB in run_xfer\n"));
scsipi_done(xs);
return;
@@ -1500,7 +1518,7 @@ send_run_xfer(session_t *session, struct
ccb->sense_len_req = sizeof(xs->sense.scsi_sense);
ccb->sense_ptr = &xs->sense;
- ccb->lun = (uint64_t) xs->xs_periph->periph_lun << 48;
+ ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48;
ccb->cmd = (uint8_t *) xs->cmd;
ccb->cmdlen = xs->cmdlen;
DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n",
@@ -1634,9 +1652,8 @@ ccb_timeout(void *par)
ccb->total_tries > MAX_CCB_TRIES ||
ccb->disp <= CCBDISP_FREE ||
!ccb->session->ErrorRecoveryLevel) {
- ccb->status = ISCSI_STATUS_TIMEOUT;
- complete_ccb(ccb);
+ wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION);
} else {
if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
Index: src/sys/dev/iscsi/iscsi_test.c
diff -u src/sys/dev/iscsi/iscsi_test.c:1.2 src/sys/dev/iscsi/iscsi_test.c:1.3
--- src/sys/dev/iscsi/iscsi_test.c:1.2 Tue Nov 29 03:50:31 2011
+++ src/sys/dev/iscsi/iscsi_test.c Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_test.c,v 1.2 2011/11/29 03:50:31 tls Exp $ */
+/* $NetBSD: iscsi_test.c,v 1.3 2012/12/29 11:05:30 mlelstv Exp $ */
/*-
* Copyright (c) 2006,2011 The NetBSD Foundation, Inc.
@@ -294,7 +294,7 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
{
mod_desc_t *mod;
uint32_t mpoff, off;
- int i, rc = 0;
+ int i, rc = 0, s;
tp->pdu_count[kind][rxtx]++;
tp->pdu_count[ANY_PDU][rxtx]++;
@@ -363,9 +363,10 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
if (!off || (mpoff != 0 && mpoff < off)) {
/* This might happen in some cases. Just discard the modification. */
- CS_BEGIN;
+ s = splbio();
TAILQ_REMOVE(&tp->mods, mod, link);
- CS_END;
+ splx(s);
+
update_options(tp, mod);
if (mod->pars.options & ISCSITEST_OPT_WAIT_FOR_COMPLETION) {
@@ -413,8 +414,7 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
if (ccb != NULL &&
(ccb->disp == CCBDISP_WAIT || ccb->disp == CCBDISP_SCSIPI)) {
/* simulate timeout */
- ccb->status = ISCSI_STATUS_TIMEOUT;
- wake_ccb(ccb);
+ wake_ccb(ccb, ISCSI_STATUS_TIMEOUT);
}
}
@@ -436,14 +436,13 @@ test_mod(test_pars_t *tp, pdu_t *pdu, is
}
}
- CS_BEGIN;
+ s = splbio();
TAILQ_REMOVE(&tp->mods, mod, link);
-
update_options(tp, mod);
-
/* we've modified a PDU - copy current count into last count */
memcpy(tp->pdu_last, tp->pdu_count, sizeof(tp->pdu_last));
- CS_END;
+ splx(s);
+
if (mod->pars.options & ISCSITEST_OPT_WAIT_FOR_COMPLETION) {
wakeup(mod);
}
@@ -941,6 +940,7 @@ void
test_cancel(iscsi_test_cancel_parameters_t *par)
{
test_pars_t *tp;
+ int s;
if ((tp = find_test_id(par->test_id)) == NULL) {
par->status = ISCSI_STATUS_INVALID_ID;
@@ -948,11 +948,12 @@ test_cancel(iscsi_test_cancel_parameters
}
DEB(1, ("Test Cancel, id %d\n", par->test_id));
- CS_BEGIN;
+ s = splbio();
if (tp->connection)
tp->connection->test_pars = NULL;
TAILQ_REMOVE(&test_list, tp, link);
- CS_END;
+ splx(s);
+
free_negs(tp);
free_mods(tp, ISCSI_STATUS_TEST_CANCELED);
free(tp, M_TEMP);
@@ -980,6 +981,7 @@ test_send_pdu(struct proc *p, iscsi_test
void *pdu_ptr = par->pdu_ptr;
struct uio *uio;
uint32_t i, pad, dsl, size;
+ int s;
if ((tp = find_test_id(par->test_id)) == NULL) {
par->status = ISCSI_STATUS_INVALID_ID;
@@ -994,7 +996,7 @@ test_send_pdu(struct proc *p, iscsi_test
par->status = ISCSI_STATUS_TEST_INACTIVE;
return;
}
- if ((pdu = get_pdu(conn)) == NULL) {
+ if ((pdu = get_pdu(conn, TRUE)) == NULL) {
par->status = ISCSI_STATUS_TEST_CONNECTION_CLOSED;
return;
}
@@ -1068,8 +1070,8 @@ test_send_pdu(struct proc *p, iscsi_test
pdu->disp = PDUDISP_SIGNAL;
pdu->flags = PDUF_BUSY | PDUF_NOUPDATE;
- CS_BEGIN;
- /* Enqueue for sending */
+ s = splbio();
+ /* Enqueue for sending */
if (pdu->pdu.Opcode & OP_IMMEDIATE)
TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
else
@@ -1077,7 +1079,8 @@ test_send_pdu(struct proc *p, iscsi_test
wakeup(&conn->pdus_to_send);
tsleep(pdu, PINOD, "test_send_pdu", 0);
- CS_END;
+ splx(s);
+
unmap_databuf(p, pdu_ptr, psize);
par->status = ISCSI_STATUS_SUCCESS;
if (par->options & ISCSITEST_KILL_CONNECTION)
Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.4 src/sys/dev/iscsi/iscsi_utils.c:1.5
--- src/sys/dev/iscsi/iscsi_utils.c:1.4 Mon Jun 25 20:34:26 2012
+++ src/sys/dev/iscsi/iscsi_utils.c Sat Dec 29 11:05:30 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_utils.c,v 1.4 2012/06/25 20:34:26 mlelstv Exp $ */
+/* $NetBSD: iscsi_utils.c,v 1.5 2012/12/29 11:05:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -219,14 +219,15 @@ get_ccb(connection_t *conn, bool waitok)
{
ccb_t *ccb;
session_t *sess = conn->session;
+ int s;
do {
- CS_BEGIN;
+ s = splbio();
ccb = TAILQ_FIRST(&sess->ccb_pool);
- if (ccb != NULL) {
+ if (ccb != NULL)
TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
- }
- CS_END;
+ splx(s);
+
DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
if (ccb == NULL) {
if (!waitok || conn->terminating) {
@@ -262,6 +263,10 @@ free_ccb(ccb_t *ccb)
{
session_t *sess = ccb->session;
pdu_t *pdu;
+ int s;
+
+ KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+ KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
ccb->connection->usecount--;
ccb->connection = NULL;
@@ -281,9 +286,10 @@ free_ccb(ccb_t *ccb)
free_pdu(pdu);
}
- CS_BEGIN;
+ s = splbio();
TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
- CS_END;
+ splx(s);
+
wakeup(&sess->ccb_pool);
}
@@ -319,6 +325,50 @@ create_ccbs(session_t *sess)
}
}
+/*
+ * suspend_ccb:
+ * Put CCB on wait queue
+ */
+void
+suspend_ccb(ccb_t *ccb, bool yes)
+{
+ connection_t *conn;
+
+ conn = ccb->connection;
+ if (yes) {
+ KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+ KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+ TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
+ ccb->flags |= CCBF_WAITQUEUE;
+ } else if (ccb->flags & CCBF_WAITQUEUE) {
+ KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+ TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
+ ccb->flags &= ~CCBF_WAITQUEUE;
+ }
+}
+
+/*
+ * throttle_ccb:
+ * Put CCB on throttling queue
+ */
+void
+throttle_ccb(ccb_t *ccb, bool yes)
+{
+ session_t *sess;
+
+ sess = ccb->session;
+ if (yes) {
+ KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
+ KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+ TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
+ ccb->flags |= CCBF_THROTTLING;
+ } else if (ccb->flags & CCBF_THROTTLING) {
+ KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
+ TAILQ_REMOVE(&sess->ccbs_throttled, ccb, chain);
+ ccb->flags &= ~CCBF_THROTTLING;
+ }
+}
+
/*
* wake_ccb:
@@ -326,33 +376,21 @@ create_ccbs(session_t *sess)
* either wake up the requesting thread, signal SCSIPI that we're done,
* or just free the CCB for CCBDISP_FREE.
*
- * Parameter: The CCB to handle.
+ * Parameter: The CCB to handle and the new status of the CCB
*/
void
-wake_ccb(ccb_t *ccb)
+wake_ccb(ccb_t *ccb, uint32_t status)
{
ccb_disp_t disp;
connection_t *conn;
int s;
-#ifdef ISCSI_DEBUG
- static ccb_t *lastccb = NULL;
- static int lastdisp = -1;
-#endif
-
- /* Just in case */
- if (ccb == NULL)
- return;
conn = ccb->connection;
#ifdef ISCSI_DEBUG
- if (ccb != lastccb || ccb->disp != lastdisp) {
- DEBC(conn, 9, ("Wake CCB, ccb = %p, disp = %d\n",
- ccb, (ccb) ? ccb->disp : 0));
- lastccb = ccb;
- lastdisp = (ccb) ? ccb->disp : 0;
- }
+ DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n",
+ ccb, ccb->disp));
#endif
callout_stop(&ccb->timeout);
@@ -365,86 +403,46 @@ wake_ccb(ccb_t *ccb)
return;
}
- TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
+ suspend_ccb(ccb, FALSE);
+ throttle_ccb(ccb, FALSE);
/* change the disposition so nobody tries this again */
ccb->disp = CCBDISP_BUSY;
+ ccb->status = status;
splx(s);
PERF_END(ccb);
switch (disp) {
- case CCBDISP_WAIT:
- wakeup(ccb);
- break;
-
- case CCBDISP_SCSIPI:
- iscsi_done(ccb);
- break;
-
- case CCBDISP_DEFER:
- break;
-
- default:
+ case CCBDISP_FREE:
free_ccb(ccb);
break;
- }
-}
-
-
-/*
- * complete_ccb:
- * Same as wake_ccb, but the CCB is not assumed to be in the waiting list.
- *
- * Parameter: The CCB to handle.
- */
-
-void
-complete_ccb(ccb_t *ccb)
-{
- ccb_disp_t disp;
- int s;
-
- /* Just in case */
- if (ccb == NULL)
- return;
-
- callout_stop(&ccb->timeout);
- s = splbio();
- disp = ccb->disp;
- if (disp <= CCBDISP_NOWAIT || disp == CCBDISP_DEFER) {
- splx(s);
- return;
- }
- /* change the disposition so nobody tries this again */
- ccb->disp = CCBDISP_BUSY;
- splx(s);
-
- PERF_END(ccb);
-
- switch (disp) {
case CCBDISP_WAIT:
wakeup(ccb);
break;
case CCBDISP_SCSIPI:
iscsi_done(ccb);
+ free_ccb(ccb);
+ break;
+
+ case CCBDISP_DEFER:
break;
default:
+ DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
free_ccb(ccb);
break;
}
}
-
/*****************************************************************************
* PDU management functions
*****************************************************************************/
/*
- * get_pdu_c:
+ * get_pdu:
* Get a PDU for the SCSI operation.
*
* Parameter:
@@ -455,17 +453,18 @@ complete_ccb(ccb_t *ccb)
*/
pdu_t *
-get_pdu_c(connection_t *conn, bool waitok)
+get_pdu(connection_t *conn, bool waitok)
{
pdu_t *pdu;
+ int s;
do {
- CS_BEGIN;
+ s = splbio();
pdu = TAILQ_FIRST(&conn->pdu_pool);
- if (pdu != NULL) {
+ if (pdu != NULL)
TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
- }
- CS_END;
+ splx(s);
+
DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
if (pdu == NULL) {
if (!waitok || conn->terminating)
@@ -483,46 +482,6 @@ get_pdu_c(connection_t *conn, bool waito
}
/*
- * get_pdu:
- * Get a PDU for the SCSI operation, waits if none is available.
- * Same as get_pdu_c, but with wait always OK.
- * Duplicated code because this is the more common case.
- *
- * Parameter: The connection this PDU should be associated with.
- *
- * Returns: The PDU.
- */
-
-pdu_t *
-get_pdu(connection_t *conn)
-{
- pdu_t *pdu;
-
- do {
- CS_BEGIN;
- pdu = TAILQ_FIRST(&conn->pdu_pool);
- if (pdu != NULL) {
- TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
- }
- CS_END;
- DEB(100, ("get_pdu: pdu = %p\n", pdu));
- if (pdu == NULL) {
- if (conn->terminating)
- return NULL;
-
- PDEBOUT(("Waiting for PDU!\n"));
- tsleep(&conn->pdu_pool, PWAIT, "get_pdu", 0);
- }
- } while (pdu == NULL);
-
- memset(pdu, 0, sizeof(pdu_t));
- pdu->connection = conn;
- pdu->disp = PDUDISP_FREE;
-
- return pdu;
-}
-
-/*
* free_pdu:
* Put a PDU back onto the free list.
*
@@ -534,6 +493,7 @@ free_pdu(pdu_t *pdu)
{
connection_t *conn = pdu->connection;
pdu_disp_t pdisp;
+ int s;
if (PDUDISP_UNUSED == (pdisp = pdu->disp))
return;
@@ -551,9 +511,10 @@ free_pdu(pdu_t *pdu)
if (pdu->temp_data)
free(pdu->temp_data, M_TEMP);
- CS_BEGIN;
+ s = splbio();
TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
- CS_END;
+ splx(s);
+
wakeup(&conn->pdu_pool);
}