Index: sys/dev/iscsi/iscsi_globals.h =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_globals.h,v retrieving revision 1.25 diff -p -u -r1.25 iscsi_globals.h --- sys/dev/iscsi/iscsi_globals.h 21 Apr 2019 11:45:08 -0000 1.25 +++ sys/dev/iscsi/iscsi_globals.h 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_globals.h,v 1.25 2019/04/21 11:45:08 maya Exp $ */ +/* $NetBSD: iscsi_globals.h,v 1.27 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -37,6 +37,8 @@ /* Includes we need in all files */ #include +#include +#include #include #include #include @@ -354,6 +356,8 @@ struct connection_s { struct lwp *c_threadobj; /* proc/thread pointer of socket owner */ + + krwlock_t c_sock_rw; struct file *c_sock; /* the connection's socket */ session_t *c_session; /* back pointer to the owning session */ @@ -366,7 +370,7 @@ struct connection_s { int c_recover; /* recovery count */ /* (reset on first successful data transfer) */ volatile unsigned c_usecount; /* number of active CCBs */ - volatile unsigned c_pducount; /* number of active PDUs */ + unsigned c_pducount; /* number of active PDUs */ bool c_destroy; /* conn will be destroyed */ bool c_in_session; @@ -537,8 +541,8 @@ extern bool iscsi_hex_bignums; /* Whethe #define DEBOUT(x) printf x #define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;} #define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \ - conn ? conn->c_session->s_id : -1, \ - conn ? conn->c_id : -1); printf x ;}} + conn && conn->c_session ? conn->c_session->s_id : -1, \ + conn ? conn->c_id : -1); printf x ;}} #define STATIC static @@ -646,15 +650,11 @@ void iscsi_notify_cleanup(void); 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_session(uint32_t, uint32_t, int, bool); int kill_all_sessions(void); void handle_connection_error(connection_t *, uint32_t, int); void add_connection_cleanup(connection_t *); -#ifndef ISCSI_MINIMAL -uint32_t map_databuf(struct proc *, void **, uint32_t); -void unmap_databuf(struct proc *, void *, uint32_t); -#endif int iscsiioctl(struct file *, u_long, void *); session_t *find_session(uint32_t); Index: sys/dev/iscsi/iscsi_ioctl.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_ioctl.c,v retrieving revision 1.30 diff -p -u -r1.30 iscsi_ioctl.c --- sys/dev/iscsi/iscsi_ioctl.c 7 Dec 2018 14:59:19 -0000 1.30 +++ sys/dev/iscsi/iscsi_ioctl.c 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_ioctl.c,v 1.30 2018/12/07 14:59:19 mlelstv Exp $ */ +/* $NetBSD: iscsi_ioctl.c,v 1.33 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -34,11 +34,7 @@ #include #include #include - -#ifndef ISCSI_MINIMAL -#include -#include -#endif +#include static kmutex_t iscsi_cleanup_mtx; static kcondvar_t iscsi_cleanup_cv; @@ -498,8 +494,8 @@ kill_connection(connection_t *conn, uint if (recover && !conn->c_destroy && conn->c_recover > MAX_RECOVERY_ATTEMPTS) { - DEBC(conn, 1, - ("Kill_connection: Too many recovery attempts, destroying\n")); + DEBC(conn, 1, ("Kill_connection: Too many recovery attempts, " + "destroying\n")); conn->c_destroy = TRUE; } @@ -551,6 +547,8 @@ kill_connection(connection_t *conn, uint } mutex_exit(&iscsi_cleanup_mtx); + DEBC(conn, 1, ("Send_logout for reason %d\n", logout)); + connection_timeout_start(conn, CONNECTION_TIMEOUT); if (!send_logout(conn, conn, logout, FALSE)) { @@ -595,14 +593,24 @@ done: */ void -kill_session(session_t *sess, uint32_t status, int logout, bool recover) +kill_session(uint32_t sid, uint32_t status, int logout, bool recover) { + session_t *sess; connection_t *conn; DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n", - sess->s_id, status, logout, recover)); + sid, status, logout, recover)); mutex_enter(&iscsi_cleanup_mtx); + + sess = find_session(sid); + if (sess == NULL) { + mutex_exit(&iscsi_cleanup_mtx); + + DEB(5, ("Session %u already gone\n", sid)); + return; + } + if (sess->s_terminating) { mutex_exit(&iscsi_cleanup_mtx); @@ -652,6 +660,13 @@ kill_session(session_t *sess, uint32_t s sess->s_sessions.tqe_next = NULL; sess->s_sessions.tqe_prev = NULL; + /* + * If all connections are already gone, trigger cleanup + * otherwise, the last connection will do this + */ + if (sess->s_active_connections == 0) + iscsi_notify_cleanup(); + mutex_exit(&iscsi_cleanup_mtx); /* kill all connections */ @@ -665,6 +680,7 @@ kill_session(session_t *sess, uint32_t s /* * create_connection: * Create and init the necessary framework for a connection: + * Take over userland socket * Alloc the connection structure itself * Copy connection parameters * Create the send and receive threads @@ -693,6 +709,9 @@ create_connection(iscsi_login_parameters sess->s_active_connections >= sess->s_MaxConnections) { DEBOUT(("Too many connections (max = %d, curr = %d)\n", sess->s_MaxConnections, sess->s_active_connections)); + /* Always close descriptor */ + fd_close(par->socket); + par->status = ISCSI_STATUS_MAXED_CONNECTIONS; return EIO; } @@ -700,10 +719,35 @@ create_connection(iscsi_login_parameters conn = malloc(sizeof(*conn), M_DEVBUF, M_WAITOK | M_ZERO); if (conn == NULL) { DEBOUT(("No mem for connection\n")); + + /* Always close descriptor */ + fd_close(par->socket); + par->status = ISCSI_STATUS_NO_RESOURCES; return EIO; } + rc = get_socket(par->socket, &conn->c_sock); + fd_close(par->socket); + + if (rc) { + DEBOUT(("Invalid socket %d\n", par->socket)); + + callout_destroy(&conn->c_timeout); + rw_destroy(&conn->c_sock_rw); + cv_destroy(&conn->c_idle_cv); + cv_destroy(&conn->c_ccb_cv); + cv_destroy(&conn->c_pdu_cv); + cv_destroy(&conn->c_conn_cv); + mutex_destroy(&conn->c_lock); + free(conn, M_DEVBUF); + par->status = ISCSI_STATUS_INVALID_SOCKET; + return rc; + } + + DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", + par->socket, conn->c_sock)); + mutex_enter(&iscsi_cleanup_mtx); /* create a unique ID */ do { @@ -725,6 +769,7 @@ create_connection(iscsi_login_parameters cv_init(&conn->c_pdu_cv, "pdupool"); cv_init(&conn->c_ccb_cv, "ccbwait"); cv_init(&conn->c_idle_cv, "idle"); + rw_init(&conn->c_sock_rw); callout_init(&conn->c_timeout, CALLOUT_MPSAFE); callout_setfunc(&conn->c_timeout, connection_timeout_co, conn); @@ -733,25 +778,6 @@ create_connection(iscsi_login_parameters init_sernum(&conn->c_StatSN_buf); create_pdus(conn); - if ((rc = get_socket(par->socket, &conn->c_sock)) != 0) { - DEBOUT(("Invalid socket %d\n", par->socket)); - - callout_destroy(&conn->c_timeout); - cv_destroy(&conn->c_idle_cv); - cv_destroy(&conn->c_ccb_cv); - cv_destroy(&conn->c_pdu_cv); - cv_destroy(&conn->c_conn_cv); - mutex_destroy(&conn->c_lock); - free(conn, M_DEVBUF); - par->status = ISCSI_STATUS_INVALID_SOCKET; - return rc; - } - DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", - par->socket, conn->c_sock)); - - /* close the file descriptor */ - fd_close(par->socket); - conn->c_threadobj = l; conn->c_login_par = par; @@ -762,6 +788,7 @@ create_connection(iscsi_login_parameters DEBOUT(("Can't create rcv thread (rc %d)\n", rc)); release_socket(conn->c_sock); + rw_destroy(&conn->c_sock_rw); callout_destroy(&conn->c_timeout); cv_destroy(&conn->c_idle_cv); cv_destroy(&conn->c_ccb_cv); @@ -795,6 +822,7 @@ create_connection(iscsi_login_parameters release_socket(conn->c_sock); callout_destroy(&conn->c_timeout); + rw_destroy(&conn->c_sock_rw); cv_destroy(&conn->c_idle_cv); cv_destroy(&conn->c_ccb_cv); cv_destroy(&conn->c_pdu_cv); @@ -872,27 +900,32 @@ recreate_connection(iscsi_login_paramete sess->s_active_connections >= sess->s_MaxConnections) { DEBOUT(("Too many connections (max = %d, curr = %d)\n", sess->s_MaxConnections, sess->s_active_connections)); + + /* Always close the desecriptor */ + fd_close(par->socket); + par->status = ISCSI_STATUS_MAXED_CONNECTIONS; return EIO; } - /* close old socket */ + rw_enter(&conn->c_sock_rw, RW_WRITER); if (conn->c_sock != NULL) { closef(conn->c_sock); conn->c_sock = NULL; } + rc = get_socket(par->socket, &conn->c_sock); + rw_exit(&conn->c_sock_rw); + fd_close(par->socket); - if ((rc = get_socket(par->socket, &conn->c_sock)) != 0) { + if (rc) { DEBOUT(("Invalid socket %d\n", par->socket)); par->status = ISCSI_STATUS_INVALID_SOCKET; return rc; } + DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", par->socket, conn->c_sock)); - /* close the file descriptor */ - fd_close(par->socket); - conn->c_threadobj = l; conn->c_login_par = par; conn->c_terminating = ISCSI_STATUS_SUCCESS; @@ -916,7 +949,7 @@ recreate_connection(iscsi_login_paramete mutex_exit(&conn->c_lock); if ((rc = send_login(conn)) != 0) { - DEBOUT(("Login failed (rc %d)\n", rc)); + DEBC(conn, 0, ("Re-Login failed (rc %d)\n", rc)); while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); wake_ccb(ccb, rc); @@ -1125,7 +1158,7 @@ login(iscsi_login_parameters_t *par, str DEB(1, ("Login: map session %d\n", sess->s_id)); if (!map_session(sess, dev)) { DEB(1, ("Login: map session %d failed\n", sess->s_id)); - kill_session(sess, ISCSI_STATUS_MAP_FAILED, + kill_session(par->session_id, ISCSI_STATUS_MAP_FAILED, LOGOUT_SESSION, FALSE); par->status = ISCSI_STATUS_MAP_FAILED; return; @@ -1160,7 +1193,9 @@ logout(iscsi_logout_parameters_t *par) /* If the session exists, this always succeeds */ par->status = ISCSI_STATUS_SUCCESS; - kill_session(session, ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, FALSE); + kill_session(par->session_id, + ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, + FALSE); } @@ -1173,7 +1208,7 @@ logout(iscsi_logout_parameters_t *par) * l IN: The lwp pointer of the caller */ -static void +static int add_connection(iscsi_login_parameters_t *par, struct lwp *l) { session_t *session; @@ -1185,12 +1220,15 @@ add_connection(iscsi_login_parameters_t mutex_exit(&iscsi_cleanup_mtx); DEBOUT(("Session %d not found\n", par->session_id)); par->status = ISCSI_STATUS_INVALID_SESSION_ID; - return; + return -1; } mutex_exit(&iscsi_cleanup_mtx); - if ((par->status = check_login_pars(par)) == 0) { - create_connection(par, session, l); - } + + par->status = check_login_pars(par); + if (par->status) + return -1; + + return create_connection(par, session, l); } @@ -1259,7 +1297,6 @@ restore_connection(iscsi_login_parameter par->status = ISCSI_STATUS_INVALID_SESSION_ID; return; } - if ((conn = find_connection(sess, par->connection_id)) == NULL) { mutex_exit(&iscsi_cleanup_mtx); DEBOUT(("Connection %d not found in session %d\n", @@ -1267,6 +1304,12 @@ restore_connection(iscsi_login_parameter par->status = ISCSI_STATUS_INVALID_CONNECTION_ID; return; } + if (!conn->c_terminating) { + mutex_exit(&iscsi_cleanup_mtx); + DEBC(conn, 0, ("Connection is alive\n")); + par->status = ISCSI_STATUS_SUCCESS; + return; + } mutex_exit(&iscsi_cleanup_mtx); if ((par->status = check_login_pars(par)) == 0) { @@ -1278,92 +1321,6 @@ restore_connection(iscsi_login_parameter #ifndef ISCSI_MINIMAL /* - * map_databuf: - * Map user-supplied data buffer into kernel space. - * - * Parameter: - * p IN: The proc pointer of the caller - * buf IN/OUT: The virtual address of the buffer, modified - * on exit to reflect kernel VA. - * datalen IN: The size of the data buffer - * - * Returns: - * An ISCSI status code on error, else 0. - */ - -uint32_t -map_databuf(struct proc *p, void **buf, uint32_t datalen) -{ - vaddr_t kva, databuf, offs; - int error; - - /* page align address */ - databuf = (vaddr_t) * buf & ~PAGE_MASK; - /* offset of VA into page */ - offs = (vaddr_t) * buf & PAGE_MASK; - /* round to full page including offset */ - datalen = (datalen + offs + PAGE_MASK) & ~PAGE_MASK; - - /* Do some magic to the vm space reference count (copied from "copyin_proc") */ - if ((p->p_sflag & PS_WEXIT) || (p->p_vmspace->vm_refcnt < 1)) { - return ISCSI_STATUS_NO_RESOURCES; - } - p->p_vmspace->vm_refcnt++; - - /* this is lifted from uvm_io */ - error = uvm_map_extract(&p->p_vmspace->vm_map, databuf, datalen, - kernel_map, &kva, - UVM_EXTRACT_QREF | UVM_EXTRACT_CONTIG | - UVM_EXTRACT_FIXPROT); - if (error) { - DEBOUT(("uvm_map_extract failed, error = %d\n", error)); - return ISCSI_STATUS_NO_RESOURCES; - } - /* add offset back into kernel VA */ - *buf = (void *) (kva + offs); - - return 0; -} - - -/* - * unmap_databuf: - * Remove kernel space mapping of data buffer. - * - * Parameter: - * p IN: The proc pointer of the caller - * buf IN: The kernel virtual address of the buffer - * datalen IN: The size of the data buffer - * - * Returns: - * An ISCSI status code on error, else 0. - */ - -void -unmap_databuf(struct proc *p, void *buf, uint32_t datalen) -{ - struct vm_map_entry *dead_entries; - vaddr_t databuf; - - /* round to full page */ - datalen = (datalen + ((uintptr_t) buf & PAGE_MASK) + PAGE_MASK) & ~PAGE_MASK; - /* page align address */ - databuf = (vaddr_t) buf & ~PAGE_MASK; - - /* following code lifted almost verbatim from uvm_io.c */ - vm_map_lock(kernel_map); - uvm_unmap_remove(kernel_map, databuf, databuf + datalen, &dead_entries, - 0); - vm_map_unlock(kernel_map); - if (dead_entries != NULL) { - uvm_unmap_detach(dead_entries, AMAP_REFALL); - } - /* this apparently reverses the magic to the vm ref count, from copyin_proc */ - uvmspace_free(p->p_vmspace); -} - - -/* * io_command: * Handle the io_command ioctl. * @@ -1376,8 +1333,9 @@ static void io_command(iscsi_iocommand_parameters_t *par, struct lwp *l) { uint32_t datalen = par->req.datalen; - void *databuf = par->req.databuf; session_t *session; + void *kbuf = NULL; + int error; DEB(9, ("ISCSI: io_command, SID=%d, lun=%" PRIu64 "\n", par->session_id, par->lun)); mutex_enter(&iscsi_cleanup_mtx); @@ -1400,18 +1358,31 @@ io_command(iscsi_iocommand_parameters_t return; } - if (datalen && (par->status = map_databuf(l->l_proc, - &par->req.databuf, datalen)) != 0) { - return; + if (datalen) { + /* Arbitrarily limit datalen to 8k. */ + if (datalen > 8192) { + par->status = ISCSI_STATUS_PARAMETER_INVALID; + return; + } + kbuf = kmem_zalloc(datalen, KM_SLEEP); + if ((par->req.flags & SCCMD_WRITE) != 0) { + error = copyin(par->req.databuf, kbuf, datalen); + if (error) { + kmem_free(kbuf, datalen); + par->status = ISCSI_STATUS_PARAMETER_INVALID; + return; + } + } } par->status = send_io_command(session, par->lun, &par->req, par->options.immediate, par->connection_id); - if (datalen) { - unmap_databuf(l->l_proc, par->req.databuf, datalen); - par->req.databuf = databuf; /* restore original addr */ + if (kbuf) { + if ((par->req.flags & SCCMD_READ) != 0) { + (void) copyout(kbuf, par->req.databuf, datalen); + } + kmem_free(kbuf, datalen); } - switch (par->status) { case ISCSI_STATUS_SUCCESS: par->req.retsts = SCCMD_OK; @@ -1594,11 +1565,13 @@ kill_all_sessions(void) { session_t *sess; int rc = 0; + uint32_t sid; mutex_enter(&iscsi_cleanup_mtx); while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) { + sid = sess->s_id; mutex_exit(&iscsi_cleanup_mtx); - kill_session(sess, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION, + kill_session(sid, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION, FALSE); mutex_enter(&iscsi_cleanup_mtx); } @@ -1624,7 +1597,6 @@ kill_all_sessions(void) void handle_connection_error(connection_t *conn, uint32_t status, int dologout) { - DEBC(conn, 0, ("*** Connection Error, status=%d, logout=%d, state=%d\n", status, dologout, conn->c_state)); @@ -1643,7 +1615,7 @@ handle_connection_error(connection_t *co void add_connection_cleanup(connection_t *conn) { - session_t *sess; + session_t *sess = NULL; mutex_enter(&iscsi_cleanup_mtx); if (conn->c_in_session) { @@ -1698,7 +1670,7 @@ connection_timeout_stop(connection_t *co kpause("connbusy", false, 1, &iscsi_cleanup_mtx); } mutex_exit(&iscsi_cleanup_mtx); -} +} void ccb_timeout_co(void *par) @@ -1786,6 +1758,7 @@ iscsi_cleanup_thread(void *par) callout_halt(&conn->c_timeout, NULL); closef(conn->c_sock); callout_destroy(&conn->c_timeout); + rw_destroy(&conn->c_sock_rw); cv_destroy(&conn->c_idle_cv); cv_destroy(&conn->c_ccb_cv); cv_destroy(&conn->c_pdu_cv); Index: sys/dev/iscsi/iscsi_main.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_main.c,v retrieving revision 1.30 diff -p -u -r1.30 iscsi_main.c --- sys/dev/iscsi/iscsi_main.c 13 Jul 2019 17:06:00 -0000 1.30 +++ sys/dev/iscsi/iscsi_main.c 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_main.c,v 1.30 2019/07/13 17:06:00 mlelstv Exp $ */ +/* $NetBSD: iscsi_main.c,v 1.41 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -87,8 +87,15 @@ static int iscsiclose(struct file *); static const struct fileops iscsi_fileops = { .fo_name = "iscsi", + .fo_read = fbadop_read, + .fo_write = fbadop_write, .fo_ioctl = iscsiioctl, + .fo_fcntl = fnullop_fcntl, + .fo_poll = fnullop_poll, + .fo_stat = fbadop_stat, .fo_close = iscsiclose, + .fo_kqfilter = fnullop_kqfilter, + .fo_restart = fnullop_restart }; struct cdevsw iscsi_cdevsw = { @@ -166,15 +173,12 @@ iscsiclose(struct file *fp) struct iscsi_softc *sc; sc = device_lookup_private(&iscsi_cd, d->fd_unit); - if (sc == NULL) { - DEBOUT(("%s: Cannot find private data\n",__func__)); - return ENXIO; + if (sc != NULL) { + mutex_enter(&sc->lock); + TAILQ_REMOVE(&sc->fds, d, fd_link); + mutex_exit(&sc->lock); } - mutex_enter(&sc->lock); - TAILQ_REMOVE(&sc->fds, d, fd_link); - mutex_exit(&sc->lock); - kmem_free(d, sizeof(*d)); fp->f_iscsi = NULL; @@ -217,12 +221,7 @@ iscsiattach(int n) aprint_error("%s: only one device supported\n", iscsi_cd.cd_name); - cf = kmem_alloc(sizeof(struct cfdata), KM_NOSLEEP); - if (cf == NULL) { - aprint_error("%s: couldn't allocate cfdata\n", - iscsi_cd.cd_name); - return; - } + cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP); cf->cf_name = iscsi_cd.cd_name; cf->cf_atname = iscsi_cd.cd_name; cf->cf_unit = 0; @@ -255,7 +254,7 @@ iscsi_attach(device_t parent, device_t s if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); - aprint_normal("%s: attached. major = %d\n", iscsi_cd.cd_name, + aprint_verbose("%s: attached. major = %d\n", iscsi_cd.cd_name, cdevsw_lookup_major(&iscsi_cdevsw)); } @@ -360,6 +359,7 @@ map_session(session_t *sess, device_t de struct scsipi_adapter *adapt = &sess->s_sc_adapter; struct scsipi_channel *chan = &sess->s_sc_channel; const quirktab_t *tgt; + int found; mutex_enter(&sess->s_lock); sess->s_send_window = max(2, window_size(sess, CCBS_FOR_SCSIPI)); @@ -392,9 +392,12 @@ map_session(session_t *sess, device_t de chan->chan_nluns = 16; chan->chan_id = sess->s_id; + KERNEL_LOCK(1, NULL); sess->s_child_dev = config_found(dev, chan, scsiprint); + found = (sess->s_child_dev != NULL); + KERNEL_UNLOCK_ONE(NULL); - return sess->s_child_dev != NULL; + return found; } @@ -415,9 +418,10 @@ unmap_session(session_t *sess) int rv = 1; if ((dev = sess->s_child_dev) != NULL) { - sess->s_child_dev = NULL; if (config_detach(dev, 0)) rv = 0; + if (rv) + sess->s_child_dev = NULL; } return rv; @@ -427,11 +431,12 @@ unmap_session(session_t *sess) * grow_resources * Try to grow openings up to current window size */ -static void +static int grow_resources(session_t *sess) { struct scsipi_adapter *adapt = &sess->s_sc_adapter; int win; + int rc = -1; mutex_enter(&sess->s_lock); if (sess->s_refcount < CCBS_FOR_SCSIPI && @@ -440,10 +445,13 @@ grow_resources(session_t *sess) if (win > sess->s_send_window) { sess->s_send_window++; adapt->adapt_openings++; + rc = 0; DEB(5, ("Grow send window to %d\n", sess->s_send_window)); } } mutex_exit(&sess->s_lock); + + return rc; } /******************************************************************************/ @@ -513,7 +521,10 @@ iscsi_scsipi_request(struct scsipi_chann case ADAPTER_REQ_GROW_RESOURCES: DEB(5, ("ISCSI: scsipi_request GROW_RESOURCES\n")); - grow_resources(sess); + if (grow_resources(sess)) { + /* reached maximum */ + chan->chan_flags &= ~SCSIPI_CHAN_CANGROW; + } break; case ADAPTER_REQ_SET_XFER_MODE: @@ -677,20 +688,28 @@ iscsi_modcmd(modcmd_t cmd, void *arg) #ifdef _MODULE devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; int error; - static struct sysctllog *clog; #endif switch (cmd) { case MODULE_CMD_INIT: #ifdef _MODULE + error = devsw_attach(iscsi_cd.cd_name, NULL, &bmajor, + &iscsi_cdevsw, &cmajor); + if (error) { + aprint_error("%s: unable to register devsw\n", + iscsi_cd.cd_name); + return error; + } error = config_cfdriver_attach(&iscsi_cd); if (error) { + devsw_detach(NULL, &iscsi_cdevsw); return error; } error = config_cfattach_attach(iscsi_cd.cd_name, &iscsi_ca); if (error) { config_cfdriver_detach(&iscsi_cd); + devsw_detach(NULL, &iscsi_cdevsw); aprint_error("%s: unable to register cfattach\n", iscsi_cd.cd_name); return error; @@ -702,29 +721,20 @@ iscsi_modcmd(modcmd_t cmd, void *arg) iscsi_cd.cd_name); config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); config_cfdriver_detach(&iscsi_cd); - return error; - } - - error = devsw_attach(iscsi_cd.cd_name, NULL, &bmajor, - &iscsi_cdevsw, &cmajor); - if (error) { - aprint_error("%s: unable to register devsw\n", - iscsi_cd.cd_name); - config_cfdata_detach(iscsi_cfdata); - config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); - config_cfdriver_detach(&iscsi_cd); + devsw_detach(NULL, &iscsi_cdevsw); return error; } if (config_attach_pseudo(iscsi_cfdata) == NULL) { aprint_error("%s: config_attach_pseudo failed\n", iscsi_cd.cd_name); + + config_cfdata_detach(iscsi_cfdata); config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); config_cfdriver_detach(&iscsi_cd); + devsw_detach(NULL, &iscsi_cdevsw); return ENXIO; } - - sysctl_iscsi_setup(&clog); #endif return 0; break; @@ -735,8 +745,7 @@ iscsi_modcmd(modcmd_t cmd, void *arg) if (error) return error; - sysctl_teardown(&clog); - + config_cfdata_detach(iscsi_cfdata); config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); config_cfdriver_detach(&iscsi_cd); devsw_detach(NULL, &iscsi_cdevsw); Index: sys/dev/iscsi/iscsi_rcv.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_rcv.c,v retrieving revision 1.25 diff -p -u -r1.25 iscsi_rcv.c --- sys/dev/iscsi/iscsi_rcv.c 4 Mar 2018 07:37:43 -0000 1.25 +++ sys/dev/iscsi/iscsi_rcv.c 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_rcv.c,v 1.25 2018/03/04 07:37:43 mlelstv Exp $ */ +/* $NetBSD: iscsi_rcv.c,v 1.26 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -51,7 +51,7 @@ STATIC int my_soo_read(connection_t *conn, struct uio *u, int flags) { - struct socket *so = conn->c_sock->f_socket; + struct socket *so; int ret; #ifdef ISCSI_DEBUG size_t resid = u->uio_resid; @@ -59,22 +59,34 @@ my_soo_read(connection_t *conn, struct u DEBC(conn, 99, ("soo_read req: %zu\n", resid)); - if (flags & MSG_WAITALL) { - flags &= ~MSG_WAITALL; - do { - int oresid = u->uio_resid; - ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags); - if (!ret && u->uio_resid == oresid) - break; - } while (!ret && u->uio_resid > 0); - } else - ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags); + rw_enter(&conn->c_sock_rw, RW_READER); + if (conn->c_sock == NULL) { + ret = EIO; + } else { + so = conn->c_sock->f_socket; + if (flags & MSG_WAITALL) { + flags &= ~MSG_WAITALL; + do { + int oresid = u->uio_resid; + ret = (*so->so_receive)(so, NULL, u, + NULL, NULL, &flags); + if (!ret && u->uio_resid == oresid) + break; + } while (!ret && u->uio_resid > 0); + } else { + ret = (*so->so_receive)(so, NULL, u, + NULL, NULL, &flags); + } + } + + rw_exit(&conn->c_sock_rw); if (ret || (flags != MSG_DONTWAIT && u->uio_resid)) { DEBC(conn, 1, ("Read failed (ret: %d, req: %zu, out: %zu)\n", ret, resid, u->uio_resid)); - handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, - RECOVER_CONNECTION); + if (ret) + handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, + RECOVER_CONNECTION); return 1; } return 0; @@ -810,34 +822,41 @@ receive_asynch_pdu(connection_t *conn, p case 0: /* SCSI Asynch event. Don't know what to do with it... */ break; - case 1: /* Target requests logout. */ + case 1: /* Target requests logout. */ if (conn->c_session->s_active_connections > 1) { kill_connection(conn, ISCSI_STATUS_TARGET_LOGOUT, LOGOUT_CONNECTION, FALSE); } else { - kill_session(conn->c_session, ISCSI_STATUS_TARGET_LOGOUT, - LOGOUT_SESSION, FALSE); + kill_session(conn->c_session->s_id, + ISCSI_STATUS_TARGET_LOGOUT, LOGOUT_SESSION, + FALSE); } break; - case 2: /* Target is dropping connection */ + case 2: /* Target is dropping connection */ conn = find_connection(conn->c_session, - ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter1)); + ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter1)); if (conn != NULL) { - conn->c_Time2Wait = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2); - conn->c_Time2Retain = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3); + conn->c_Time2Wait = + ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2); + conn->c_Time2Retain = + ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3); kill_connection(conn, ISCSI_STATUS_TARGET_DROP, NO_LOGOUT, TRUE); } break; - case 3: /* Target is dropping all connections of session */ - conn->c_session->s_DefaultTime2Wait = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2); - conn->c_session->s_DefaultTime2Retain = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3); - kill_session(conn->c_session, ISCSI_STATUS_TARGET_DROP, NO_LOGOUT, TRUE); + case 3: /* Target is dropping all connections of session */ + conn->c_session->s_DefaultTime2Wait = + ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2); + conn->c_session->s_DefaultTime2Retain = + ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3); + kill_session(conn->c_session->s_id, + ISCSI_STATUS_TARGET_DROP, NO_LOGOUT, + TRUE); break; - case 4: /* Target requests parameter negotiation */ + case 4: /* Target requests parameter negotiation */ start_text_negotiation(conn); break; @@ -1144,12 +1163,12 @@ receive_pdu(connection_t *conn, pdu_t *p MaxCmdSN = ntohl(pdu->pdu_hdr.pduh_p.nop_in.MaxCmdSN); /* received a valid frame, reset timeout */ + conn->c_num_timeouts = 0; if ((pdu->pdu_hdr.pduh_Opcode & OPCODE_MASK) == TOP_NOP_In && TAILQ_EMPTY(&conn->c_ccbs_waiting)) connection_timeout_start(conn, conn->c_idle_timeout_val); else connection_timeout_start(conn, CONNECTION_TIMEOUT); - conn->c_num_timeouts = 0; /* Update session window */ mutex_enter(&sess->s_lock); Index: sys/dev/iscsi/iscsi_send.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_send.c,v retrieving revision 1.37 diff -p -u -r1.37 iscsi_send.c --- sys/dev/iscsi/iscsi_send.c 4 Mar 2018 07:39:45 -0000 1.37 +++ sys/dev/iscsi/iscsi_send.c 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_send.c,v 1.37 2018/03/04 07:39:45 mlelstv Exp $ */ +/* $NetBSD: iscsi_send.c,v 1.39 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -54,7 +54,7 @@ STATIC int my_soo_write(connection_t *conn, struct uio *u) { - struct socket *so = conn->c_sock->f_socket; + struct socket *so; int ret; #ifdef ISCSI_DEBUG size_t resid = u->uio_resid; @@ -62,7 +62,15 @@ my_soo_write(connection_t *conn, struct KASSERT(u->uio_resid != 0); - ret = (*so->so_send)(so, NULL, u, NULL, NULL, 0, conn->c_threadobj); + rw_enter(&conn->c_sock_rw, RW_READER); + if (conn->c_sock == NULL) { + ret = EIO; + } else { + so = conn->c_sock->f_socket; + ret = (*so->so_send)(so, NULL, u, + NULL, NULL, 0, conn->c_threadobj); + } + rw_exit(&conn->c_sock_rw); DEB(99, ("soo_write done: len = %zu\n", u->uio_resid)); @@ -140,6 +148,7 @@ reassign_tasks(connection_t *oldconn) session_t *sess = oldconn->c_session; connection_t *conn; ccb_t *ccb; + ccb_list_t old_waiting; pdu_t *pdu = NULL; pdu_t *opdu; int no_tm = 1; @@ -154,6 +163,10 @@ reassign_tasks(connection_t *oldconn) return; } + TAILQ_INIT(&old_waiting); + + mutex_enter(&oldconn->c_lock); + if (sess->s_ErrorRecoveryLevel >= 2) { if (oldconn->c_loggedout == NOT_LOGGED_OUT) { oldconn->c_loggedout = LOGOUT_SENT; @@ -169,24 +182,34 @@ reassign_tasks(connection_t *oldconn) if (!no_tm && oldconn->c_Time2Wait) { DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n", oldconn->c_Time2Wait, hz)); - kpause("Time2Wait", false, oldconn->c_Time2Wait * hz, NULL); + kpause("Time2Wait", false, oldconn->c_Time2Wait * hz, &oldconn->c_lock); } } - DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n", - sess->s_id, oldconn->c_id, conn->c_id, no_tm)); + while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) { + suspend_ccb(ccb, FALSE); + TAILQ_INSERT_TAIL(&old_waiting, ccb, ccb_chain); + } + mutex_exit(&oldconn->c_lock); + + DEBC(conn, 1, ("Reassign_tasks: S%dC%d -> S%dC%d, no_tm=%d, pdus old %d + new %d\n", + sess->s_id, oldconn->c_id, sess->s_id, conn->c_id, no_tm, + oldconn->c_pducount, conn->c_pducount)); /* XXX reassign waiting CCBs to new connection */ - while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) { + while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { /* Copy PDU contents (PDUs are bound to connection) */ if ((pdu = get_pdu(conn, TRUE)) == NULL) { + DEBC(conn, 0, ("get_pdu failed, terminating=%d\n", conn->c_terminating)); + /* new connection is terminating */ break; } + TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); + /* adjust CCB and clone PDU for new connection */ - TAILQ_REMOVE(&oldconn->c_ccbs_waiting, ccb, ccb_chain); opdu = ccb->ccb_pdu_waiting; KASSERT((opdu->pdu_flags & PDUF_INQUEUE) == 0); @@ -224,7 +247,7 @@ reassign_tasks(connection_t *oldconn) atomic_inc_uint(&conn->c_usecount); DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n", - ccb, opdu, pdu)); + ccb, opdu, pdu)); /* kill temp pointer that is now referenced by the new PDU */ opdu->pdu_temp_data = NULL; @@ -238,14 +261,24 @@ reassign_tasks(connection_t *oldconn) mutex_exit(&conn->c_lock); } - if (pdu == NULL) { - DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n")); - /* give up recovering, the other connection is screwed up as well... */ - while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) { + if (TAILQ_FIRST(&old_waiting) != NULL) { + DEBC(conn, 0, ("Error while copying PDUs in reassign_tasks!\n")); + /* + * give up recovering, the other connection is screwed up + * as well... + */ + + while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { + TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); + + DEBC(oldconn, 1, ("Wake CCB %p for connection %d, terminating %d\n", + ccb, ccb->ccb_connection->c_id, oldconn->c_terminating)); + mutex_enter(&oldconn->c_lock); + suspend_ccb(ccb, TRUE); + mutex_exit(&oldconn->c_lock); wake_ccb(ccb, oldconn->c_terminating); } - /* XXX some CCBs might have been moved to new connection, but how is the - * new connection handled or killed ? */ + return; } @@ -262,7 +295,7 @@ reassign_tasks(connection_t *oldconn) /* update CmdSN */ DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n", - ccb->ccb_CmdSN, sn)); + ccb->ccb_CmdSN, sn)); ccb->ccb_CmdSN = sn; pdu->pdu_hdr.pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); } @@ -548,9 +581,10 @@ resend_pdu(ccb_t *ccb) } else { TAILQ_INSERT_TAIL(&conn->c_pdus_to_send, pdu, pdu_send_chain); } - ccb_timeout_start(ccb, COMMAND_TIMEOUT); cv_broadcast(&conn->c_conn_cv); mutex_exit(&conn->c_lock); + + ccb_timeout_start(ccb, COMMAND_TIMEOUT); } @@ -1636,10 +1670,10 @@ send_io_command(session_t *session, uint void connection_timeout(connection_t *conn) { - - if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) + if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) { + DEBC(conn, 1, ("connection timeout %d\n", conn->c_num_timeouts)); handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); - else { + } else { if (conn->c_state == ST_FULL_FEATURE) send_nop_out(conn, NULL); Index: sys/dev/iscsi/iscsi_utils.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_utils.c,v retrieving revision 1.27 diff -p -u -r1.27 iscsi_utils.c --- sys/dev/iscsi/iscsi_utils.c 21 Apr 2019 11:45:08 -0000 1.27 +++ sys/dev/iscsi/iscsi_utils.c 19 Nov 2022 09:03:08 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_utils.c,v 1.27 2019/04/21 11:45:08 maya Exp $ */ +/* $NetBSD: iscsi_utils.c,v 1.28 2022/09/13 13:09:16 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc. @@ -203,22 +203,28 @@ get_ccb(connection_t *conn, bool waitok) session_t *sess = conn->c_session; mutex_enter(&sess->s_lock); - do { + for (;;) { ccb = TAILQ_FIRST(&sess->s_ccb_pool); + DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok)); if (ccb != NULL) { TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain); - } else { - if (!waitok || conn->c_terminating) { - mutex_exit(&sess->s_lock); - return NULL; - } - cv_wait(&sess->s_ccb_cv, &sess->s_lock); + break; } - } while (ccb == NULL); + + if (!waitok) + break; + + cv_wait(&sess->s_ccb_cv, &sess->s_lock); + } mutex_exit(&sess->s_lock); + if (ccb == NULL) { + DEB(15, ("get_ccb: failed")); + return NULL; + } + ccb->ccb_flags = 0; ccb->ccb_timedout = TOUT_NONE; ccb->ccb_xs = NULL; @@ -454,23 +460,27 @@ get_pdu(connection_t *conn, bool waitok) pdu_t *pdu; mutex_enter(&conn->c_lock); - do { + for (;;) { pdu = TAILQ_FIRST(&conn->c_pdu_pool); - if (pdu != NULL) - TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain); - if (pdu == NULL) { - if (!waitok || conn->c_terminating) { - mutex_exit(&conn->c_lock); - DEB(15, ("get_pdu: failed")); - return NULL; - } - cv_wait(&conn->c_pdu_cv, &conn->c_lock); + if (pdu != NULL) { + TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain); + conn->c_pducount++; + break; } - } while (pdu == NULL); - atomic_inc_uint(&conn->c_pducount); + + if (!waitok) + break; + + cv_wait(&conn->c_pdu_cv, &conn->c_lock); + } mutex_exit(&conn->c_lock); + if (pdu == NULL) { + DEB(15, ("get_pdu: failed")); + return NULL; + } + memset(pdu, 0, sizeof(pdu_t)); pdu->pdu_connection = conn; pdu->pdu_disp = PDUDISP_FREE; @@ -497,8 +507,11 @@ free_pdu(pdu_t *pdu) KASSERT((pdu->pdu_flags & PDUF_INQUEUE) == 0); - if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp)) + if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp)) { + DEBC(conn, 0, ("freeing UNUSED pdu\n")); return; + } + pdu->pdu_disp = PDUDISP_UNUSED; /* free temporary data in this PDU */ @@ -506,7 +519,7 @@ free_pdu(pdu_t *pdu) free(pdu->pdu_temp_data, M_TEMP); mutex_enter(&conn->c_lock); - atomic_dec_uint(&conn->c_pducount); + conn->c_pducount--; TAILQ_INSERT_TAIL(&conn->c_pdu_pool, pdu, pdu_chain); cv_broadcast(&conn->c_pdu_cv); mutex_exit(&conn->c_lock);