diff options
-rw-r--r-- | sys/cam/ctl/ctl.c | 39 | ||||
-rw-r--r-- | sys/cam/ctl/ctl.h | 2 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend.c | 4 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend.h | 5 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend_iscsi.c | 307 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend_iscsi.h | 8 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_ioctl.h | 42 | ||||
-rw-r--r-- | usr.sbin/ctld/ctld.c | 17 | ||||
-rw-r--r-- | usr.sbin/ctld/ctld.h | 4 | ||||
-rw-r--r-- | usr.sbin/ctld/kernel.c | 319 |
10 files changed, 593 insertions, 154 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index a0fc33a..22da757 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -3148,11 +3148,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; @@ -3219,6 +3249,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 06d2e55..6e4cdb3 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -168,6 +168,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); @@ -540,7 +542,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"); @@ -552,7 +554,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; @@ -606,7 +608,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"); @@ -618,7 +620,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; @@ -1040,7 +1042,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; @@ -1049,7 +1051,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 */ @@ -1068,7 +1070,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; @@ -1077,8 +1079,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 */ @@ -1201,7 +1202,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); @@ -1225,7 +1226,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); @@ -1316,7 +1317,6 @@ int cfiscsi_init(void) { struct cfiscsi_softc *softc; - struct ctl_port *port; int retval; softc = &cfiscsi_softc; @@ -1330,46 +1330,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 @@ -1396,10 +1363,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); @@ -1411,16 +1391,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); @@ -1444,18 +1436,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; } @@ -1953,11 +1946,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); @@ -2227,6 +2357,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; @@ -2241,7 +2377,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); @@ -2266,7 +2403,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); @@ -2340,22 +2478,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); } @@ -2365,16 +2487,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"); @@ -2387,15 +2508,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); } @@ -2406,19 +2523,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 a8799f8..0225691 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); |