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); }