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.
This commit is contained in:
parent
ae0ee83b73
commit
bbe94f43d2
@ -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. */
|
||||
|
@ -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.
|
||||
@ -70,34 +70,26 @@
|
||||
#define VERSION_MINOR 1
|
||||
#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, uint32_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, void *);
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -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, uint32_t id)
|
||||
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, uint32_t status, int logout, bool recover)
|
||||
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_t status, int logout, bool recover)
|
||||
mutex_enter(&iscsi_cleanup_mtx);
|
||||
if (session->terminating) {
|
||||
mutex_exit(&iscsi_cleanup_mtx);
|
||||
|
||||
DEB(5, ("Session is being killed with status %d\n",session->terminating));
|
||||
return;
|
||||
}
|
||||
@ -560,15 +604,16 @@ kill_session(session_t *session, uint32_t status, int logout, bool recover)
|
||||
* 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_t status, int logout, bool recover)
|
||||
* 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);
|
||||
|
||||
/* 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_t *par, session_t *session,
|
||||
|
||||
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_t *par, session_t *session,
|
||||
|
||||
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_t *par, session_t *session,
|
||||
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_t *par, session_t *session,
|
||||
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_t *par, session_t *session,
|
||||
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_t *par, session_t *session,
|
||||
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_t *par, session_t *session,
|
||||
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_parameters_t *par, session_t *session,
|
||||
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_parameters_t *par, session_t *session,
|
||||
|
||||
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_parameters_t *par, session_t *session,
|
||||
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, struct lwp *l, device_t dev)
|
||||
}
|
||||
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 *par, struct lwp *l)
|
||||
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_t *par)
|
||||
* 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 *conn)
|
||||
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);
|
||||
|
||||
if (--sess->total_connections == 0) {
|
||||
DEB(1, ("Cleanup: session %d\n", sess->id));
|
||||
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);
|
||||
}
|
||||
DEB(5, ("Cleanup: Done\n"));
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* if timed out, not woken up */
|
||||
if (rc == EWOULDBLOCK)
|
||||
check_event_handlers();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -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 dev)
|
||||
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 dev)
|
||||
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 dev)
|
||||
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_channel *chan, scsipi_adapter_req_t req,
|
||||
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_channel *chan, scsipi_adapter_req_t req,
|
||||
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")
|
||||
|
@ -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, pdu_t *pdu, ccb_t *req_ccb)
|
||||
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_t *conn, pdu_t *pdu, ccb_t *req_ccb)
|
||||
|
||||
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 *pdu)
|
||||
}
|
||||
}
|
||||
|
||||
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 *pdu)
|
||||
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;
|
||||
|
@ -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, bool waitok)
|
||||
|
||||
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_disp_t cdisp, pdu_disp_t pdisp)
|
||||
|
||||
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_disp_t cdisp, pdu_disp_t pdisp)
|
||||
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 *ccb, pdu_t *ppdu, bool next)
|
||||
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 *ccb, pdu_t *ppdu, pdu_t *rx_pdu)
|
||||
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, uint8_t *key)
|
||||
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 *rx_pdu)
|
||||
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, bool waitok, bool immed)
|
||||
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, bool waitok, bool immed)
|
||||
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);
|
||||
|
@ -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,44 +333,19 @@ 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,
|
||||
@ -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_t num)
|
||||
* 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user