Module Name: src
Committed By: mlelstv
Date: Wed Jun 15 04:30:30 UTC 2016
Modified Files:
src/sys/dev/iscsi: iscsi.h iscsi_globals.h iscsi_ioctl.c iscsi_main.c
iscsi_rcv.c iscsi_send.c iscsi_utils.c
Log Message:
Remove throttling code, instead signal scsipi layer to reduce the openings
and retry the command. Start with a small openings number and let scsipi
request to grow it up to the current send window.
Adjust ccb and pdu counts to avoid ressource shortages. These are still
very ad-hoc numbers, but seem to be sufficient for a Gigabit link.
Use separate condvar for PDU pool and add counter to help debugging.
Revert setting PDU disposition to UNUSED before freeing. free_pdu
uses this as a flag to detect already returned PDUs.
Add reference counter for open commands to defer unmapping a session
that would lead to crashes in scsipi.
Move session cleanup to cleanup thread.
Use get_sernum to retrieve current serial number where possible and
make it check for immediate commands itself.
Adjust debug output.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/iscsi/iscsi.h
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/iscsi/iscsi_globals.h \
src/sys/dev/iscsi/iscsi_rcv.c src/sys/dev/iscsi/iscsi_utils.c
cvs rdiff -u -r1.21 -r1.22 src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/iscsi/iscsi_main.c
cvs rdiff -u -r1.30 -r1.31 src/sys/dev/iscsi/iscsi_send.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.h
diff -u src/sys/dev/iscsi/iscsi.h:1.3 src/sys/dev/iscsi/iscsi.h:1.4
--- src/sys/dev/iscsi/iscsi.h:1.3 Sat Nov 19 16:41:56 2011
+++ src/sys/dev/iscsi/iscsi.h Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi.h,v 1.3 2011/11/19 16:41:56 agc Exp $ */
+/* $NetBSD: iscsi.h,v 1.4 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2006,2011 The NetBSD Foundation, Inc.
@@ -182,6 +182,7 @@ typedef struct {
#define ISCSI_STATUS_LOGOUT_CID_NOT_FOUND 45 /* Logout error: CID not found */
#define ISCSI_STATUS_LOGOUT_RECOVERY_NS 46 /* Logout error: Recovery not supported */
#define ISCSI_STATUS_LOGOUT_ERROR 47 /* Logout error: Unknown reason */
+#define ISCSI_STATUS_QUEUE_FULL 48 /* iSCSI send window exhausted */
#define ISCSID_STATUS_SUCCESS 0 /* Indicates success. */
#define ISCSID_STATUS_LIST_EMPTY 1001 /* The requested list is empty. */
Index: src/sys/dev/iscsi/iscsi_globals.h
diff -u src/sys/dev/iscsi/iscsi_globals.h:1.20 src/sys/dev/iscsi/iscsi_globals.h:1.21
--- src/sys/dev/iscsi/iscsi_globals.h:1.20 Wed Jun 15 03:51:55 2016
+++ src/sys/dev/iscsi/iscsi_globals.h Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_globals.h,v 1.20 2016/06/15 03:51:55 mlelstv Exp $ */
+/* $NetBSD: iscsi_globals.h,v 1.21 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -71,33 +71,25 @@
#define VERSION_STRING "NetBSD iSCSI Software Initiator 20110407"
/*
-Various checks are made that the expected cmd Serial Number is less than
-the actual command serial number. The extremely paranoid amongst us
-believe that a malicious iSCSI server could set this artificially low
-and effectively DoS a naive initiator. For this (possibly ludicrous)
-reason, I have added the two definitions below (agc, 2011/04/09). The
-throttling definition enables a check that the CmdSN is less than the
-ExpCmdSN in iscsi_send.c, and is enabled by default. The second definition
-effectively says "don't bother testing these values", and is used right
-now only in iscsi_send.c.
- */
-#define ISCSI_THROTTLING_ENABLED 1
-#define ISCSI_SERVER_TRUSTED 0
-
-/*
NOTE: CCBS_PER_SESSION must not exceed 256 due to the way the ITT
is constructed (it has the CCB index in its lower 8 bits). If it should ever
be necessary to increase the number beyond that (which isn't expected),
the corresponding ITT generation and extraction code must be rewritten.
*/
-#define CCBS_PER_SESSION 64 /* ToDo: Reasonable number?? */
+#define CCBS_PER_SESSION 32 /* ToDo: Reasonable number?? */
+/*
+ NOTE: CCBS_FOR_SCSPI limits the number of outstanding commands for
+ SCSI commands, leaving some CCBs for keepalive and logout attempts,
+ which are needed for each connection.
+*/
+#define CCBS_FOR_SCSIPI 16 /* ToDo: Reasonable number?? */
/*
NOTE: PDUS_PER_CONNECTION is a number that could potentially impact
performance if set too low, as a single command may use up a lot of PDUs for
high values of First/MaxBurstLength and small values of
MaxRecvDataSegmentLength of the target.
*/
-#define PDUS_PER_CONNECTION 128 /* ToDo: Reasonable number?? */
+#define PDUS_PER_CONNECTION 64 /* ToDo: Reasonable number?? */
/* max outstanding serial nums before we give up on the connection */
#define SERNUM_BUFFER_LENGTH (CCBS_PER_SESSION / 2) /* ToDo: Reasonable?? */
@@ -106,7 +98,7 @@ now only in iscsi_send.c.
#define DEFAULT_MaxRecvDataSegmentLength (64*1024)
/* Command timeout (reset on received PDU associated with the command's CCB) */
-#define COMMAND_TIMEOUT (7 * hz) /* ToDo: Reasonable? (7 seconds) */
+#define COMMAND_TIMEOUT (60 * hz) /* ToDo: Reasonable? (60 seconds) */
#define MAX_CCB_TIMEOUTS 3 /* Max number of tries to resend or SNACK */
#define MAX_CCB_TRIES 9 /* Max number of total tries to recover */
@@ -131,12 +123,10 @@ now only in iscsi_send.c.
#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 ------------------------------- */
@@ -322,6 +312,7 @@ struct connection_s {
kmutex_t lock;
kcondvar_t conn_cv;
+ kcondvar_t pdu_cv;
kcondvar_t ccb_cv;
kcondvar_t idle_cv;
@@ -375,6 +366,7 @@ struct connection_s {
int recover; /* recovery count */
/* (reset on first successful data transfer) */
volatile unsigned usecount; /* number of active CCBs */
+ volatile unsigned pducount; /* number of active PDUs */
bool destroy; /* conn will be destroyed */
bool in_session;
@@ -417,6 +409,8 @@ struct session_s {
device_t child_dev;
/* the child we're associated with - (NULL if not mapped) */
+ int refcount; /* session in use by scsipi */
+
/* local stuff */
TAILQ_ENTRY(session_s) sessions; /* the list of sessions */
@@ -425,8 +419,8 @@ struct session_s {
kcondvar_t ccb_cv;
ccb_list_t ccb_pool; /* The free CCB pool */
- ccb_list_t ccbs_throttled;
- /* CCBs waiting for MaxCmdSN to increase */
+
+ int send_window;
uint16_t id; /* session ID (unique within driver) */
uint16_t TSIH; /* Target assigned session ID */
@@ -638,7 +632,7 @@ sn_a_le_b(uint32_t a, uint32_t b)
/* in iscsi_ioctl.c */
void iscsi_init_cleanup(void);
-void iscsi_destroy_cleanup(void);
+int iscsi_destroy_cleanup(void);
void iscsi_notify_cleanup(void);
@@ -652,7 +646,7 @@ void add_event(iscsi_event_t, uint32_t,
void kill_connection(connection_t *, uint32_t, int, bool);
void kill_session(session_t *, uint32_t, int, bool);
-void kill_all_sessions(void);
+int kill_all_sessions(void);
void handle_connection_error(connection_t *, uint32_t, int);
void add_connection_cleanup(connection_t *);
@@ -664,7 +658,8 @@ int iscsiioctl(struct file *, u_long, vo
session_t *find_session(uint32_t);
connection_t *find_connection(session_t *, uint32_t);
-
+int ref_session(session_t *);
+void unref_session(session_t *);
/* in iscsi_main.c */
@@ -725,7 +720,6 @@ void create_ccbs(session_t *);
ccb_t *get_ccb(connection_t *, bool);
void free_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 *);
@@ -736,8 +730,9 @@ void init_sernum(sernum_buffer_t *);
int add_sernum(sernum_buffer_t *, uint32_t);
uint32_t ack_sernum(sernum_buffer_t *, uint32_t);
-uint32_t get_sernum(session_t *, bool);
+uint32_t get_sernum(session_t *, pdu_t *);
int sernum_in_window(session_t *);
+int window_size(session_t *, int);
/* in iscsi_text.c */
Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.20 src/sys/dev/iscsi/iscsi_rcv.c:1.21
--- src/sys/dev/iscsi/iscsi_rcv.c:1.20 Sun Jun 5 14:00:12 2016
+++ src/sys/dev/iscsi/iscsi_rcv.c Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_rcv.c,v 1.20 2016/06/05 14:00:12 mlelstv Exp $ */
+/* $NetBSD: iscsi_rcv.c,v 1.21 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -645,7 +645,8 @@ receive_data_in_pdu(connection_t *conn,
done = sn_empty(&req_ccb->DataSN_buf);
if (pdu->pdu.Flags & FLAG_STATUS) {
- DEBC(conn, 10, ("Rx Data In Complete, done = %d\n", done));
+ DEBC(conn, 10, ("Rx Data In %d, done = %d\n",
+ req_ccb->CmdSN, done));
req_ccb->flags |= CCBF_COMPLETE;
/* successful transfer, reset recover count */
@@ -760,8 +761,10 @@ receive_command_response_pdu(connection_
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]));
+ DEBC(conn, 10, ("Rx Response: CmdSN %d, rsp = %x, status = %x\n",
+ req_ccb->CmdSN,
+ pdu->pdu.OpcodeSpecific[0],
+ pdu->pdu.OpcodeSpecific[1]));
rc = check_StatSN(conn, pdu->pdu.p.response.StatSN, done);
@@ -968,7 +971,7 @@ STATIC int
receive_nop_in_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb)
{
DEBC(conn, 10,
- ("Received NOP_In PDU, req_ccb=%p, ITT=%x, TTT=%x, StatSN=%x\n",
+ ("Received NOP_In PDU, req_ccb=%p, ITT=%x, TTT=%x, StatSN=%u\n",
req_ccb, pdu->pdu.InitiatorTaskTag,
pdu->pdu.p.nop_in.TargetTransferTag,
ntohl(pdu->pdu.p.nop_in.StatSN)));
@@ -1019,7 +1022,6 @@ STATIC int
receive_pdu(connection_t *conn, pdu_t *pdu)
{
ccb_t *req_ccb;
- ccb_list_t waiting;
int rc;
uint32_t MaxCmdSN, ExpCmdSN, digest;
session_t *sess = conn->session;
@@ -1036,9 +1038,11 @@ receive_pdu(connection_t *conn, pdu_t *p
}
}
- DEBC(conn, 99, ("Received PDU ExpCmdSN = %u, MaxCmdSN = %u\n",
+ DEBC(conn, 10, ("Received PDU StatSN=%u, ExpCmdSN=%u MaxCmdSN=%u ExpDataSN=%u\n",
+ ntohl(pdu->pdu.p.response.StatSN),
ntohl(pdu->pdu.p.response.ExpCmdSN),
- ntohl(pdu->pdu.p.response.ExpCmdSN)));
+ ntohl(pdu->pdu.p.response.MaxCmdSN),
+ ntohl(pdu->pdu.p.response.ExpDataSN)));
req_ccb = ccb_from_itt(conn, pdu->pdu.InitiatorTaskTag);
@@ -1131,65 +1135,14 @@ receive_pdu(connection_t *conn, pdu_t *p
connection_timeout_start(conn, CONNECTION_TIMEOUT);
conn->num_timeouts = 0;
- /*
- * Un-throttle - wakeup all CCBs waiting for MaxCmdSN to increase.
- * We have to handle wait/nowait CCBs a bit differently.
- */
+ /* Update session window */
mutex_enter(&sess->lock);
-
- if (sn_a_lt_b(MaxCmdSN, ExpCmdSN-1)) {
- /* both are ignored */
- mutex_exit(&sess->lock);
- return 0;
+ if (sn_a_le_b(ExpCmdSN - 1, MaxCmdSN)) {
+ if (sn_a_lt_b(sess->ExpCmdSN, ExpCmdSN))
+ sess->ExpCmdSN = ExpCmdSN;
+ if (sn_a_lt_b(sess->MaxCmdSN, MaxCmdSN))
+ sess->MaxCmdSN = MaxCmdSN;
}
-
- if (sn_a_lt_b(sess->ExpCmdSN, ExpCmdSN))
- sess->ExpCmdSN = ExpCmdSN;
-
- if (sn_a_lt_b(sess->MaxCmdSN, MaxCmdSN)) {
- sess->MaxCmdSN = MaxCmdSN;
-
- if (TAILQ_FIRST(&sess->ccbs_throttled) == NULL) {
- mutex_exit(&sess->lock);
- return 0;
- }
-
- DEBC(conn, 5, ("Unthrottling - MaxCmdSN = %d\n", MaxCmdSN));
-
- TAILQ_INIT(&waiting);
- while ((req_ccb = TAILQ_FIRST(&sess->ccbs_throttled)) != NULL) {
- if (!conn->terminating ||
- (req_ccb->flags & CCBF_WAITING) != 0) {
- throttle_ccb(req_ccb, FALSE);
- TAILQ_INSERT_TAIL(&waiting, req_ccb, chain);
- }
- }
-
- while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
- if (!sernum_in_window(sess))
- break;
- mutex_exit(&sess->lock);
-
- TAILQ_REMOVE(&waiting, req_ccb, chain);
-
- DEBC(conn, 10, ("Unthrottling - ccb = %p, disp = %d\n",
- req_ccb, req_ccb->disp));
-
- if ((req_ccb->flags & CCBF_WAITING) != 0) {
- cv_broadcast(&conn->ccb_cv);
- } else {
- send_command(req_ccb, req_ccb->disp, FALSE, FALSE);
- }
-
- mutex_enter(&sess->lock);
- }
-
- while ((req_ccb = TAILQ_FIRST(&waiting)) != NULL) {
- TAILQ_REMOVE(&waiting, req_ccb, chain);
- throttle_ccb(req_ccb, TRUE);
- }
- }
-
mutex_exit(&sess->lock);
return 0;
@@ -1215,6 +1168,11 @@ iscsi_rcv_thread(void *par)
do {
while (!conn->terminating) {
pdu = get_pdu(conn, TRUE);
+ if (pdu == NULL) {
+ KASSERT(conn->terminating);
+ break;
+ }
+
pdu->uio.uio_iov = pdu->io_vec;
UIO_SETUP_SYSSPACE(&pdu->uio);
pdu->uio.uio_iovcnt = 1;
Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.20 src/sys/dev/iscsi/iscsi_utils.c:1.21
--- src/sys/dev/iscsi/iscsi_utils.c:1.20 Wed Jun 15 03:51:55 2016
+++ src/sys/dev/iscsi/iscsi_utils.c Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_utils.c,v 1.20 2016/06/15 03:51:55 mlelstv Exp $ */
+/* $NetBSD: iscsi_utils.c,v 1.21 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -256,7 +256,6 @@ free_ccb(ccb_t *ccb)
"free_ccb: ccb = %p, usecount = %d\n",
ccb, conn->usecount-1));
- KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
atomic_dec_uint(&conn->usecount);
@@ -334,45 +333,20 @@ suspend_ccb(ccb_t *ccb, bool yes)
connection_t *conn;
conn = ccb->connection;
+
+ KASSERT(mutex_owned(&conn->lock));
+
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;
-
- KASSERT(mutex_owned(&sess->lock));
-
- 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:
* Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
* either wake up the requesting thread, signal SCSIPI that we're done,
@@ -386,15 +360,11 @@ wake_ccb(ccb_t *ccb, uint32_t status)
{
ccb_disp_t disp;
connection_t *conn;
- session_t *sess;
conn = ccb->connection;
- sess = ccb->session;
-#ifdef ISCSI_DEBUG
- DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n",
- ccb, ccb->disp));
-#endif
+ DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n",
+ ccb->CmdSN, ccb, ccb->disp));
ccb_timeout_stop(ccb);
@@ -413,10 +383,6 @@ wake_ccb(ccb_t *ccb, uint32_t status)
ccb->status = status;
mutex_exit(&conn->lock);
- mutex_enter(&sess->lock);
- throttle_ccb(ccb, FALSE);
- mutex_exit(&sess->lock);
-
switch (disp) {
case CCBDISP_FREE:
free_ccb(ccb);
@@ -467,22 +433,24 @@ get_pdu(connection_t *conn, bool waitok)
if (pdu != NULL)
TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
- DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
-
if (pdu == NULL) {
if (!waitok || conn->terminating) {
mutex_exit(&conn->lock);
+ DEB(15, ("get_pdu: failed"));
return NULL;
}
- cv_wait(&conn->conn_cv, &conn->lock);
+ cv_wait(&conn->pdu_cv, &conn->lock);
}
} while (pdu == NULL);
+ atomic_inc_uint(&conn->pducount);
mutex_exit(&conn->lock);
memset(pdu, 0, sizeof(pdu_t));
pdu->connection = conn;
pdu->disp = PDUDISP_FREE;
+ DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount));
+
return pdu;
}
@@ -499,6 +467,8 @@ free_pdu(pdu_t *pdu)
connection_t *conn = pdu->connection;
pdu_disp_t pdisp;
+ DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount-1));
+
KASSERT((pdu->flags & PDUF_INQUEUE) == 0);
if (PDUDISP_UNUSED == (pdisp = pdu->disp))
@@ -510,10 +480,11 @@ free_pdu(pdu_t *pdu)
free(pdu->temp_data, M_TEMP);
mutex_enter(&conn->lock);
+ atomic_dec_uint(&conn->pducount);
TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
mutex_exit(&conn->lock);
- cv_broadcast(&conn->conn_cv);
+ cv_broadcast(&conn->pdu_cv);
}
/*
@@ -676,14 +647,14 @@ ack_sernum(sernum_buffer_t *buff, uint32
* and optionally increment it for the next query
*/
uint32_t
-get_sernum(session_t *sess, bool bump)
+get_sernum(session_t *sess, pdu_t *pdu)
{
uint32_t sn;
KASSERT(mutex_owned(&sess->lock));
sn = sess->CmdSN;
- if (bump)
+ if ((pdu->pdu.Opcode & OP_IMMEDIATE) == 0)
atomic_inc_32(&sess->CmdSN);
return sn;
}
@@ -701,3 +672,22 @@ sernum_in_window(session_t *sess)
return sn_a_le_b(sess->CmdSN, sess->MaxCmdSN);
}
+/*
+ * window_size:
+ * Compute send window size
+ */
+int
+window_size(session_t *sess, int limit)
+{
+ uint32_t win;
+
+ KASSERT(mutex_owned(&sess->lock));
+
+ win = 0;
+ if (sn_a_le_b(sess->CmdSN, sess->MaxCmdSN))
+ win = sess->MaxCmdSN - sess->CmdSN + 1;
+ if (win > INT_MAX || win > limit)
+ win = limit;
+
+ return win;
+}
Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.21 src/sys/dev/iscsi/iscsi_ioctl.c:1.22
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.21 Sun Jun 5 15:04:31 2016
+++ src/sys/dev/iscsi/iscsi_ioctl.c Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_ioctl.c,v 1.21 2016/06/05 15:04:31 mlelstv Exp $ */
+/* $NetBSD: iscsi_ioctl.c,v 1.22 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -430,6 +430,50 @@ find_connection(session_t *session, uint
return curr;
}
+/*
+ * ref_session:
+ * Reference a session
+ *
+ * Session cannot be release until reference count reaches zero
+ *
+ * Returns: 1 if reference counter would overflow
+ */
+
+int
+ref_session(session_t *session)
+{
+ int rc = 1;
+
+ mutex_enter(&iscsi_cleanup_mtx);
+ KASSERT(session != NULL);
+ if (session->refcount <= CCBS_PER_SESSION) {
+ session->refcount++;
+ rc = 0;
+ }
+ mutex_exit(&iscsi_cleanup_mtx);
+
+ return rc;
+}
+
+/*
+ * unref_session:
+ * Unreference a session
+ *
+ * Release session reference, trigger cleanup
+ */
+
+void
+unref_session(session_t *session)
+{
+
+ mutex_enter(&iscsi_cleanup_mtx);
+ KASSERT(session != NULL);
+ KASSERT(session->refcount > 0);
+ if (--session->refcount == 0)
+ cv_broadcast(&session->sess_cv);
+ mutex_exit(&iscsi_cleanup_mtx);
+}
+
/*
* kill_connection:
@@ -543,8 +587,7 @@ kill_connection(connection_t *conn, uint
void
kill_session(session_t *session, uint32_t status, int logout, bool recover)
{
- connection_t *curr;
- ccb_t *ccb;
+ connection_t *conn;
DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n",
session->id, status, logout, recover));
@@ -552,6 +595,7 @@ kill_session(session_t *session, uint32_
mutex_enter(&iscsi_cleanup_mtx);
if (session->terminating) {
mutex_exit(&iscsi_cleanup_mtx);
+
DEB(5, ("Session is being killed with status %d\n",session->terminating));
return;
}
@@ -560,15 +604,16 @@ kill_session(session_t *session, uint32_
* don't do anything if session isn't established yet, termination will be
* handled elsewhere
*/
- if (session->sessions.tqe_next == NULL &&
- session->sessions.tqe_prev == NULL) {
+ if (session->sessions.tqe_next == NULL && session->sessions.tqe_prev == NULL) {
mutex_exit(&iscsi_cleanup_mtx);
+
+ DEB(5, ("Session is being killed which is not yet established\n"));
return;
}
- session->terminating = status;
- mutex_exit(&iscsi_cleanup_mtx);
if (recover) {
+ mutex_exit(&iscsi_cleanup_mtx);
+
/*
* Only recover when there's just one active connection left.
* Otherwise we get in all sorts of timing problems, and it doesn't
@@ -576,41 +621,32 @@ kill_session(session_t *session, uint32_
* requested that we kill a multipathed session.
*/
if (session->active_connections == 1) {
- curr = assign_connection(session, FALSE);
- if (curr != NULL)
- kill_connection(curr, status, logout, TRUE);
+ conn = assign_connection(session, FALSE);
+ if (conn != NULL)
+ kill_connection(conn, status, logout, TRUE);
}
- /* don't allow the session to disappear when the target */
- /* requested the logout */
- session->terminating = ISCSI_STATUS_SUCCESS;
return;
}
- /* remove from session list */
- mutex_enter(&iscsi_cleanup_mtx);
+ if (session->refcount > 0) {
+ mutex_exit(&iscsi_cleanup_mtx);
+
+ DEB(5, ("Session is being killed while in use (refcnt = %d)\n",
+ session->refcount));
+ return;
+ }
+
+ /* Remove session from global list */
+ session->terminating = status;
TAILQ_REMOVE(&iscsi_sessions, session, sessions);
session->sessions.tqe_next = NULL;
session->sessions.tqe_prev = NULL;
- mutex_exit(&iscsi_cleanup_mtx);
-
- /* complete any throttled CCBs */
- mutex_enter(&session->lock);
- while ((ccb = TAILQ_FIRST(&session->ccbs_throttled)) != NULL) {
- throttle_ccb(ccb, FALSE);
- mutex_exit(&session->lock);
- wake_ccb(ccb, ISCSI_STATUS_LOGOUT);
- mutex_enter(&session->lock);
- }
- mutex_exit(&session->lock);
- /*
- * unmap first to give the system an opportunity to flush its buffers
- */
- unmap_session(session);
+ mutex_exit(&iscsi_cleanup_mtx);
/* kill all connections */
- while ((curr = TAILQ_FIRST(&session->conn_list)) != NULL) {
- kill_connection(curr, status, logout, FALSE);
+ while ((conn = TAILQ_FIRST(&session->conn_list)) != NULL) {
+ kill_connection(conn, status, logout, FALSE);
logout = NO_LOGOUT;
}
}
@@ -676,6 +712,7 @@ create_connection(iscsi_login_parameters
mutex_init(&connection->lock, MUTEX_DEFAULT, IPL_BIO);
cv_init(&connection->conn_cv, "conn");
+ cv_init(&connection->pdu_cv, "pdupool");
cv_init(&connection->ccb_cv, "ccbwait");
cv_init(&connection->idle_cv, "idle");
@@ -691,6 +728,7 @@ create_connection(iscsi_login_parameters
cv_destroy(&connection->idle_cv);
cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->pdu_cv);
cv_destroy(&connection->conn_cv);
mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
@@ -707,7 +745,7 @@ create_connection(iscsi_login_parameters
connection->login_par = par;
DEB(5, ("Creating receive thread\n"));
- if ((rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_rcv_thread,
+ if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_rcv_thread,
connection, &connection->rcvproc,
"ConnRcv")) != 0) {
DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
@@ -715,6 +753,7 @@ create_connection(iscsi_login_parameters
release_socket(connection->sock);
cv_destroy(&connection->idle_cv);
cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->pdu_cv);
cv_destroy(&connection->conn_cv);
mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
@@ -722,7 +761,7 @@ create_connection(iscsi_login_parameters
return rc;
}
DEB(5, ("Creating send thread\n"));
- if ((rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_send_thread,
+ if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_send_thread,
connection, &connection->sendproc,
"ConnSend")) != 0) {
DEBOUT(("Can't create send thread (rc %d)\n", rc));
@@ -746,6 +785,7 @@ create_connection(iscsi_login_parameters
release_socket(connection->sock);
cv_destroy(&connection->idle_cv);
cv_destroy(&connection->ccb_cv);
+ cv_destroy(&connection->pdu_cv);
cv_destroy(&connection->conn_cv);
mutex_destroy(&connection->lock);
free(connection, M_DEVBUF);
@@ -767,12 +807,21 @@ create_connection(iscsi_login_parameters
return -1;
}
+ mutex_enter(&session->lock);
+ if (session->terminating) {
+ DEBC(connection, 0, ("Session terminating\n"));
+ kill_connection(connection, rc, NO_LOGOUT, FALSE);
+ mutex_exit(&session->lock);
+ par->status = session->terminating;
+ return -1;
+ }
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;
+ mutex_exit(&session->lock);
DEBC(connection, 5, ("Connection created successfully!\n"));
return 0;
@@ -844,7 +893,13 @@ recreate_connection(iscsi_login_paramete
session->active_connections++;
TAILQ_INIT(&old_waiting);
- TAILQ_CONCAT(&old_waiting, &connection->ccbs_waiting, chain);
+
+ mutex_enter(&connection->lock);
+ while ((ccb = TAILQ_FIRST(&connection->ccbs_waiting)) != NULL) {
+ suspend_ccb(ccb, FALSE);
+ TAILQ_INSERT_TAIL(&old_waiting, ccb, chain);
+ }
+ mutex_exit(&connection->lock);
init_sernum(&connection->StatSN_buf);
cv_broadcast(&connection->idle_cv);
@@ -869,7 +924,9 @@ recreate_connection(iscsi_login_paramete
while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
TAILQ_REMOVE(&old_waiting, ccb, chain);
+ mutex_enter(&connection->lock);
suspend_ccb(ccb, TRUE);
+ mutex_exit(&connection->lock);
rc = send_task_management(connection, ccb, NULL, TASK_REASSIGN);
/* if we get an error on reassign, restart the original request */
@@ -877,17 +934,22 @@ recreate_connection(iscsi_login_paramete
mutex_enter(&session->lock);
if (sn_a_lt_b(ccb->CmdSN, session->ExpCmdSN)) {
pdu = ccb->pdu_waiting;
- sn = get_sernum(session, !(pdu->pdu.Opcode & OP_IMMEDIATE));
+ sn = get_sernum(session, pdu);
/* update CmdSN */
- DEBC(connection, 1, ("Resend Updating CmdSN - old %d, new %d\n",
- ccb->CmdSN, sn));
+ DEBC(connection, 0, ("Resend ccb %p (%d) - updating CmdSN old %u, new %u\n",
+ ccb, rc, ccb->CmdSN, sn));
ccb->CmdSN = sn;
pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
+ } else {
+ DEBC(connection, 0, ("Resend ccb %p (%d) - CmdSN %u\n",
+ ccb, rc, ccb->CmdSN));
}
mutex_exit(&session->lock);
resend_pdu(ccb);
} else {
+ DEBC(connection, 0, ("Resend ccb %p (%d) CmdSN %u - reassigned\n",
+ ccb, rc, ccb->CmdSN));
ccb_timeout_start(ccb, COMMAND_TIMEOUT);
}
}
@@ -1011,7 +1073,6 @@ login(iscsi_login_parameters_t *par, str
}
TAILQ_INIT(&session->conn_list);
TAILQ_INIT(&session->ccb_pool);
- TAILQ_INIT(&session->ccbs_throttled);
mutex_init(&session->lock, MUTEX_DEFAULT, IPL_BIO);
cv_init(&session->sess_cv, "session");
@@ -1116,8 +1177,6 @@ add_connection(iscsi_login_parameters_t
if ((par->status = check_login_pars(par)) == 0) {
create_connection(par, session, l);
}
-
- iscsi_notify_cleanup();
}
@@ -1516,10 +1575,11 @@ get_version(iscsi_get_version_parameters
* Terminate all sessions (called when the driver unloads).
*/
-void
+int
kill_all_sessions(void)
{
session_t *sess;
+ int rc = 0;
mutex_enter(&iscsi_cleanup_mtx);
while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) {
@@ -1528,7 +1588,13 @@ kill_all_sessions(void)
FALSE);
mutex_enter(&iscsi_cleanup_mtx);
}
+ if (TAILQ_FIRST(&iscsi_sessions) != NULL) {
+ DEBOUT(("Failed to kill all sessions\n"));
+ rc = EBUSY;
+ }
mutex_exit(&iscsi_cleanup_mtx);
+
+ return rc;
}
/*
@@ -1566,6 +1632,7 @@ add_connection_cleanup(connection_t *con
mutex_enter(&iscsi_cleanup_mtx);
TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections);
mutex_exit(&iscsi_cleanup_mtx);
+ iscsi_notify_cleanup();
}
/*
@@ -1658,24 +1725,19 @@ static void
iscsi_cleanup_thread(void *par)
{
int s, rc;
- connection_t *conn;
+ session_t *sess, *nxts;
+ connection_t *conn, *nxtc;
ccb_t *ccb;
- session_t *sess, *nxt;
- uint32_t status;
-#ifdef ISCSI_DEBUG
- int last_usecount;
-#endif
mutex_enter(&iscsi_cleanup_mtx);
- while ((conn = TAILQ_FIRST(&iscsi_cleanupc_list)) != NULL ||
- iscsi_num_send_threads ||
- !iscsi_detaching) {
- if (conn != NULL) {
+ while (iscsi_num_send_threads || !iscsi_detaching ||
+ !TAILQ_EMPTY(&iscsi_cleanupc_list) || !TAILQ_EMPTY(&iscsi_cleanups_list)) {
+ TAILQ_FOREACH_SAFE(conn, &iscsi_cleanupc_list, connections, nxtc) {
+
TAILQ_REMOVE(&iscsi_cleanupc_list, conn, connections);
mutex_exit(&iscsi_cleanup_mtx);
sess = conn->session;
- status = conn->terminating;
/*
* This implies that connection cleanup only runs when
@@ -1683,97 +1745,102 @@ iscsi_cleanup_thread(void *par)
*/
DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n"));
while (conn->sendproc || conn->rcvproc)
- kpause("termwait", false, hz, NULL);
+ kpause("threads", false, hz, NULL);
- last_usecount = 0;
- while (conn->usecount > 0) {
- if (conn->usecount != last_usecount) {
- DEBC(conn, 5,("Cleanup: %d CCBs busy\n", conn->usecount));
- last_usecount = conn->usecount;
- mutex_enter(&conn->lock);
- TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) {
- DEBC(conn, 5,("Cleanup: ccb=%p disp=%d timedout=%d\n", ccb,ccb->disp, ccb->timedout));
- }
- mutex_exit(&conn->lock);
- }
- kpause("finalwait", false, hz, NULL);
+ for (s=1; conn->usecount > 0 && s < 3; ++s)
+ kpause("usecount", false, hz, NULL);
+
+ if (conn->usecount > 0) {
+ DEBC(conn, 5, ("Cleanup: %d CCBs busy\n", conn->usecount));
+ /* retry later */
+ mutex_enter(&iscsi_cleanup_mtx);
+ TAILQ_INSERT_HEAD(&iscsi_cleanupc_list, conn, connections);
+ continue;
}
+ KASSERT(!conn->in_session);
+
callout_halt(&conn->timeout, NULL);
closef(conn->sock);
cv_destroy(&conn->idle_cv);
cv_destroy(&conn->ccb_cv);
+ cv_destroy(&conn->pdu_cv);
cv_destroy(&conn->conn_cv);
mutex_destroy(&conn->lock);
free(conn, M_DEVBUF);
+ mutex_enter(&iscsi_cleanup_mtx);
+
if (--sess->total_connections == 0) {
DEB(1, ("Cleanup: session %d\n", sess->id));
+ KASSERT(sess->sessions.tqe_prev == NULL);
TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, sessions);
}
+ }
- TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, sessions, nxt) {
- if (sess->total_connections != 0)
- continue;
-
- TAILQ_REMOVE(&iscsi_cleanups_list, sess, sessions);
-
- 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));
- TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, sessions);
- }
-
- 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);
- DEB(1, ("Cleanup: session ended %d\n", sess->id));
-
- cv_destroy(&sess->ccb_cv);
- cv_destroy(&sess->sess_cv);
- mutex_destroy(&sess->lock);
- free(sess, M_DEVBUF);
+ TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, sessions, nxts) {
+ if (sess->refcount > 0)
+ continue;
+ TAILQ_REMOVE(&iscsi_cleanups_list, sess, sessions);
+ sess->sessions.tqe_next = NULL;
+ sess->sessions.tqe_prev = NULL;
+ mutex_exit(&iscsi_cleanup_mtx);
+
+ DEB(1, ("Cleanup: Unmap session %d\n", sess->id));
+ if (unmap_session(sess) == 0) {
+ DEB(1, ("Cleanup: Unmap session %d failed\n", sess->id));
+ mutex_enter(&iscsi_cleanup_mtx);
+ TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, sessions);
+ continue;
}
- DEB(5, ("Cleanup: Done\n"));
+
+ 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, sess->terminating);
+ DEB(1, ("Cleanup: session ended %d\n", sess->id));
+
+ cv_destroy(&sess->ccb_cv);
+ cv_destroy(&sess->sess_cv);
+ mutex_destroy(&sess->lock);
+ free(sess, M_DEVBUF);
mutex_enter(&iscsi_cleanup_mtx);
+ }
- } else {
- /* Go to sleep, but wake up every 30 seconds to
- * check for dead event handlers */
- rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx,
- (TAILQ_FIRST(&event_handlers)) ? 30 * hz : 0);
-
- /* handle ccb timeouts */
- while ((ccb = TAILQ_FIRST(&iscsi_timeout_ccb_list)) != NULL) {
- TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, tchain);
- KASSERT(ccb->timedout == TOUT_QUEUED);
- ccb->timedout = TOUT_BUSY;
- mutex_exit(&iscsi_cleanup_mtx);
- ccb_timeout(ccb);
- mutex_enter(&iscsi_cleanup_mtx);
- if (ccb->timedout == TOUT_BUSY)
- ccb->timedout = TOUT_NONE;
- }
- /* handle connection timeouts */
- while ((conn = TAILQ_FIRST(&iscsi_timeout_conn_list)) != NULL) {
- TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, tchain);
- KASSERT(conn->timedout == TOUT_QUEUED);
- conn->timedout = TOUT_BUSY;
- mutex_exit(&iscsi_cleanup_mtx);
- connection_timeout(conn);
- mutex_enter(&iscsi_cleanup_mtx);
- if (conn->timedout == TOUT_BUSY)
- conn->timedout = TOUT_NONE;
- }
+ /* handle ccb timeouts */
+ while ((ccb = TAILQ_FIRST(&iscsi_timeout_ccb_list)) != NULL) {
+ TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, tchain);
+ KASSERT(ccb->timedout == TOUT_QUEUED);
+ ccb->timedout = TOUT_BUSY;
+ mutex_exit(&iscsi_cleanup_mtx);
+ ccb_timeout(ccb);
+ mutex_enter(&iscsi_cleanup_mtx);
+ if (ccb->timedout == TOUT_BUSY)
+ ccb->timedout = TOUT_NONE;
+ }
- /* if timed out, not woken up */
- if (rc == EWOULDBLOCK)
- check_event_handlers();
+ /* handle connection timeouts */
+ while ((conn = TAILQ_FIRST(&iscsi_timeout_conn_list)) != NULL) {
+ TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, tchain);
+ KASSERT(conn->timedout == TOUT_QUEUED);
+ conn->timedout = TOUT_BUSY;
+ mutex_exit(&iscsi_cleanup_mtx);
+ connection_timeout(conn);
+ mutex_enter(&iscsi_cleanup_mtx);
+ if (conn->timedout == TOUT_BUSY)
+ conn->timedout = TOUT_NONE;
}
+
+ /* Go to sleep, but wake up every 30 seconds to
+ * check for dead event handlers */
+ rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx,
+ (TAILQ_FIRST(&event_handlers)) ? 120 * hz : 0);
+
+ /* if timed out, not woken up */
+ if (rc == EWOULDBLOCK)
+ check_event_handlers();
}
mutex_exit(&iscsi_cleanup_mtx);
@@ -1807,7 +1874,7 @@ iscsi_init_cleanup(void)
}
}
-void
+int
iscsi_destroy_cleanup(void)
{
@@ -1822,6 +1889,8 @@ iscsi_destroy_cleanup(void)
cv_destroy(&iscsi_event_cv);
cv_destroy(&iscsi_cleanup_cv);
mutex_destroy(&iscsi_cleanup_mtx);
+
+ return 0;
}
void
Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.22 src/sys/dev/iscsi/iscsi_main.c:1.23
--- src/sys/dev/iscsi/iscsi_main.c:1.22 Sun Jun 5 05:29:01 2016
+++ src/sys/dev/iscsi/iscsi_main.c Wed Jun 15 04:30:30 2016
@@ -262,6 +262,7 @@ static int
iscsi_detach(device_t self, int flags)
{
struct iscsi_softc *sc;
+ int error;
DEB(1, ("ISCSI: detach\n"));
sc = (struct iscsi_softc *) device_private(self);
@@ -274,8 +275,13 @@ iscsi_detach(device_t self, int flags)
iscsi_detaching = true;
mutex_exit(&sc->lock);
- kill_all_sessions();
- iscsi_destroy_cleanup();
+ error = kill_all_sessions();
+ if (error)
+ return error;
+
+ error = iscsi_destroy_cleanup();
+ if (error)
+ return error;
mutex_destroy(&sc->lock);
@@ -348,6 +354,10 @@ map_session(session_t *session, device_t
struct scsipi_channel *chan = &session->sc_channel;
const quirktab_t *tgt;
+ mutex_enter(&session->lock);
+ session->send_window = max(2, window_size(session, CCBS_FOR_SCSIPI));
+ mutex_exit(&session->lock);
+
/*
* Fill in the scsipi_adapter.
*/
@@ -355,8 +365,8 @@ map_session(session_t *session, device_t
adapt->adapt_nchannels = 1;
adapt->adapt_request = iscsi_scsipi_request;
adapt->adapt_minphys = iscsi_minphys;
- adapt->adapt_openings = CCBS_PER_SESSION - 1;
- adapt->adapt_max_periph = CCBS_PER_SESSION - 1;
+ adapt->adapt_openings = session->send_window;
+ adapt->adapt_max_periph = CCBS_FOR_SCSIPI;
/*
* Fill in the scsipi_channel.
@@ -369,7 +379,7 @@ map_session(session_t *session, device_t
chan->chan_adapter = adapt;
chan->chan_bustype = &scsi_bustype;
chan->chan_channel = 0;
- chan->chan_flags = SCSIPI_CHAN_NOSETTLE;
+ chan->chan_flags = SCSIPI_CHAN_NOSETTLE | SCSIPI_CHAN_CANGROW;
chan->chan_ntargets = 1;
chan->chan_nluns = 16; /* ToDo: ??? */
chan->chan_id = session->id;
@@ -405,6 +415,29 @@ unmap_session(session_t *session)
return rv;
}
+/*
+ * grow_resources
+ * Try to grow openings up to current window size
+ */
+static void
+grow_resources(session_t *session)
+{
+ struct scsipi_adapter *adapt = &session->sc_adapter;
+ int win;
+
+ mutex_enter(&session->lock);
+ if (session->refcount < CCBS_FOR_SCSIPI &&
+ session->send_window < CCBS_FOR_SCSIPI) {
+ win = window_size(session, CCBS_FOR_SCSIPI - session->refcount);
+ if (win > session->send_window) {
+ session->send_window++;
+ adapt->adapt_openings++;
+ DEB(5, ("Grow send window to %d\n", session->send_window));
+ }
+ }
+ mutex_exit(&session->lock);
+}
+
/******************************************************************************/
/*****************************************************************************
@@ -425,20 +458,32 @@ iscsi_scsipi_request(struct scsipi_chann
session_t *session;
int flags;
struct scsipi_xfer_mode *xm;
+ int error;
session = (session_t *) adapt; /* adapter is first field in session */
+ error = ref_session(session);
+
switch (req) {
case ADAPTER_REQ_RUN_XFER:
DEB(9, ("ISCSI: scsipi_request RUN_XFER\n"));
xs = arg;
flags = xs->xs_control;
+ if (error) {
+ DEB(9, ("ISCSI: refcount too high: %d, winsize %d\n",
+ session->refcount, session->send_window));
+ xs->error = XS_BUSY;
+ xs->status = XS_BUSY;
+ scsipi_done(xs);
+ return;
+ }
+
if ((flags & XS_CTL_POLL) != 0) {
xs->error = XS_DRIVER_STUFFUP;
DEBOUT(("Run Xfer request with polling\n"));
scsipi_done(xs);
- return;
+ break;
}
/*
* NOTE: It appears that XS_CTL_DATA_UIO is not actually used anywhere.
@@ -451,28 +496,32 @@ iscsi_scsipi_request(struct scsipi_chann
xs->error = XS_DRIVER_STUFFUP;
DEBOUT(("Run Xfer with data in UIO\n"));
scsipi_done(xs);
- return;
+ break;
}
send_run_xfer(session, xs);
- DEB(15, ("scsipi_req returns\n"));
+ DEB(15, ("scsipi_req returns, refcount = %d\n", session->refcount));
return;
case ADAPTER_REQ_GROW_RESOURCES:
DEB(5, ("ISCSI: scsipi_request GROW_RESOURCES\n"));
- return;
+ grow_resources(session);
+ break;
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;
+ break;
default:
+ DEBOUT(("ISCSI: scsipi_request with invalid REQ code %d\n", req));
break;
}
- DEBOUT(("ISCSI: scsipi_request with invalid REQ code %d\n", req));
+
+ if (!error)
+ unref_session(session);
}
/* cap the transfer at 64K */
@@ -522,6 +571,8 @@ iscsi_done(ccb_t *ccb)
break;
case ISCSI_STATUS_TARGET_BUSY:
+ case ISCSI_STATUS_NO_RESOURCES:
+ DEBC(ccb->connection, 5, ("target busy, ccb %p\n", ccb));
xs->error = XS_BUSY;
xs->status = SCSI_BUSY;
break;
@@ -532,7 +583,8 @@ iscsi_done(ccb_t *ccb)
xs->status = SCSI_BUSY;
break;
- case ISCSI_STATUS_NO_RESOURCES:
+ case ISCSI_STATUS_QUEUE_FULL:
+ DEBC(ccb->connection, 5, ("queue full, ccb %p\n", ccb));
xs->error = XS_BUSY;
xs->status = SCSI_QUEUE_FULL;
break;
@@ -550,6 +602,8 @@ iscsi_done(ccb_t *ccb)
} else {
DEBOUT(("ISCSI: iscsi_done CCB %p without XS\n", ccb));
}
+
+ unref_session(ccb->session);
}
SYSCTL_SETUP(sysctl_iscsi_setup, "ISCSI subtree setup")
Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.30 src/sys/dev/iscsi/iscsi_send.c:1.31
--- src/sys/dev/iscsi/iscsi_send.c:1.30 Sun Jun 5 13:54:28 2016
+++ src/sys/dev/iscsi/iscsi_send.c Wed Jun 15 04:30:30 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: iscsi_send.c,v 1.30 2016/06/05 13:54:28 mlelstv Exp $ */
+/* $NetBSD: iscsi_send.c,v 1.31 2016/06/15 04:30:30 mlelstv Exp $ */
/*-
* Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -93,7 +93,8 @@ assign_connection(session_t *session, bo
mutex_enter(&session->lock);
do {
- if ((conn = session->mru_connection) == NULL) {
+ if (session->terminating ||
+ (conn = session->mru_connection) == NULL) {
mutex_exit(&session->lock);
return NULL;
}
@@ -232,7 +233,9 @@ reassign_tasks(connection_t *oldconn)
free_pdu(opdu);
/* put ready CCB into waiting list of new connection */
+ mutex_enter(&conn->lock);
suspend_ccb(ccb, TRUE);
+ mutex_exit(&conn->lock);
}
if (pdu == NULL) {
@@ -255,7 +258,7 @@ reassign_tasks(connection_t *oldconn)
mutex_enter(&sess->lock);
if (ccb->CmdSN < sess->ExpCmdSN) {
pdu = ccb->pdu_waiting;
- sn = get_sernum(sess, !(pdu->pdu.Opcode & OP_IMMEDIATE));
+ sn = get_sernum(sess, pdu);
/* update CmdSN */
DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n",
@@ -312,18 +315,17 @@ iscsi_send_thread(void *par)
if (conn->HeaderDigest)
pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE);
- DEBC(conn, 99, ("Transmitting PDU CmdSN = %u\n",
- ntohl(pdu->pdu.p.command.CmdSN)));
+
+ DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n",
+ ntohl(pdu->pdu.p.command.CmdSN),
+ ntohl(pdu->pdu.p.command.ExpStatSN)));
my_soo_write(conn, &pdu->uio);
mutex_enter(&conn->lock);
pdisp = pdu->disp;
- if (pdisp <= PDUDISP_FREE)
- pdu->disp = PDUDISP_UNUSED;
- else
+ if (pdisp > PDUDISP_FREE)
pdu->flags &= ~PDUF_BUSY;
mutex_exit(&conn->lock);
-
if (pdisp <= PDUDISP_FREE)
free_pdu(pdu);
@@ -459,8 +461,10 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
pdu->disp = pdisp;
- DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n",
- ccb, prev_cdisp, cdisp, pdu, pdisp));
+ DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
+ ntohl(pdu->pdu.p.command.CmdSN),
+ conn->StatSN_buf.ExpSN,
+ ccb, pdu));
mutex_enter(&conn->lock);
if (pdisp == PDUDISP_WAIT) {
@@ -486,10 +490,9 @@ send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_dis
if (cdisp != CCBDISP_NOWAIT) {
ccb_timeout_start(ccb, COMMAND_TIMEOUT);
+ mutex_enter(&conn->lock);
if (prev_cdisp <= CCBDISP_NOWAIT)
suspend_ccb(ccb, TRUE);
-
- mutex_enter(&conn->lock);
while (ccb->disp == CCBDISP_WAIT) {
DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n",
ccb, ccb->disp));
@@ -528,7 +531,10 @@ resend_pdu(ccb_t *ccb)
pdu->uio = pdu->save_uio;
memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec));
- DEBC(conn, 8, ("ReSend_pdu ccb=%p, pdu=%p\n", ccb, pdu));
+ DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n",
+ ntohl(pdu->pdu.p.command.CmdSN),
+ conn->StatSN_buf.ExpSN,
+ ccb, pdu));
mutex_enter(&conn->lock);
/* Enqueue for sending */
@@ -632,7 +638,7 @@ init_login_pdu(connection_t *conn, ccb_t
pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE;
mutex_enter(&conn->session->lock);
- ccb->CmdSN = get_sernum(conn->session, false);
+ ccb->CmdSN = get_sernum(conn->session, ppdu);
mutex_exit(&conn->session->lock);
if (next) {
@@ -746,7 +752,7 @@ init_text_pdu(connection_t *conn, ccb_t
pdu->Flags = FLAG_FINAL;
mutex_enter(&conn->session->lock);
- ccb->CmdSN = get_sernum(conn->session, false);
+ ccb->CmdSN = get_sernum(conn->session, ppdu);
mutex_exit(&conn->session->lock);
if (rx_pdu != NULL) {
@@ -952,11 +958,11 @@ send_send_targets(session_t *session, ui
int
send_nop_out(connection_t *conn, pdu_t *rx_pdu)
{
+ session_t *sess;
ccb_t *ccb;
pdu_t *ppdu;
pdu_header_t *pdu;
-
- DEBC(conn, 10, ("Send NOP_Out rx_pdu=%p\n", rx_pdu));
+ uint32_t sn;
if (rx_pdu != NULL) {
ccb = NULL;
@@ -981,18 +987,27 @@ send_nop_out(connection_t *conn, pdu_t *
pdu->Flags = FLAG_FINAL;
pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE;
+ sess = conn->session;
+
+ mutex_enter(&sess->lock);
+ sn = get_sernum(sess, ppdu);
+ mutex_exit(&sess->lock);
+
if (rx_pdu != NULL) {
pdu->p.nop_out.TargetTransferTag =
rx_pdu->pdu.p.nop_in.TargetTransferTag;
pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
- pdu->p.nop_out.CmdSN = htonl(conn->session->CmdSN);
+ pdu->p.nop_out.CmdSN = htonl(sn);
pdu->LUN = rx_pdu->pdu.LUN;
} else {
pdu->p.nop_out.TargetTransferTag = 0xffffffff;
- ccb->CmdSN = ccb->session->CmdSN;
- pdu->p.nop_out.CmdSN = htonl(ccb->CmdSN);
+ pdu->InitiatorTaskTag = 0xffffffff;
+ ccb->CmdSN = sn;
+ pdu->p.nop_out.CmdSN = htonl(sn);
}
+ DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu));
+
setup_tx_uio(ppdu, 0, NULL, FALSE);
send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE,
PDUDISP_FREE);
@@ -1364,30 +1379,22 @@ send_command(ccb_t *ccb, ccb_disp_t disp
pdu_header_t *pdu;
mutex_enter(&sess->lock);
- while (/*CONSTCOND*/ISCSI_THROTTLING_ENABLED &&
- /*CONSTCOND*/!ISCSI_SERVER_TRUSTED &&
- !sernum_in_window(sess)) {
-
+ while (!sernum_in_window(sess)) {
+ mutex_exit(&sess->lock);
ccb->disp = disp;
- if (waitok)
- ccb->flags |= CCBF_WAITING;
- throttle_ccb(ccb, TRUE);
-
- if (!waitok) {
- mutex_exit(&sess->lock);
- DEBC(conn, 10, ("Throttling send_command, ccb = %p\n",ccb));
- return;
- }
-
- DEBC(conn, 15, ("Wait send_command, ccb = %p\n",ccb));
- cv_wait(&sess->ccb_cv, &sess->lock);
- DEBC(conn, 15, ("Resuming send_command, ccb = %p\n",ccb));
-
- throttle_ccb(ccb, FALSE);
- ccb->flags &= ~CCBF_WAITING;
+ wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL);
+ return;
}
mutex_exit(&sess->lock);
+ /* Don't confuse targets during (re-)negotations */
+ if (conn->state != ST_FULL_FEATURE) {
+ DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb));
+ ccb->disp = disp;
+ wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY);
+ return;
+ }
+
ppdu = get_pdu(conn, waitok);
if (ppdu == NULL) {
DEBOUT(("No PDU for send_command, ccb = %p\n",ccb));
@@ -1432,7 +1439,7 @@ send_command(ccb_t *ccb, ccb_disp_t disp
ccb->flags |= CCBF_REASSIGN;
mutex_enter(&sess->lock);
- ccb->CmdSN = get_sernum(sess, !immed);
+ ccb->CmdSN = get_sernum(sess, ppdu);
mutex_exit(&sess->lock);
pdu->p.command.CmdSN = htonl(ccb->CmdSN);