summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/ctl/ctl.c39
-rw-r--r--sys/cam/ctl/ctl.h2
-rw-r--r--sys/cam/ctl/ctl_frontend.c4
-rw-r--r--sys/cam/ctl/ctl_frontend.h5
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c307
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.h8
-rw-r--r--sys/cam/ctl/ctl_ioctl.h42
-rw-r--r--usr.sbin/ctld/ctld.c17
-rw-r--r--usr.sbin/ctld/ctld.h4
-rw-r--r--usr.sbin/ctld/kernel.c319
10 files changed, 593 insertions, 154 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index cb41bf5..ebf547d 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -3146,11 +3146,41 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
retval = fe->ioctl(dev, cmd, addr, flag, td);
break;
}
+ case CTL_PORT_REQ: {
+ struct ctl_req *req;
+ struct ctl_frontend *fe;
+
+ req = (struct ctl_req *)addr;
+
+ fe = ctl_frontend_find(req->driver);
+ if (fe == NULL) {
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "Frontend \"%s\" not found.", req->driver);
+ break;
+ }
+ if (req->num_args > 0) {
+ req->kern_args = ctl_copyin_args(req->num_args,
+ req->args, req->error_str, sizeof(req->error_str));
+ if (req->kern_args == NULL) {
+ req->status = CTL_LUN_ERROR;
+ break;
+ }
+ }
+
+ retval = fe->ioctl(dev, cmd, addr, flag, td);
+
+ if (req->num_args > 0) {
+ ctl_copyout_args(req->num_args, req->kern_args);
+ ctl_free_args(req->num_args, req->kern_args);
+ }
+ break;
+ }
case CTL_PORT_LIST: {
struct sbuf *sb;
struct ctl_port *port;
struct ctl_lun_list *list;
-// struct ctl_option *opt;
+ struct ctl_option *opt;
list = (struct ctl_lun_list *)addr;
@@ -3217,6 +3247,13 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
if (retval != 0)
break;
+ STAILQ_FOREACH(opt, &port->options, links) {
+ retval = sbuf_printf(sb, "\t<%s>%s</%s>\n",
+ opt->name, opt->value, opt->name);
+ if (retval != 0)
+ break;
+ }
+
retval = sbuf_printf(sb, "</targ_port>\n");
if (retval != 0)
break;
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index 71c37ca..aaf75b0 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -103,6 +103,8 @@ union ctl_modepage_info {
*/
#define CTL_WWPN_LEN 8
+#define CTL_DRIVER_NAME_LEN 32
+
/*
* Unit attention types. ASC/ASCQ values for these should be placed in
* ctl_build_ua. These are also listed in order of reporting priority.
diff --git a/sys/cam/ctl/ctl_frontend.c b/sys/cam/ctl/ctl_frontend.c
index a01ccf6..210a85f 100644
--- a/sys/cam/ctl/ctl_frontend.c
+++ b/sys/cam/ctl/ctl_frontend.c
@@ -176,6 +176,9 @@ ctl_port_register(struct ctl_port *port, int master_shelf)
}
port->ctl_pool_ref = pool;
+ if (port->options.stqh_first == NULL)
+ STAILQ_INIT(&port->options);
+
mtx_lock(&control_softc->ctl_lock);
port->targ_port = port_num + (master_shelf != 0 ? 0 : CTL_MAX_PORTS);
port->max_initiators = CTL_MAX_INIT_PER_PORT;
@@ -214,6 +217,7 @@ ctl_port_deregister(struct ctl_port *port)
mtx_unlock(&control_softc->ctl_lock);
ctl_pool_free(pool);
+ ctl_free_opts(&port->options);
bailout:
return (retval);
diff --git a/sys/cam/ctl/ctl_frontend.h b/sys/cam/ctl/ctl_frontend.h
index 3bd8fa8..dae9ce8 100644
--- a/sys/cam/ctl/ctl_frontend.h
+++ b/sys/cam/ctl/ctl_frontend.h
@@ -39,8 +39,6 @@
#ifndef _CTL_FRONTEND_H_
#define _CTL_FRONTEND_H_
-#define CTL_FE_NAME_LEN 32
-
typedef enum {
CTL_PORT_STATUS_NONE = 0x00,
CTL_PORT_STATUS_ONLINE = 0x01,
@@ -232,12 +230,13 @@ struct ctl_port {
uint64_t wwnn; /* set by CTL before online */
uint64_t wwpn; /* set by CTL before online */
ctl_port_status status; /* used by CTL */
+ ctl_options_t options; /* passed to CTL */
STAILQ_ENTRY(ctl_port) fe_links; /* used by CTL */
STAILQ_ENTRY(ctl_port) links; /* used by CTL */
};
struct ctl_frontend {
- char name[CTL_FE_NAME_LEN]; /* passed to CTL */
+ char name[CTL_DRIVER_NAME_LEN]; /* passed to CTL */
fe_init_t init; /* passed to CTL */
fe_ioctl_t ioctl; /* passed to CTL */
void (*fe_dump)(void); /* passed to CTL */
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index b550755..e1d1982 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -164,6 +164,8 @@ static void cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
static void cfiscsi_session_terminate(struct cfiscsi_session *cs);
static struct cfiscsi_target *cfiscsi_target_find(struct cfiscsi_softc
*softc, const char *name);
+static struct cfiscsi_target *cfiscsi_target_find_or_create(
+ struct cfiscsi_softc *softc, const char *name, const char *alias);
static void cfiscsi_target_release(struct cfiscsi_target *ct);
static void cfiscsi_session_delete(struct cfiscsi_session *cs);
@@ -536,7 +538,7 @@ cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
cfiscsi_session_terminate(cs);
return;
}
- io = ctl_alloc_io(cs->cs_target->ct_softc->port.ctl_pool_ref);
+ io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
if (io == NULL) {
CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io; "
"dropping connection");
@@ -548,7 +550,7 @@ cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
io->io_hdr.io_type = CTL_IO_SCSI;
io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
- io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->port.targ_port;
+ io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
io->io_hdr.nexus.targ_target.id = 0;
io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun);
io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
@@ -602,7 +604,7 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
cs = PDU_SESSION(request);
bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
- io = ctl_alloc_io(cs->cs_target->ct_softc->port.ctl_pool_ref);
+ io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
if (io == NULL) {
CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io;"
"dropping connection");
@@ -614,7 +616,7 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request;
io->io_hdr.io_type = CTL_IO_TASK;
io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
- io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->port.targ_port;
+ io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
io->io_hdr.nexus.targ_target.id = 0;
io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun);
io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun;
@@ -1036,7 +1038,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
int error, last;
#ifdef notyet
- io = ctl_alloc_io(cs->cs_target->ct_softc->port.ctl_pool_ref);
+ io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
if (io == NULL) {
CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
return;
@@ -1045,7 +1047,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
io->io_hdr.io_type = CTL_IO_TASK;
io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
- io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->port.targ_port;
+ io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
io->io_hdr.nexus.targ_target.id = 0;
io->io_hdr.nexus.targ_lun = lun;
io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
@@ -1064,7 +1066,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
CFISCSI_SESSION_LOCK(cs);
TAILQ_FOREACH_SAFE(cdw,
&cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
- io = ctl_alloc_io(cs->cs_target->ct_softc->port.ctl_pool_ref);
+ io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
if (io == NULL) {
CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io");
return;
@@ -1073,8 +1075,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
io->io_hdr.io_type = CTL_IO_TASK;
io->io_hdr.nexus.initid.id = cs->cs_ctl_initid;
- io->io_hdr.nexus.targ_port =
- cs->cs_target->ct_softc->port.targ_port;
+ io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
io->io_hdr.nexus.targ_target.id = 0;
//io->io_hdr.nexus.targ_lun = lun; /* Not needed? */
io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
@@ -1197,7 +1198,7 @@ cfiscsi_session_register_initiator(struct cfiscsi_session *cs)
i, softc->max_initiators);
#endif
cs->cs_ctl_initid = i;
- error = ctl_add_initiator(0x0, softc->port.targ_port, cs->cs_ctl_initid);
+ error = ctl_add_initiator(0x0, cs->cs_target->ct_port.targ_port, cs->cs_ctl_initid);
if (error != 0) {
CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d", error);
mtx_lock(&softc->lock);
@@ -1221,7 +1222,7 @@ cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
softc = &cfiscsi_softc;
- error = ctl_remove_initiator(softc->port.targ_port, cs->cs_ctl_initid);
+ error = ctl_remove_initiator(cs->cs_target->ct_port.targ_port, cs->cs_ctl_initid);
if (error != 0) {
CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d",
error);
@@ -1312,7 +1313,6 @@ int
cfiscsi_init(void)
{
struct cfiscsi_softc *softc;
- struct ctl_port *port;
int retval;
softc = &cfiscsi_softc;
@@ -1326,46 +1326,13 @@ cfiscsi_init(void)
TAILQ_INIT(&softc->sessions);
TAILQ_INIT(&softc->targets);
- port = &softc->port;
- port->frontend = &cfiscsi_frontend;
- port->port_type = CTL_PORT_ISCSI;
- /* XXX KDM what should the real number be here? */
- port->num_requested_ctl_io = 4096;
- snprintf(softc->port_name, sizeof(softc->port_name), "iscsi");
- port->port_name = softc->port_name;
- port->port_online = cfiscsi_online;
- port->port_offline = cfiscsi_offline;
- port->onoff_arg = softc;
- port->lun_enable = cfiscsi_lun_enable;
- port->lun_disable = cfiscsi_lun_disable;
- port->targ_lun_arg = softc;
- port->devid = cfiscsi_devid;
- port->fe_datamove = cfiscsi_datamove;
- port->fe_done = cfiscsi_done;
-
- /* XXX KDM what should we report here? */
- /* XXX These should probably be fetched from CTL. */
- port->max_targets = 1;
- port->max_target_id = 15;
-
- retval = ctl_port_register(port, /*master_SC*/ 1);
- if (retval != 0) {
- CFISCSI_WARN("ctl_frontend_register() failed with error %d",
- retval);
- retval = 1;
- goto bailout;
- }
-
- softc->max_initiators = port->max_initiators;
+ softc->max_initiators = CTL_MAX_INIT_PER_PORT;
cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait",
sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
return (0);
-
-bailout:
- return (retval);
}
#ifdef ICL_KERNEL_PROXY
@@ -1392,10 +1359,23 @@ static void
cfiscsi_online(void *arg)
{
struct cfiscsi_softc *softc;
+ struct cfiscsi_target *ct;
+ int online;
+
+ ct = (struct cfiscsi_target *)arg;
+ softc = ct->ct_softc;
- softc = (struct cfiscsi_softc *)arg;
+ mtx_lock(&softc->lock);
+ if (ct->ct_online) {
+ mtx_unlock(&softc->lock);
+ return;
+ }
+ ct->ct_online = 1;
+ online = softc->online++;
+ mtx_unlock(&softc->lock);
+ if (online > 0)
+ return;
- softc->online = 1;
#ifdef ICL_KERNEL_PROXY
if (softc->listener != NULL)
icl_listen_free(softc->listener);
@@ -1407,16 +1387,28 @@ static void
cfiscsi_offline(void *arg)
{
struct cfiscsi_softc *softc;
+ struct cfiscsi_target *ct;
struct cfiscsi_session *cs;
+ int online;
- softc = (struct cfiscsi_softc *)arg;
-
- softc->online = 0;
+ ct = (struct cfiscsi_target *)arg;
+ softc = ct->ct_softc;
mtx_lock(&softc->lock);
- TAILQ_FOREACH(cs, &softc->sessions, cs_next)
- cfiscsi_session_terminate(cs);
+ if (!ct->ct_online) {
+ mtx_unlock(&softc->lock);
+ return;
+ }
+ ct->ct_online = 0;
+ online = --softc->online;
+
+ TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
+ if (cs->cs_target == ct)
+ cfiscsi_session_terminate(cs);
+ }
mtx_unlock(&softc->lock);
+ if (online > 0)
+ return;
#ifdef ICL_KERNEL_PROXY
icl_listen_free(softc->listener);
@@ -1440,18 +1432,19 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
cihp->initiator_name, cihp->initiator_addr,
cihp->target_name);
- if (softc->online == 0) {
+ ct = cfiscsi_target_find(softc, cihp->target_name);
+ if (ct == NULL) {
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
- "%s: port offline", __func__);
+ "%s: target not found", __func__);
return;
}
- ct = cfiscsi_target_find(softc, cihp->target_name);
- if (ct == NULL) {
+ if (ct->ct_online == 0) {
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
- "%s: target not found", __func__);
+ "%s: port offline", __func__);
+ cfiscsi_target_release(ct);
return;
}
@@ -1949,11 +1942,148 @@ cfiscsi_ioctl_receive(struct ctl_iscsi *ci)
#endif /* !ICL_KERNEL_PROXY */
+static void
+cfiscsi_ioctl_port_create(struct ctl_req *req)
+{
+ struct cfiscsi_target *ct;
+ struct ctl_port *port;
+ const char *target, *alias, *tag;
+ ctl_options_t opts;
+ int retval;
+
+ ctl_init_opts(&opts, req->num_args, req->kern_args);
+ target = ctl_get_opt(&opts, "cfiscsi_target");
+ alias = ctl_get_opt(&opts, "cfiscsi_target_alias");
+ tag = ctl_get_opt(&opts, "cfiscsi_portal_group_tag");
+ if (target == NULL || tag == NULL) {
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "Missing required argument");
+ return;
+ }
+ ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias);
+ if (ct == NULL) {
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "failed to create target \"%s\"", target);
+ return;
+ }
+ if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) {
+ cfiscsi_target_release(ct);
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "target \"%s\" already exist", target);
+ return;
+ }
+ port = &ct->ct_port;
+ if (ct->ct_state == CFISCSI_TARGET_STATE_DYING)
+ goto done;
+
+ port->frontend = &cfiscsi_frontend;
+ port->port_type = CTL_PORT_ISCSI;
+ /* XXX KDM what should the real number be here? */
+ port->num_requested_ctl_io = 4096;
+ port->port_name = "iscsi";
+ port->virtual_port = strtoul(tag, NULL, 0);
+ port->port_online = cfiscsi_online;
+ port->port_offline = cfiscsi_offline;
+ port->onoff_arg = ct;
+ port->lun_enable = cfiscsi_lun_enable;
+ port->lun_disable = cfiscsi_lun_disable;
+ port->targ_lun_arg = ct;
+ port->devid = cfiscsi_devid;
+ port->fe_datamove = cfiscsi_datamove;
+ port->fe_done = cfiscsi_done;
+
+ /* XXX KDM what should we report here? */
+ /* XXX These should probably be fetched from CTL. */
+ port->max_targets = 1;
+ port->max_target_id = 15;
+
+ port->options = opts;
+ STAILQ_INIT(&opts);
+
+ retval = ctl_port_register(port, /*master_SC*/ 1);
+ if (retval != 0) {
+ ctl_free_opts(&port->options);
+ cfiscsi_target_release(ct);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "ctl_frontend_register() failed with error %d", retval);
+ return;
+ }
+done:
+ ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE;
+ req->status = CTL_LUN_OK;
+ memcpy(req->kern_args[0].kvalue, &port->targ_port,
+ sizeof(port->targ_port)); //XXX
+}
+
+static void
+cfiscsi_ioctl_port_remove(struct ctl_req *req)
+{
+ struct cfiscsi_target *ct;
+ const char *target;
+ ctl_options_t opts;
+
+ ctl_init_opts(&opts, req->num_args, req->kern_args);
+ target = ctl_get_opt(&opts, "cfiscsi_target");
+ if (target == NULL) {
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "Missing required argument");
+ return;
+ }
+ ct = cfiscsi_target_find(&cfiscsi_softc, target);
+ if (ct == NULL) {
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "can't find target \"%s\"", target);
+ return;
+ }
+ if (ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE) {
+ ctl_free_opts(&opts);
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "target \"%s\" is already dying", target);
+ return;
+ }
+ ctl_free_opts(&opts);
+
+ ct->ct_state = CFISCSI_TARGET_STATE_DYING;
+ ctl_port_offline(&ct->ct_port);
+ cfiscsi_target_release(ct);
+ cfiscsi_target_release(ct);
+}
+
static int
cfiscsi_ioctl(struct cdev *dev,
u_long cmd, caddr_t addr, int flag, struct thread *td)
{
struct ctl_iscsi *ci;
+ struct ctl_req *req;
+
+ if (cmd == CTL_PORT_REQ) {
+ req = (struct ctl_req *)addr;
+ switch (req->reqtype) {
+ case CTL_REQ_CREATE:
+ cfiscsi_ioctl_port_create(req);
+ break;
+ case CTL_REQ_REMOVE:
+ cfiscsi_ioctl_port_remove(req);
+ break;
+ default:
+ req->status = CTL_LUN_ERROR;
+ snprintf(req->error_str, sizeof(req->error_str),
+ "Unsupported request type %d", req->reqtype);
+ }
+ return (0);
+ }
if (cmd != CTL_ISCSI)
return (ENOTTY);
@@ -2223,6 +2353,12 @@ cfiscsi_target_release(struct cfiscsi_target *ct)
if (refcount_release(&ct->ct_refcount)) {
TAILQ_REMOVE(&softc->targets, ct, ct_next);
mtx_unlock(&softc->lock);
+ if (ct->ct_state != CFISCSI_TARGET_STATE_INVALID) {
+ ct->ct_state = CFISCSI_TARGET_STATE_INVALID;
+ if (ctl_port_deregister(&ct->ct_port) != 0)
+ printf("%s: ctl_port_deregister() failed\n",
+ __func__);
+ }
free(ct, M_CFISCSI);
return;
@@ -2237,7 +2373,8 @@ cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name)
mtx_lock(&softc->lock);
TAILQ_FOREACH(ct, &softc->targets, ct_next) {
- if (strcmp(name, ct->ct_name) != 0)
+ if (strcmp(name, ct->ct_name) != 0 ||
+ ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE)
continue;
cfiscsi_target_hold(ct);
mtx_unlock(&softc->lock);
@@ -2262,7 +2399,8 @@ cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name,
mtx_lock(&softc->lock);
TAILQ_FOREACH(ct, &softc->targets, ct_next) {
- if (strcmp(name, ct->ct_name) != 0)
+ if (strcmp(name, ct->ct_name) != 0 ||
+ ct->ct_state == CFISCSI_TARGET_STATE_INVALID)
continue;
cfiscsi_target_hold(ct);
mtx_unlock(&softc->lock);
@@ -2336,22 +2474,6 @@ cfiscsi_target_set_lun(struct cfiscsi_target *ct,
#endif
ct->ct_luns[lun_id] = ctl_lun_id;
- cfiscsi_target_hold(ct);
-
- return (0);
-}
-
-static int
-cfiscsi_target_unset_lun(struct cfiscsi_target *ct, unsigned long lun_id)
-{
-
- if (ct->ct_luns[lun_id] < 0) {
- CFISCSI_WARN("lun %ld not allocated", lun_id);
- return (-1);
- }
-
- ct->ct_luns[lun_id] = -1;
- cfiscsi_target_release(ct);
return (0);
}
@@ -2361,16 +2483,15 @@ cfiscsi_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
{
struct cfiscsi_softc *softc;
struct cfiscsi_target *ct;
- const char *target = NULL, *target_alias = NULL;
+ const char *target = NULL;
const char *lun = NULL;
unsigned long tmp;
- softc = (struct cfiscsi_softc *)arg;
+ ct = (struct cfiscsi_target *)arg;
+ softc = ct->ct_softc;
target = ctl_get_opt(&control_softc->ctl_luns[lun_id]->be_lun->options,
"cfiscsi_target");
- target_alias = ctl_get_opt(&control_softc->ctl_luns[lun_id]->be_lun->options,
- "cfiscsi_target_alias");
lun = ctl_get_opt(&control_softc->ctl_luns[lun_id]->be_lun->options,
"cfiscsi_lun");
@@ -2383,15 +2504,11 @@ cfiscsi_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
return (0);
}
- ct = cfiscsi_target_find_or_create(softc, target, target_alias);
- if (ct == NULL) {
- CFISCSI_WARN("failed to create target \"%s\"", target);
+ if (strcmp(target, ct->ct_name) != 0)
return (0);
- }
tmp = strtoul(lun, NULL, 10);
cfiscsi_target_set_lun(ct, tmp, lun_id);
- cfiscsi_target_release(ct);
return (0);
}
@@ -2402,19 +2519,17 @@ cfiscsi_lun_disable(void *arg, struct ctl_id target_id, int lun_id)
struct cfiscsi_target *ct;
int i;
- softc = (struct cfiscsi_softc *)arg;
+ ct = (struct cfiscsi_target *)arg;
+ softc = ct->ct_softc;
mtx_lock(&softc->lock);
- TAILQ_FOREACH(ct, &softc->targets, ct_next) {
- for (i = 0; i < CTL_MAX_LUNS; i++) {
- if (ct->ct_luns[i] < 0)
- continue;
- if (ct->ct_luns[i] != lun_id)
- continue;
- mtx_unlock(&softc->lock);
- cfiscsi_target_unset_lun(ct, i);
- return (0);
- }
+ for (i = 0; i < CTL_MAX_LUNS; i++) {
+ if (ct->ct_luns[i] < 0)
+ continue;
+ if (ct->ct_luns[i] != lun_id)
+ continue;
+ ct->ct_luns[lun_id] = -1;
+ break;
}
mtx_unlock(&softc->lock);
return (0);
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.h b/sys/cam/ctl/ctl_frontend_iscsi.h
index 02e77d4..887576a 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.h
+++ b/sys/cam/ctl/ctl_frontend_iscsi.h
@@ -32,6 +32,10 @@
#ifndef CTL_FRONTEND_ISCSI_H
#define CTL_FRONTEND_ISCSI_H
+#define CFISCSI_TARGET_STATE_INVALID 0
+#define CFISCSI_TARGET_STATE_ACTIVE 1
+#define CFISCSI_TARGET_STATE_DYING 2
+
struct cfiscsi_target {
TAILQ_ENTRY(cfiscsi_target) ct_next;
int ct_luns[CTL_MAX_LUNS];
@@ -39,6 +43,9 @@ struct cfiscsi_target {
volatile u_int ct_refcount;
char ct_name[CTL_ISCSI_NAME_LEN];
char ct_alias[CTL_ISCSI_ALIAS_LEN];
+ int ct_state;
+ int ct_online;
+ struct ctl_port ct_port;
};
struct cfiscsi_data_wait {
@@ -96,7 +103,6 @@ struct icl_listen;
#endif
struct cfiscsi_softc {
- struct ctl_port port;
struct mtx lock;
char port_name[32];
int online;
diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h
index 1144b75..06ff936 100644
--- a/sys/cam/ctl/ctl_ioctl.h
+++ b/sys/cam/ctl/ctl_ioctl.h
@@ -595,6 +595,45 @@ struct ctl_lun_list {
};
/*
+ * Port request interface:
+ *
+ * driver: This is required, and is NUL-terminated a string
+ * that is the name of the frontend, like "iscsi" .
+ *
+ * reqtype: The type of request, CTL_REQ_CREATE to create a
+ * port, CTL_REQ_REMOVE to delete a port.
+ *
+ * num_be_args: This is the number of frontend-specific arguments
+ * in the be_args array.
+ *
+ * be_args: This is an array of frontend-specific arguments.
+ * See above for a description of the fields in this
+ * structure.
+ *
+ * status: Status of the request.
+ *
+ * error_str: If the status is CTL_LUN_ERROR, this will
+ * contain a string describing the error.
+ *
+ * kern_be_args: For kernel use only.
+ */
+typedef enum {
+ CTL_REQ_CREATE,
+ CTL_REQ_REMOVE,
+ CTL_REQ_MODIFY,
+} ctl_req_type;
+
+struct ctl_req {
+ char driver[CTL_DRIVER_NAME_LEN];
+ ctl_req_type reqtype;
+ int num_args;
+ struct ctl_be_arg *args;
+ ctl_lun_status status;
+ char error_str[CTL_ERROR_STR_LEN];
+ struct ctl_be_arg *kern_args;
+};
+
+/*
* iSCSI status
*
* OK: Request completed successfully.
@@ -789,7 +828,8 @@ struct ctl_iscsi {
#define CTL_ERROR_INJECT_DELETE _IOW(CTL_MINOR, 0x23, struct ctl_error_desc)
#define CTL_SET_PORT_WWNS _IOW(CTL_MINOR, 0x24, struct ctl_port_entry)
#define CTL_ISCSI _IOWR(CTL_MINOR, 0x25, struct ctl_iscsi)
-#define CTL_PORT_LIST _IOWR(CTL_MINOR, 0x26, struct ctl_lun_list)
+#define CTL_PORT_REQ _IOWR(CTL_MINOR, 0x26, struct ctl_req)
+#define CTL_PORT_LIST _IOWR(CTL_MINOR, 0x27, struct ctl_lun_list)
#endif /* _CTL_IOCTL_H_ */
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 2cda316..e2b9ebe 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -1120,7 +1120,6 @@ conf_verify(struct conf *conf)
if (!found_lun) {
log_warnx("no LUNs defined for target \"%s\"",
targ->t_name);
- return (1);
}
}
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
@@ -1209,19 +1208,6 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
}
- if (oldconf->conf_kernel_port_on != newconf->conf_kernel_port_on) {
- if (newconf->conf_kernel_port_on == true) {
- log_debugx("enabling CTL iSCSI port");
- error = kernel_port_on();
- if (error != 0)
- log_errx(1, "failed to enable CTL iSCSI port; exiting");
- } else {
- error = kernel_port_off();
- if (error != 0)
- log_warnx("failed to disable CTL iSCSI port");
- }
- }
-
/*
* XXX: If target or lun removal fails, we should somehow "move"
* the old lun or target into newconf, so that subsequent
@@ -1253,6 +1239,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
lun_delete(oldlun);
}
+ kernel_port_remove(oldtarg);
target_delete(oldtarg);
continue;
}
@@ -1387,6 +1374,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
cumulated_error++;
}
}
+ if (oldtarg == NULL)
+ kernel_port_add(newtarg);
}
/*
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 3399648..5f7aea6 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -272,8 +272,8 @@ int kernel_lun_add(struct lun *lun);
int kernel_lun_resize(struct lun *lun);
int kernel_lun_remove(struct lun *lun);
void kernel_handoff(struct connection *conn);
-int kernel_port_on(void);
-int kernel_port_off(void);
+int kernel_port_add(struct target *targ);
+int kernel_port_remove(struct target *targ);
void kernel_capsicate(void);
#ifdef ICL_KERNEL_PROXY
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index 5f3408f..ecc43cf 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -119,10 +119,21 @@ struct cctl_lun {
STAILQ_ENTRY(cctl_lun) links;
};
+struct cctl_port {
+ uint32_t port_id;
+ char *cfiscsi_target;
+ uint16_t cfiscsi_portal_group_tag;
+ STAILQ_HEAD(,cctl_lun_nv) attr_list;
+ STAILQ_ENTRY(cctl_port) links;
+};
+
struct cctl_devlist_data {
int num_luns;
STAILQ_HEAD(,cctl_lun) lun_list;
struct cctl_lun *cur_lun;
+ int num_ports;
+ STAILQ_HEAD(,cctl_port) port_list;
+ struct cctl_port *cur_port;
int level;
struct sbuf *cur_sb[32];
};
@@ -247,6 +258,109 @@ cctl_end_element(void *user_data, const char *name)
}
static void
+cctl_start_pelement(void *user_data, const char *name, const char **attr)
+{
+ int i;
+ struct cctl_devlist_data *devlist;
+ struct cctl_port *cur_port;
+
+ devlist = (struct cctl_devlist_data *)user_data;
+ cur_port = devlist->cur_port;
+ devlist->level++;
+ if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
+ sizeof(devlist->cur_sb[0])))
+ log_errx(1, "%s: too many nesting levels, %zd max", __func__,
+ sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
+
+ devlist->cur_sb[devlist->level] = sbuf_new_auto();
+ if (devlist->cur_sb[devlist->level] == NULL)
+ log_err(1, "%s: unable to allocate sbuf", __func__);
+
+ if (strcmp(name, "targ_port") == 0) {
+ if (cur_port != NULL)
+ log_errx(1, "%s: improper port element nesting (%s)",
+ __func__, name);
+
+ cur_port = calloc(1, sizeof(*cur_port));
+ if (cur_port == NULL)
+ log_err(1, "%s: cannot allocate %zd bytes", __func__,
+ sizeof(*cur_port));
+
+ devlist->num_ports++;
+ devlist->cur_port = cur_port;
+
+ STAILQ_INIT(&cur_port->attr_list);
+ STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
+
+ for (i = 0; attr[i] != NULL; i += 2) {
+ if (strcmp(attr[i], "id") == 0) {
+ cur_port->port_id = strtoul(attr[i+1], NULL, 0);
+ } else {
+ log_errx(1, "%s: invalid LUN attribute %s = %s",
+ __func__, attr[i], attr[i+1]);
+ }
+ }
+ }
+}
+
+static void
+cctl_end_pelement(void *user_data, const char *name)
+{
+ struct cctl_devlist_data *devlist;
+ struct cctl_port *cur_port;
+ char *str;
+
+ devlist = (struct cctl_devlist_data *)user_data;
+ cur_port = devlist->cur_port;
+
+ if ((cur_port == NULL)
+ && (strcmp(name, "ctlportlist") != 0))
+ log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
+
+ if (devlist->cur_sb[devlist->level] == NULL)
+ log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
+ devlist->level, name);
+
+ sbuf_finish(devlist->cur_sb[devlist->level]);
+ str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
+
+ if (strlen(str) == 0) {
+ free(str);
+ str = NULL;
+ }
+
+ sbuf_delete(devlist->cur_sb[devlist->level]);
+ devlist->cur_sb[devlist->level] = NULL;
+ devlist->level--;
+
+ if (strcmp(name, "cfiscsi_target") == 0) {
+ cur_port->cfiscsi_target = str;
+ str = NULL;
+ } else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
+ cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
+ } else if (strcmp(name, "targ_port") == 0) {
+ devlist->cur_port = NULL;
+ } else if (strcmp(name, "ctlportlist") == 0) {
+
+ } else {
+ struct cctl_lun_nv *nv;
+
+ nv = calloc(1, sizeof(*nv));
+ if (nv == NULL)
+ log_err(1, "%s: can't allocate %zd bytes for nv pair",
+ __func__, sizeof(*nv));
+
+ nv->name = checked_strdup(name);
+
+ nv->value = str;
+ str = NULL;
+ STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
+ }
+
+ free(str);
+}
+
+static void
cctl_char_handler(void *user_data, const XML_Char *str, int len)
{
struct cctl_devlist_data *devlist;
@@ -266,50 +380,51 @@ conf_new_from_kernel(void)
struct ctl_lun_list list;
struct cctl_devlist_data devlist;
struct cctl_lun *lun;
+ struct cctl_port *port;
XML_Parser parser;
- char *lun_str = NULL;
- int lun_len;
- int retval;
-
- lun_len = 4096;
+ char *str;
+ int len, retval;
bzero(&devlist, sizeof(devlist));
STAILQ_INIT(&devlist.lun_list);
+ STAILQ_INIT(&devlist.port_list);
log_debugx("obtaining previously configured CTL luns from the kernel");
+ str = NULL;
+ len = 4096;
retry:
- lun_str = realloc(lun_str, lun_len);
- if (lun_str == NULL)
+ str = realloc(str, len);
+ if (str == NULL)
log_err(1, "realloc");
bzero(&list, sizeof(list));
- list.alloc_len = lun_len;
+ list.alloc_len = len;
list.status = CTL_LUN_LIST_NONE;
- list.lun_xml = lun_str;
+ list.lun_xml = str;
if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
log_warn("error issuing CTL_LUN_LIST ioctl");
- free(lun_str);
+ free(str);
return (NULL);
}
if (list.status == CTL_LUN_LIST_ERROR) {
log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
list.error_str);
- free(lun_str);
+ free(str);
return (NULL);
}
if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
- lun_len = lun_len << 1;
+ len = len << 1;
goto retry;
}
parser = XML_ParserCreate(NULL);
if (parser == NULL) {
log_warnx("unable to create XML parser");
- free(lun_str);
+ free(str);
return (NULL);
}
@@ -317,9 +432,58 @@ retry:
XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
XML_SetCharacterDataHandler(parser, cctl_char_handler);
- retval = XML_Parse(parser, lun_str, strlen(lun_str), 1);
+ retval = XML_Parse(parser, str, strlen(str), 1);
+ XML_ParserFree(parser);
+ free(str);
+ if (retval != 1) {
+ log_warnx("XML_Parse failed");
+ return (NULL);
+ }
+
+ str = NULL;
+ len = 4096;
+retry_port:
+ str = realloc(str, len);
+ if (str == NULL)
+ log_err(1, "realloc");
+
+ bzero(&list, sizeof(list));
+ list.alloc_len = len;
+ list.status = CTL_LUN_LIST_NONE;
+ list.lun_xml = str;
+
+ if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
+ log_warn("error issuing CTL_PORT_LIST ioctl");
+ free(str);
+ return (NULL);
+ }
+
+ if (list.status == CTL_PORT_LIST_ERROR) {
+ log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
+ list.error_str);
+ free(str);
+ return (NULL);
+ }
+
+ if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
+ len = len << 1;
+ goto retry_port;
+ }
+
+ parser = XML_ParserCreate(NULL);
+ if (parser == NULL) {
+ log_warnx("unable to create XML parser");
+ free(str);
+ return (NULL);
+ }
+
+ XML_SetUserData(parser, &devlist);
+ XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
+ XML_SetCharacterDataHandler(parser, cctl_char_handler);
+
+ retval = XML_Parse(parser, str, strlen(str), 1);
XML_ParserFree(parser);
- free(lun_str);
+ free(str);
if (retval != 1) {
log_warnx("XML_Parse failed");
return (NULL);
@@ -327,6 +491,28 @@ retry:
conf = conf_new();
+ STAILQ_FOREACH(port, &devlist.port_list, links) {
+
+ if (port->cfiscsi_target == NULL) {
+ log_debugx("CTL port %ju wasn't managed by ctld; "
+ "ignoring", (uintmax_t)port->port_id);
+ continue;
+ }
+
+ targ = target_find(conf, port->cfiscsi_target);
+ if (targ == NULL) {
+#if 0
+ log_debugx("found new kernel target %s for CTL port %ld",
+ port->cfiscsi_target, port->port_id);
+#endif
+ targ = target_new(conf, port->cfiscsi_target);
+ if (targ == NULL) {
+ log_warnx("target_new failed");
+ continue;
+ }
+ }
+ }
+
STAILQ_FOREACH(lun, &devlist.lun_list, links) {
struct cctl_lun_nv *nv;
@@ -391,6 +577,17 @@ retry:
return (conf);
}
+static void
+str_arg(struct ctl_be_arg *arg, const char *name, const char *value)
+{
+
+ arg->namelen = strlen(name) + 1;
+ arg->name = __DECONST(char *, name);
+ arg->vallen = strlen(value) + 1;
+ arg->value = __DECONST(char *, value);
+ arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
+}
+
int
kernel_lun_add(struct lun *lun)
{
@@ -482,14 +679,7 @@ kernel_lun_add(struct lun *lun)
i = 0;
TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
- /*
- * +1 for the terminating '\0'
- */
- req.be_args[i].namelen = strlen(lo->lo_name) + 1;
- req.be_args[i].name = lo->lo_name;
- req.be_args[i].vallen = strlen(lo->lo_value) + 1;
- req.be_args[i].value = lo->lo_value;
- req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
+ str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
i++;
}
assert(i == num_options);
@@ -634,15 +824,50 @@ kernel_handoff(struct connection *conn)
}
int
-kernel_port_on(void)
+kernel_port_add(struct target *targ)
{
struct ctl_port_entry entry;
+ struct ctl_req req;
+ char tagstr[16];
int error;
+ uint32_t port_id = -1;
- bzero(&entry, sizeof(entry));
+ bzero(&req, sizeof(req));
+ strlcpy(req.driver, "iscsi", sizeof(req.driver));
+ req.reqtype = CTL_REQ_CREATE;
+ req.num_args = 4;
+ req.args = malloc(req.num_args * sizeof(*req.args));
+ req.args[0].namelen = sizeof("port_id");
+ req.args[0].name = __DECONST(char *, "port_id");
+ req.args[0].vallen = sizeof(port_id);
+ req.args[0].value = &port_id;
+ req.args[0].flags = CTL_BEARG_WR;
+ str_arg(&req.args[1], "cfiscsi_target", targ->t_name);
+ str_arg(&req.args[2], "cfiscsi_target_alias", targ->t_alias);
+ snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag);
+ str_arg(&req.args[3], "cfiscsi_portal_group_tag", tagstr);
+
+ error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
+ free(req.args);
+ if (error != 0) {
+ log_warn("error issuing CTL_PORT_REQ ioctl");
+ return (1);
+ }
+
+ if (req.status == CTL_LUN_ERROR) {
+ log_warnx("error returned from port creation request: %s",
+ req.error_str);
+ return (1);
+ }
- entry.port_type = CTL_PORT_ISCSI;
- entry.targ_port = -1;
+ if (req.status != CTL_LUN_OK) {
+ log_warnx("unknown port creation request status %d",
+ req.status);
+ return (1);
+ }
+
+ bzero(&entry, sizeof(entry));
+ entry.targ_port = port_id;
error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
if (error != 0) {
@@ -654,20 +879,42 @@ kernel_port_on(void)
}
int
-kernel_port_off(void)
+kernel_port_remove(struct target *targ)
{
- struct ctl_port_entry entry;
+ struct ctl_req req;
+ char tagstr[16];
int error;
- bzero(&entry, sizeof(entry));
+ bzero(&req, sizeof(req));
+ strlcpy(req.driver, "iscsi", sizeof(req.driver));
+ req.reqtype = CTL_REQ_REMOVE;
+ req.num_args = 2;
+ req.args = malloc(req.num_args * sizeof(*req.args));
+ str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
+ if (targ->t_portal_group) {
+ snprintf(tagstr, sizeof(tagstr), "%d",
+ targ->t_portal_group->pg_tag);
+ str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
+ } else
+ req.num_args--;
+
+ error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
+ free(req.args);
+ if (error != 0) {
+ log_warn("error issuing CTL_PORT_REQ ioctl");
+ return (1);
+ }
- entry.port_type = CTL_PORT_ISCSI;
- entry.targ_port = -1;
+ if (req.status == CTL_LUN_ERROR) {
+ log_warnx("error returned from port removal request: %s",
+ req.error_str);
+ return (1);
+ }
- error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
- if (error != 0) {
- log_warn("CTL_DISABLE_PORT ioctl failed");
- return (-1);
+ if (req.status != CTL_LUN_OK) {
+ log_warnx("unknown port removal request status %d",
+ req.status);
+ return (1);
}
return (0);
OpenPOWER on IntegriCloud