version 1.10, 2014/11/24 21:49:17 |
version 1.10.2.5, 2017/02/05 13:40:28 |
|
|
|
|
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/buf.h> |
#include <sys/buf.h> |
|
#include <sys/file.h> |
|
#include <sys/filedesc.h> |
#include <sys/kmem.h> |
#include <sys/kmem.h> |
#include <sys/socketvar.h> |
#include <sys/socketvar.h> |
|
#include <sys/sysctl.h> |
|
|
|
#include "ioconf.h" |
|
|
/*------------------------- Global Variables ------------------------*/ |
/*------------------------- Global Variables ------------------------*/ |
|
|
Line 44 extern struct cfdriver iscsi_cd; |
|
Line 48 extern struct cfdriver iscsi_cd; |
|
int iscsi_debug_level = ISCSI_DEBUG; |
int iscsi_debug_level = ISCSI_DEBUG; |
#endif |
#endif |
|
|
#if defined(ISCSI_PERFTEST) |
bool iscsi_detaching; |
int iscsi_perf_level = 0; |
|
#endif |
|
|
|
/* Device Structure */ |
|
iscsi_softc_t *sc = NULL; |
|
|
|
/* the list of sessions */ |
/* the list of sessions */ |
session_list_t iscsi_sessions = TAILQ_HEAD_INITIALIZER(iscsi_sessions); |
session_list_t iscsi_sessions = TAILQ_HEAD_INITIALIZER(iscsi_sessions); |
|
|
/* connections to clean up */ |
|
connection_list_t iscsi_cleanupc_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanupc_list); |
|
session_list_t iscsi_cleanups_list = TAILQ_HEAD_INITIALIZER(iscsi_cleanups_list); |
|
|
|
bool iscsi_detaching = FALSE; |
|
struct lwp *iscsi_cleanproc = NULL; |
|
|
|
/* the number of active send threads (for cleanup thread) */ |
/* the number of active send threads (for cleanup thread) */ |
uint32_t iscsi_num_send_threads = 0; |
uint32_t iscsi_num_send_threads = 0; |
|
|
Line 75 login_isid_t iscsi_InitiatorISID; |
|
Line 67 login_isid_t iscsi_InitiatorISID; |
|
System interface: autoconf and device structures |
System interface: autoconf and device structures |
*/ |
*/ |
|
|
void iscsiattach(int); |
|
|
|
static void iscsi_attach(device_t parent, device_t self, void *aux); |
static void iscsi_attach(device_t parent, device_t self, void *aux); |
static int iscsi_match(device_t, cfdata_t, void *); |
static int iscsi_match(device_t, cfdata_t, void *); |
static int iscsi_detach(device_t, int); |
static int iscsi_detach(device_t, int); |
|
|
|
struct iscsi_softc { |
|
device_t dev; |
|
kmutex_t lock; |
|
TAILQ_HEAD(, iscsifd) fds; |
|
}; |
|
|
CFATTACH_DECL_NEW(iscsi, sizeof(struct iscsi_softc), iscsi_match, iscsi_attach, |
CFATTACH_DECL_NEW(iscsi, sizeof(struct iscsi_softc), iscsi_match, iscsi_attach, |
iscsi_detach, NULL); |
iscsi_detach, NULL); |
|
|
|
|
static dev_type_open(iscsiopen); |
static dev_type_open(iscsiopen); |
static dev_type_close(iscsiclose); |
static int iscsiclose(struct file *); |
|
|
|
static const struct fileops iscsi_fileops = { |
|
.fo_ioctl = iscsiioctl, |
|
.fo_close = iscsiclose, |
|
}; |
|
|
struct cdevsw iscsi_cdevsw = { |
struct cdevsw iscsi_cdevsw = { |
.d_open = iscsiopen, |
.d_open = iscsiopen, |
.d_close = iscsiclose, |
.d_close = noclose, |
.d_read = noread, |
.d_read = noread, |
.d_write = nowrite, |
.d_write = nowrite, |
.d_ioctl = iscsiioctl, |
.d_ioctl = noioctl, |
.d_stop = nostop, |
.d_stop = nostop, |
.d_tty = notty, |
.d_tty = notty, |
.d_poll = nopoll, |
.d_poll = nopoll, |
Line 107 struct cdevsw iscsi_cdevsw = { |
|
Line 107 struct cdevsw iscsi_cdevsw = { |
|
/******************************************************************************/ |
/******************************************************************************/ |
|
|
STATIC void iscsi_scsipi_request(struct scsipi_channel *, |
STATIC void iscsi_scsipi_request(struct scsipi_channel *, |
scsipi_adapter_req_t, void *); |
scsipi_adapter_req_t, void *); |
STATIC void iscsi_minphys(struct buf *); |
STATIC void iscsi_minphys(struct buf *); |
|
|
/******************************************************************************/ |
/******************************************************************************/ |
Line 121 STATIC void iscsi_minphys(struct buf *); |
|
Line 121 STATIC void iscsi_minphys(struct buf *); |
|
*******************************************************************************/ |
*******************************************************************************/ |
|
|
int |
int |
iscsiopen(dev_t dev, int flag, int mode, PTHREADOBJ p) |
iscsiopen(dev_t dev, int flag, int mode, struct lwp *l) |
{ |
{ |
|
struct iscsifd *d; |
|
struct iscsi_softc *sc; |
|
struct file *fp; |
|
int error, fd, unit; |
|
|
DEB(99, ("ISCSI Open\n")); |
unit = minor(dev); |
return 0; |
|
|
DEB(99, ("ISCSI Open unit=%d\n",unit)); |
|
|
|
sc = device_lookup_private(&iscsi_cd, unit); |
|
if (sc == NULL) |
|
return ENXIO; |
|
|
|
if ((error = fd_allocfile(&fp, &fd)) != 0) |
|
return error; |
|
|
|
d = kmem_alloc(sizeof(*d), KM_SLEEP); |
|
d->dev = sc->dev; |
|
d->unit = unit; |
|
|
|
mutex_enter(&sc->lock); |
|
if (iscsi_detaching) { |
|
mutex_exit(&sc->lock); |
|
kmem_free(d, sizeof(*d)); |
|
DEB(99, ("ISCSI Open aborting\n")); |
|
fd_abort(curproc, fp, fd); |
|
return ENXIO; |
|
} |
|
TAILQ_INSERT_TAIL(&sc->fds, d, link); |
|
mutex_exit(&sc->lock); |
|
|
|
return fd_clone(fp, fd, flag, &iscsi_fileops, d); |
} |
} |
|
|
int |
static int |
iscsiclose(dev_t dev, int flag, int mode, PTHREADOBJ p) |
iscsiclose(struct file *fp) |
{ |
{ |
|
struct iscsifd *d = fp->f_iscsi; |
|
struct iscsi_softc *sc; |
|
|
|
sc = device_lookup_private(&iscsi_cd, d->unit); |
|
if (sc == NULL) { |
|
DEBOUT(("%s: Cannot find private data\n",__func__)); |
|
return ENXIO; |
|
} |
|
|
|
mutex_enter(&sc->lock); |
|
TAILQ_REMOVE(&sc->fds, d, link); |
|
mutex_exit(&sc->lock); |
|
|
|
kmem_free(d, sizeof(*d)); |
|
fp->f_iscsi = NULL; |
|
|
DEB(99, ("ISCSI Close\n")); |
DEB(99, ("ISCSI Close\n")); |
return 0; |
return 0; |
Line 193 iscsiattach(int n) |
|
Line 237 iscsiattach(int n) |
|
static void |
static void |
iscsi_attach(device_t parent, device_t self, void *aux) |
iscsi_attach(device_t parent, device_t self, void *aux) |
{ |
{ |
|
struct iscsi_softc *sc; |
|
|
DEBOUT(("ISCSI: iscsi_attach, parent=%p, self=%p, aux=%p\n", parent, |
DEB(1, ("ISCSI: iscsi_attach, parent=%p, self=%p, aux=%p\n", parent, |
self, aux)); |
self, aux)); |
sc = (iscsi_softc_t *) device_private(self); |
sc = (struct iscsi_softc *) device_private(self); |
sc->sc_dev = self; |
sc->dev = self; |
if (kthread_create(PRI_NONE, 0, NULL, iscsi_cleanup_thread, |
|
NULL, &iscsi_cleanproc, "Cleanup") != 0) { |
TAILQ_INIT(&sc->fds); |
panic("Can't create cleanup thread!"); |
mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE); |
} |
|
|
iscsi_detaching = false; |
|
iscsi_init_cleanup(); |
|
|
aprint_normal("%s: attached. major = %d\n", iscsi_cd.cd_name, |
aprint_normal("%s: attached. major = %d\n", iscsi_cd.cd_name, |
cdevsw_lookup_major(&iscsi_cdevsw)); |
cdevsw_lookup_major(&iscsi_cdevsw)); |
} |
} |
Line 213 iscsi_attach(device_t parent, device_t s |
|
Line 261 iscsi_attach(device_t parent, device_t s |
|
static int |
static int |
iscsi_detach(device_t self, int flags) |
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); |
|
|
DEBOUT(("ISCSI: detach\n")); |
mutex_enter(&sc->lock); |
kill_all_sessions(); |
if (!TAILQ_EMPTY(&sc->fds)) { |
iscsi_detaching = TRUE; |
mutex_exit(&sc->lock); |
while (iscsi_cleanproc != NULL) { |
return EBUSY; |
wakeup(&iscsi_cleanupc_list); |
|
tsleep(&iscsi_cleanupc_list, PWAIT, "detach_wait", 20 * hz); |
|
} |
} |
|
iscsi_detaching = true; |
|
mutex_exit(&sc->lock); |
|
|
|
error = kill_all_sessions(); |
|
if (error) |
|
return error; |
|
|
|
error = iscsi_destroy_cleanup(); |
|
if (error) |
|
return error; |
|
|
|
mutex_destroy(&sc->lock); |
|
|
return 0; |
return 0; |
} |
} |
|
|
Line 228 iscsi_detach(device_t self, int flags) |
|
Line 292 iscsi_detach(device_t self, int flags) |
|
|
|
typedef struct quirktab_t { |
typedef struct quirktab_t { |
const char *tgt; |
const char *tgt; |
size_t tgtlen; |
|
const char *iqn; |
const char *iqn; |
size_t iqnlen; |
|
uint32_t quirks; |
uint32_t quirks; |
} quirktab_t; |
} quirktab_t; |
|
|
static const quirktab_t quirktab[] = { |
static const quirktab_t quirktab[] = { |
{ "StarWind", 8, |
{ "StarWind", "iqn.2008-08.com.starwindsoftware", PQUIRK_ONLYBIG }, |
"iqn.2008-08.com.starwindsoftware", 32, |
{ "UNH", "iqn.2002-10.edu.unh.", |
PQUIRK_ONLYBIG }, |
PQUIRK_NOBIGMODESENSE | |
{ "UNH", 3, |
PQUIRK_NOMODESENSE | |
"iqn.2002-10.edu.unh.", 20, |
PQUIRK_NOSYNCCACHE }, |
PQUIRK_NOBIGMODESENSE | |
{ "NetBSD", "iqn.1994-04.org.netbsd.", 0 }, |
PQUIRK_NOMODESENSE | |
{ "Unknown", "unknown", 0 }, |
PQUIRK_NOSYNCCACHE }, |
{ NULL, NULL, 0 } |
{ "NetBSD", 6, |
|
"iqn.1994-04.org.netbsd.", 23, |
|
0 }, |
|
{ "Unknown", 7, |
|
"unknown", 7, |
|
0 }, |
|
{ NULL, 0, NULL, 0, 0 } |
|
}; |
}; |
|
|
/* loop through the quirktab looking for a match on target name */ |
/* loop through the quirktab looking for a match on target name */ |
Line 257 static const quirktab_t * |
|
Line 312 static const quirktab_t * |
|
getquirks(const char *iqn) |
getquirks(const char *iqn) |
{ |
{ |
const quirktab_t *qp; |
const quirktab_t *qp; |
|
size_t iqnlen, quirklen; |
|
|
if (iqn == NULL) { |
if (iqn == NULL) |
iqn = "unknown"; |
iqn = "unknown"; |
} |
iqnlen = strlen(iqn); |
for (qp = quirktab ; qp->iqn ; qp++) { |
for (qp = quirktab ; qp->iqn ; qp++) { |
if (strncmp(qp->iqn, iqn, qp->iqnlen) == 0) { |
quirklen = strlen(qp->iqn); |
|
if (quirklen > iqnlen) |
|
continue; |
|
if (memcmp(qp->iqn, iqn, quirklen) == 0) |
break; |
break; |
} |
|
} |
} |
return qp; |
return qp; |
} |
} |
Line 290 getquirks(const char *iqn) |
|
Line 348 getquirks(const char *iqn) |
|
*/ |
*/ |
|
|
int |
int |
map_session(session_t *session) |
map_session(session_t *session, device_t dev) |
{ |
{ |
struct scsipi_adapter *adapt = &session->sc_adapter; |
struct scsipi_adapter *adapt = &session->sc_adapter; |
struct scsipi_channel *chan = &session->sc_channel; |
struct scsipi_channel *chan = &session->sc_channel; |
const quirktab_t *tgt; |
const quirktab_t *tgt; |
|
|
if (sc == NULL) { |
mutex_enter(&session->lock); |
/* we haven't gone through the config process */ |
session->send_window = max(2, window_size(session, CCBS_FOR_SCSIPI)); |
/* (shouldn't happen) */ |
mutex_exit(&session->lock); |
DEBOUT(("Map: No device pointer!\n")); |
|
return 0; |
|
} |
|
/* |
/* |
* Fill in the scsipi_adapter. |
* Fill in the scsipi_adapter. |
*/ |
*/ |
adapt->adapt_dev = sc->sc_dev; |
adapt->adapt_dev = dev; |
adapt->adapt_nchannels = 1; |
adapt->adapt_nchannels = 1; |
adapt->adapt_request = iscsi_scsipi_request; |
adapt->adapt_request = iscsi_scsipi_request; |
adapt->adapt_minphys = iscsi_minphys; |
adapt->adapt_minphys = iscsi_minphys; |
adapt->adapt_openings = CCBS_PER_SESSION; |
adapt->adapt_openings = session->send_window; |
adapt->adapt_max_periph = CCBS_PER_SESSION; |
adapt->adapt_max_periph = CCBS_FOR_SCSIPI; |
|
adapt->adapt_flags = SCSIPI_ADAPT_MPSAFE; |
|
|
/* |
/* |
* Fill in the scsipi_channel. |
* Fill in the scsipi_channel. |
Line 323 map_session(session_t *session) |
|
Line 380 map_session(session_t *session) |
|
chan->chan_adapter = adapt; |
chan->chan_adapter = adapt; |
chan->chan_bustype = &scsi_bustype; |
chan->chan_bustype = &scsi_bustype; |
chan->chan_channel = 0; |
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_ntargets = 1; |
chan->chan_nluns = 16; /* ToDo: ??? */ |
chan->chan_nluns = 16; /* ToDo: ??? */ |
chan->chan_id = session->id; |
chan->chan_id = session->id; |
|
|
session->child_dev = config_found(sc->sc_dev, chan, scsiprint); |
session->child_dev = config_found(dev, chan, scsiprint); |
|
|
return session->child_dev != NULL; |
return session->child_dev != NULL; |
} |
} |
Line 359 unmap_session(session_t *session) |
|
Line 416 unmap_session(session_t *session) |
|
return rv; |
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); |
|
} |
|
|
/******************************************************************************/ |
/******************************************************************************/ |
|
|
/***************************************************************************** |
/***************************************************************************** |
Line 379 iscsi_scsipi_request(struct scsipi_chann |
|
Line 459 iscsi_scsipi_request(struct scsipi_chann |
|
session_t *session; |
session_t *session; |
int flags; |
int flags; |
struct scsipi_xfer_mode *xm; |
struct scsipi_xfer_mode *xm; |
|
int error; |
|
|
session = (session_t *) adapt; /* adapter is first field in session */ |
session = (session_t *) adapt; /* adapter is first field in session */ |
|
|
|
error = ref_session(session); |
|
|
switch (req) { |
switch (req) { |
case ADAPTER_REQ_RUN_XFER: |
case ADAPTER_REQ_RUN_XFER: |
DEB(9, ("ISCSI: scsipi_request RUN_XFER\n")); |
DEB(9, ("ISCSI: scsipi_request RUN_XFER\n")); |
xs = arg; |
xs = arg; |
flags = xs->xs_control; |
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) { |
if ((flags & XS_CTL_POLL) != 0) { |
xs->error = XS_DRIVER_STUFFUP; |
xs->error = XS_DRIVER_STUFFUP; |
DEBOUT(("Run Xfer request with polling\n")); |
DEBOUT(("Run Xfer request with polling\n")); |
scsipi_done(xs); |
scsipi_done(xs); |
return; |
break; |
} |
} |
/* |
/* |
* NOTE: It appears that XS_CTL_DATA_UIO is not actually used anywhere. |
* NOTE: It appears that XS_CTL_DATA_UIO is not actually used anywhere. |
* Since it really would complicate matters to handle offsets |
* Since it really would complicate matters to handle offsets |
* into scatter-gather lists, and a number of other drivers don't |
* into scatter-gather lists, and a number of other drivers don't |
* handle uio-based data as well, XS_CTL_DATA_UIO isn't |
* handle uio-based data as well, XS_CTL_DATA_UIO isn't |
* implemented in this driver (at least for now). |
* implemented in this driver (at least for now). |
*/ |
*/ |
if (flags & XS_CTL_DATA_UIO) { |
if (flags & XS_CTL_DATA_UIO) { |
xs->error = XS_DRIVER_STUFFUP; |
xs->error = XS_DRIVER_STUFFUP; |
DEBOUT(("Run Xfer with data in UIO\n")); |
DEBOUT(("Run Xfer with data in UIO\n")); |
scsipi_done(xs); |
scsipi_done(xs); |
return; |
break; |
} |
} |
|
|
send_run_xfer(session, xs); |
send_run_xfer(session, xs); |
DEB(9, ("scsipi_req returns\n")); |
DEB(15, ("scsipi_req returns, refcount = %d\n", session->refcount)); |
return; |
return; |
|
|
case ADAPTER_REQ_GROW_RESOURCES: |
case ADAPTER_REQ_GROW_RESOURCES: |
DEBOUT(("ISCSI: scsipi_request GROW_RESOURCES\n")); |
DEB(5, ("ISCSI: scsipi_request GROW_RESOURCES\n")); |
return; |
grow_resources(session); |
|
break; |
|
|
case ADAPTER_REQ_SET_XFER_MODE: |
case ADAPTER_REQ_SET_XFER_MODE: |
DEB(5, ("ISCSI: scsipi_request SET_XFER_MODE\n")); |
DEB(5, ("ISCSI: scsipi_request SET_XFER_MODE\n")); |
xm = (struct scsipi_xfer_mode *)arg; |
xm = (struct scsipi_xfer_mode *)arg; |
xm->xm_mode = PERIPH_CAP_TQING; |
xm->xm_mode = PERIPH_CAP_TQING; |
scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); |
scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); |
return; |
break; |
|
|
default: |
default: |
|
DEBOUT(("ISCSI: scsipi_request with invalid REQ code %d\n", req)); |
break; |
break; |
} |
} |
DEBOUT(("ISCSI: scsipi_request with invalid REQ code %d\n", req)); |
|
|
if (!error) |
|
unref_session(session); |
} |
} |
|
|
/* cap the transfer at 64K */ |
/* cap the transfer at 64K */ |
|
|
iscsi_done(ccb_t *ccb) |
iscsi_done(ccb_t *ccb) |
{ |
{ |
struct scsipi_xfer *xs = ccb->xs; |
struct scsipi_xfer *xs = ccb->xs; |
/*DEBOUT (("iscsi_done\n")); */ |
DEB(9, ("iscsi_done\n")); |
|
|
if (xs != NULL) { |
if (xs != NULL) { |
xs->resid = ccb->residual; |
xs->resid = ccb->residual; |
|
|
switch (ccb->status) { |
switch (ccb->status) { |
case ISCSI_STATUS_SUCCESS: |
case ISCSI_STATUS_SUCCESS: |
xs->error = 0; |
xs->error = XS_NOERROR; |
|
xs->status = SCSI_OK; |
break; |
break; |
|
|
case ISCSI_STATUS_CHECK_CONDITION: |
case ISCSI_STATUS_CHECK_CONDITION: |
xs->error = XS_SENSE; |
xs->error = XS_SENSE; |
#ifdef ISCSI_DEBUG |
xs->status = SCSI_CHECK; |
{ |
|
uint8_t *s = (uint8_t *) (&xs->sense); |
|
DEB(5, ("Scsipi_done, error=XS_SENSE, sense data=%02x " |
|
"%02x %02x %02x...\n", |
|
s[0], s[1], s[2], s[3])); |
|
} |
|
#endif |
|
break; |
break; |
|
|
case ISCSI_STATUS_TARGET_BUSY: |
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->error = XS_BUSY; |
|
xs->status = SCSI_BUSY; |
break; |
break; |
|
|
case ISCSI_STATUS_SOCKET_ERROR: |
case ISCSI_STATUS_SOCKET_ERROR: |
case ISCSI_STATUS_TIMEOUT: |
case ISCSI_STATUS_TIMEOUT: |
xs->error = XS_SELTIMEOUT; |
xs->error = XS_SELTIMEOUT; |
|
xs->status = SCSI_BUSY; |
|
break; |
|
|
|
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; |
break; |
|
|
default: |
default: |
Line 498 iscsi_done(ccb_t *ccb) |
|
Line 598 iscsi_done(ccb_t *ccb) |
|
DEB(99, ("Calling scsipi_done (%p), err = %d\n", xs, xs->error)); |
DEB(99, ("Calling scsipi_done (%p), err = %d\n", xs, xs->error)); |
scsipi_done(xs); |
scsipi_done(xs); |
DEB(99, ("scsipi_done returned\n")); |
DEB(99, ("scsipi_done returned\n")); |
|
} else { |
|
DEBOUT(("ISCSI: iscsi_done CCB %p without XS\n", ccb)); |
} |
} |
|
|
|
unref_session(ccb->session); |
} |
} |
|
|
|
SYSCTL_SETUP(sysctl_iscsi_setup, "ISCSI subtree setup") |
|
{ |
|
const struct sysctlnode *node = NULL; |
|
|
|
sysctl_createv(clog, 0, NULL, &node, |
|
CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "iscsi", |
|
SYSCTL_DESCR("iscsi controls"), |
|
NULL, 0, NULL, 0, |
|
CTL_HW, CTL_CREATE, CTL_EOL); |
|
|
|
#ifdef ISCSI_DEBUG |
|
sysctl_createv(clog, 0, &node, NULL, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
|
CTLTYPE_INT, "debug", |
|
SYSCTL_DESCR("debug level"), |
|
NULL, 0, &iscsi_debug_level, sizeof(iscsi_debug_level), |
|
CTL_CREATE, CTL_EOL); |
|
#endif |
|
} |
|
|
|
|
/* Kernel Module support */ |
/* Kernel Module support */ |
|
|
#include <sys/module.h> |
#include <sys/module.h> |
|
|
MODULE(MODULE_CLASS_DRIVER, iscsi, NULL); |
MODULE(MODULE_CLASS_DRIVER, iscsi, NULL); /* Possibly a builtin module */ |
|
|
#ifdef _MODULE |
#ifdef _MODULE |
static const struct cfiattrdata ibescsi_info = { "scsi", 1, |
static const struct cfiattrdata ibescsi_info = { "scsi", 1, |
Line 536 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
Line 662 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
#ifdef _MODULE |
#ifdef _MODULE |
devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; |
devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; |
int error; |
int error; |
|
static struct sysctllog *clog; |
#endif |
#endif |
|
|
switch (cmd) { |
switch (cmd) { |
Line 581 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
Line 708 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
config_cfdriver_detach(&iscsi_cd); |
config_cfdriver_detach(&iscsi_cd); |
return ENXIO; |
return ENXIO; |
} |
} |
|
|
|
sysctl_iscsi_setup(&clog); |
#endif |
#endif |
return 0; |
return 0; |
break; |
break; |
Line 591 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
Line 720 iscsi_modcmd(modcmd_t cmd, void *arg) |
|
if (error) |
if (error) |
return error; |
return error; |
|
|
|
sysctl_teardown(&clog); |
|
|
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); |
config_cfattach_detach(iscsi_cd.cd_name, &iscsi_ca); |
config_cfdriver_detach(&iscsi_cd); |
config_cfdriver_detach(&iscsi_cd); |
devsw_detach(NULL, &iscsi_cdevsw); |
devsw_detach(NULL, &iscsi_cdevsw); |