Create separate CTL port for every iSCSI target (and maybe portal group).
Having single port for all iSCSI connections makes problematic implementing some more advanced SCSI functionality in CTL, that require proper ports enumeration and identification. This change extends CTL iSCSI API, making ctld daemon to control list of iSCSI ports in CTL. When new target is defined in config fine, ctld will create respective port in CTL. When target is removed -- port will be also removed after all active commands through that port properly aborted. This change require ctld to be rebuilt to match the kernel. As a minor side effect, this allows to have iSCSI targets without LUNs. While that may look odd and not very useful, that is not incorrect.
This commit is contained in:
parent
5f40879138
commit
917d38fb99
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=268291
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
softc = (struct cfiscsi_softc *)arg;
|
||||
ct = (struct cfiscsi_target *)arg;
|
||||
softc = ct->ct_softc;
|
||||
|
||||
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,13 +1432,6 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
|
||||
cihp->initiator_name, cihp->initiator_addr,
|
||||
cihp->target_name);
|
||||
|
||||
if (softc->online == 0) {
|
||||
ci->status = CTL_ISCSI_ERROR;
|
||||
snprintf(ci->error_str, sizeof(ci->error_str),
|
||||
"%s: port offline", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ct = cfiscsi_target_find(softc, cihp->target_name);
|
||||
if (ct == NULL) {
|
||||
ci->status = CTL_ISCSI_ERROR;
|
||||
@ -1455,6 +1440,14 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ct->ct_online == 0) {
|
||||
ci->status = CTL_ISCSI_ERROR;
|
||||
snprintf(ci->error_str, sizeof(ci->error_str),
|
||||
"%s: port offline", __func__);
|
||||
cfiscsi_target_release(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ICL_KERNEL_PROXY
|
||||
if (cihp->socket > 0 && cihp->connection_id > 0) {
|
||||
snprintf(ci->error_str, sizeof(ci->error_str),
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -594,6 +594,45 @@ struct ctl_lun_list {
|
||||
/* passed to userland */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -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_ */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
};
|
||||
@ -246,6 +257,109 @@ cctl_end_element(void *user_data, const char *name)
|
||||
free(str);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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 @@ conf_new_from_kernel(void)
|
||||
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(lun_str);
|
||||
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(str);
|
||||
if (retval != 1) {
|
||||
log_warnx("XML_Parse failed");
|
||||
return (NULL);
|
||||
@ -327,6 +491,28 @@ conf_new_from_kernel(void)
|
||||
|
||||
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 @@ conf_new_from_kernel(void)
|
||||
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(&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);
|
||||
}
|
||||
|
||||
if (req.status != CTL_LUN_OK) {
|
||||
log_warnx("unknown port creation request status %d",
|
||||
req.status);
|
||||
return (1);
|
||||
}
|
||||
|
||||
bzero(&entry, sizeof(entry));
|
||||
|
||||
entry.port_type = CTL_PORT_ISCSI;
|
||||
entry.targ_port = -1;
|
||||
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--;
|
||||
|
||||
entry.port_type = CTL_PORT_ISCSI;
|
||||
entry.targ_port = -1;
|
||||
|
||||
error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
|
||||
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
|
||||
free(req.args);
|
||||
if (error != 0) {
|
||||
log_warn("CTL_DISABLE_PORT ioctl failed");
|
||||
return (-1);
|
||||
log_warn("error issuing CTL_PORT_REQ ioctl");
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (req.status == CTL_LUN_ERROR) {
|
||||
log_warnx("error returned from port removal request: %s",
|
||||
req.error_str);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (req.status != CTL_LUN_OK) {
|
||||
log_warnx("unknown port removal request status %d",
|
||||
req.status);
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
Loading…
Reference in New Issue
Block a user