CTL changes required for iSCSI target, most notably LUN remapping

and a mechanism to allow CTL frontends for retrieving LUN options.

Reviewed by:	ken (earlier version)
This commit is contained in:
Edward Tomasz Napierala 2013-08-24 01:50:31 +00:00
parent 83b6a67e66
commit 81a2151d5c
7 changed files with 160 additions and 64 deletions

View File

@ -894,8 +894,13 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param)
struct ctl_lun *lun;
struct ctl_page_index *page_index;
struct copan_aps_subpage *current_sp;
uint32_t targ_lun;
lun = ctl_softc->ctl_luns[msg_info.hdr.nexus.targ_lun];
targ_lun = msg_info.hdr.nexus.targ_lun;
if (msg_info.hdr.nexus.lun_map_fn != NULL)
targ_lun = msg_info.hdr.nexus.lun_map_fn(msg_info.hdr.nexus.lun_map_arg, targ_lun);
lun = ctl_softc->ctl_luns[targ_lun];
page_index = &lun->mode_pages.index[index_to_aps_page];
current_sp = (struct copan_aps_subpage *)
(page_index->page_data +
@ -1098,6 +1103,7 @@ ctl_init(void)
mtx_unlock(&softc->ctl_lock);
return (error);
}
if (bootverbose)
printf("ctl: CAM Target Layer loaded\n");
/*
@ -1194,6 +1200,7 @@ ctl_shutdown(void)
free(control_softc, M_DEVBUF);
control_softc = NULL;
if (bootverbose)
printf("ctl: CAM Target Layer unloaded\n");
}
@ -1678,12 +1685,16 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio, int have_lock)
union ctl_ha_msg msg_info;
struct ctl_lun *lun;
int retval = 0;
uint32_t targ_lun;
ctl_softc = control_softc;
if (have_lock == 0)
mtx_lock(&ctl_softc->ctl_lock);
lun = ctl_softc->ctl_luns[ctsio->io_hdr.nexus.targ_lun];
targ_lun = ctsio->io_hdr.nexus.targ_lun;
if (ctsio->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = ctsio->io_hdr.nexus.lun_map_fn(ctsio->io_hdr.nexus.lun_map_arg, targ_lun);
lun = ctl_softc->ctl_luns[targ_lun];
if (lun==NULL)
{
/*
@ -2980,6 +2991,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct sbuf *sb;
struct ctl_lun *lun;
struct ctl_lun_list *list;
struct ctl_be_lun_option *opt;
list = (struct ctl_lun_list *)addr;
@ -3097,17 +3109,16 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
if (retval != 0)
break;
if (lun->backend->lun_info == NULL) {
retval = sbuf_printf(sb, "</lun>\n");
if (lun->backend->lun_info != NULL) {
retval = lun->backend->lun_info(lun->be_lun->be_lun, sb);
if (retval != 0)
break;
continue;
}
retval =lun->backend->lun_info(lun->be_lun->be_lun, sb);
STAILQ_FOREACH(opt, &lun->be_lun->options, links) {
retval = sbuf_printf(sb, "<%s>%s</%s>", opt->name, opt->value, opt->name);
if (retval != 0)
break;
}
retval = sbuf_printf(sb, "</lun>\n");
@ -4432,9 +4443,14 @@ ctl_free_lun(struct ctl_lun *lun)
*/
for (io = (union ctl_io *)STAILQ_FIRST(&softc->rtr_queue); io != NULL;
io = next_io) {
uint32_t targ_lun;
next_io = (union ctl_io *)STAILQ_NEXT(&io->io_hdr, links);
targ_lun = io->io_hdr.nexus.targ_lun;
if (io->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = io->io_hdr.nexus.lun_map_fn(io->io_hdr.nexus.lun_map_arg, targ_lun);
if ((io->io_hdr.nexus.targ_target.id == lun->target.id)
&& (io->io_hdr.nexus.targ_lun == lun->lun))
&& (targ_lun == lun->lun))
STAILQ_REMOVE(&softc->rtr_queue, &io->io_hdr,
ctl_io_hdr, links);
}
@ -8247,12 +8263,16 @@ ctl_hndl_per_res_out_on_other_sc(union ctl_ha_msg *msg)
struct ctl_lun *lun;
struct ctl_softc *softc;
int i;
uint32_t targ_lun;
softc = control_softc;
mtx_lock(&softc->ctl_lock);
lun = softc->ctl_luns[msg->hdr.nexus.targ_lun];
targ_lun = msg->hdr.nexus.targ_lun;
if (msg->hdr.nexus.lun_map_fn != NULL)
targ_lun = msg->hdr.nexus.lun_map_fn(msg->hdr.nexus.lun_map_arg, targ_lun);
lun = softc->ctl_luns[targ_lun];
switch(msg->pr.pr_info.action) {
case CTL_PR_REG_KEY:
if (!lun->per_res[msg->pr.pr_info.residx].registered) {
@ -8601,7 +8621,7 @@ ctl_report_luns(struct ctl_scsiio *ctsio)
int num_luns, retval;
uint32_t alloc_len, lun_datalen;
int num_filled, well_known;
uint32_t initidx;
uint32_t initidx, targ_lun_id, lun_id;
retval = CTL_RETVAL_COMPLETE;
well_known = 0;
@ -8662,63 +8682,47 @@ ctl_report_luns(struct ctl_scsiio *ctsio)
lun_data = (struct scsi_report_luns_data *)ctsio->kern_data_ptr;
ctsio->kern_sg_entries = 0;
if (lun_datalen < alloc_len) {
ctsio->residual = alloc_len - lun_datalen;
ctsio->kern_data_len = lun_datalen;
ctsio->kern_total_len = lun_datalen;
} else {
ctsio->residual = 0;
ctsio->kern_data_len = alloc_len;
ctsio->kern_total_len = alloc_len;
}
ctsio->kern_data_resid = 0;
ctsio->kern_rel_offset = 0;
ctsio->kern_sg_entries = 0;
initidx = ctl_get_initindex(&ctsio->io_hdr.nexus);
/*
* We set this to the actual data length, regardless of how much
* space we actually have to return results. If the user looks at
* this value, he'll know whether or not he allocated enough space
* and reissue the command if necessary. We don't support well
* known logical units, so if the user asks for that, return none.
*/
scsi_ulto4b(lun_datalen - 8, lun_data->length);
mtx_lock(&control_softc->ctl_lock);
for (num_filled = 0, lun = STAILQ_FIRST(&control_softc->lun_list);
(lun != NULL) && (num_filled < num_luns);
lun = STAILQ_NEXT(lun, links)) {
for (targ_lun_id = 0, num_filled = 0; targ_lun_id < CTL_MAX_LUNS && num_filled < num_luns; targ_lun_id++) {
lun_id = targ_lun_id;
if (ctsio->io_hdr.nexus.lun_map_fn != NULL)
lun_id = ctsio->io_hdr.nexus.lun_map_fn(ctsio->io_hdr.nexus.lun_map_arg, lun_id);
if (lun_id >= CTL_MAX_LUNS)
continue;
lun = control_softc->ctl_luns[lun_id];
if (lun == NULL)
continue;
if (lun->lun <= 0xff) {
if (targ_lun_id <= 0xff) {
/*
* Peripheral addressing method, bus number 0.
*/
lun_data->luns[num_filled].lundata[0] =
RPL_LUNDATA_ATYP_PERIPH;
lun_data->luns[num_filled].lundata[1] = lun->lun;
lun_data->luns[num_filled].lundata[1] = targ_lun_id;
num_filled++;
} else if (lun->lun <= 0x3fff) {
} else if (targ_lun_id <= 0x3fff) {
/*
* Flat addressing method.
*/
lun_data->luns[num_filled].lundata[0] =
RPL_LUNDATA_ATYP_FLAT |
(lun->lun & RPL_LUNDATA_FLAT_LUN_MASK);
(targ_lun_id & RPL_LUNDATA_FLAT_LUN_MASK);
#ifdef OLDCTLHEADERS
(SRLD_ADDR_FLAT << SRLD_ADDR_SHIFT) |
(lun->lun & SRLD_BUS_LUN_MASK);
(targ_lun_id & SRLD_BUS_LUN_MASK);
#endif
lun_data->luns[num_filled].lundata[1] =
#ifdef OLDCTLHEADERS
lun->lun >> SRLD_BUS_LUN_BITS;
targ_lun_id >> SRLD_BUS_LUN_BITS;
#endif
lun->lun >> RPL_LUNDATA_FLAT_LUN_BITS;
targ_lun_id >> RPL_LUNDATA_FLAT_LUN_BITS;
num_filled++;
} else {
printf("ctl_report_luns: bogus LUN number %jd, "
"skipping\n", (intmax_t)lun->lun);
"skipping\n", (intmax_t)targ_lun_id);
}
/*
* According to SPC-3, rev 14 section 6.21:
@ -8742,6 +8746,35 @@ ctl_report_luns(struct ctl_scsiio *ctsio)
}
mtx_unlock(&control_softc->ctl_lock);
/*
* It's quite possible that we've returned fewer LUNs than we allocated
* space for. Trim it.
*/
lun_datalen = sizeof(*lun_data) +
(num_filled * sizeof(struct scsi_report_luns_lundata));
if (lun_datalen < alloc_len) {
ctsio->residual = alloc_len - lun_datalen;
ctsio->kern_data_len = lun_datalen;
ctsio->kern_total_len = lun_datalen;
} else {
ctsio->residual = 0;
ctsio->kern_data_len = alloc_len;
ctsio->kern_total_len = alloc_len;
}
ctsio->kern_data_resid = 0;
ctsio->kern_rel_offset = 0;
ctsio->kern_sg_entries = 0;
/*
* We set this to the actual data length, regardless of how much
* space we actually have to return results. If the user looks at
* this value, he'll know whether or not he allocated enough space
* and reissue the command if necessary. We don't support well
* known logical units, so if the user asks for that, return none.
*/
scsi_ulto4b(lun_datalen - 8, lun_data->length);
/*
* We can only return SCSI_STATUS_CHECK_COND when we can't satisfy
* this request.
@ -9077,6 +9110,14 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len)
int devid_len;
ctl_softc = control_softc;
mtx_lock(&ctl_softc->ctl_lock);
fe = ctl_softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)];
mtx_unlock(&ctl_softc->ctl_lock);
if (fe->devid != NULL)
return ((fe->devid)(ctsio, alloc_len));
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
devid_len = sizeof(struct scsi_vpd_device_id) +
@ -9130,8 +9171,6 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len)
mtx_lock(&ctl_softc->ctl_lock);
fe = ctl_softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)];
/*
* For Fibre channel,
*/
@ -10350,7 +10389,7 @@ ctl_scsiio_precheck(struct ctl_softc *ctl_softc, struct ctl_scsiio *ctsio)
struct ctl_lun *lun;
struct ctl_cmd_entry *entry;
uint8_t opcode;
uint32_t initidx;
uint32_t initidx, targ_lun;
int retval;
retval = 0;
@ -10361,9 +10400,12 @@ ctl_scsiio_precheck(struct ctl_softc *ctl_softc, struct ctl_scsiio *ctsio)
mtx_lock(&ctl_softc->ctl_lock);
if ((ctsio->io_hdr.nexus.targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[ctsio->io_hdr.nexus.targ_lun] != NULL)) {
lun = ctl_softc->ctl_luns[ctsio->io_hdr.nexus.targ_lun];
targ_lun = ctsio->io_hdr.nexus.targ_lun;
if (ctsio->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = ctsio->io_hdr.nexus.lun_map_fn(ctsio->io_hdr.nexus.lun_map_arg, targ_lun);
if ((targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[targ_lun] != NULL)) {
lun = ctl_softc->ctl_luns[targ_lun];
/*
* If the LUN is invalid, pretend that it doesn't exist.
* It will go away as soon as all pending I/O has been
@ -10403,6 +10445,7 @@ ctl_scsiio_precheck(struct ctl_softc *ctl_softc, struct ctl_scsiio *ctsio)
ctl_set_unsupported_lun(ctsio);
mtx_unlock(&ctl_softc->ctl_lock);
ctl_done((union ctl_io *)ctsio);
CTL_DEBUG_PRINT(("ctl_scsiio_precheck: bailing out due to invalid LUN\n"));
goto bailout;
} else {
/*
@ -10769,6 +10812,7 @@ ctl_abort_task(union ctl_io *io)
char printbuf[128];
#endif
int found;
uint32_t targ_lun;
ctl_softc = control_softc;
found = 0;
@ -10776,9 +10820,12 @@ ctl_abort_task(union ctl_io *io)
/*
* Look up the LUN.
*/
if ((io->io_hdr.nexus.targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[io->io_hdr.nexus.targ_lun] != NULL))
lun = ctl_softc->ctl_luns[io->io_hdr.nexus.targ_lun];
targ_lun = io->io_hdr.nexus.targ_lun;
if (io->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = io->io_hdr.nexus.lun_map_fn(io->io_hdr.nexus.lun_map_arg, targ_lun);
if ((targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[targ_lun] != NULL))
lun = ctl_softc->ctl_luns[targ_lun];
else
goto bailout;
@ -10968,6 +11015,8 @@ ctl_run_task_queue(struct ctl_softc *ctl_softc)
int retval;
targ_lun = io->io_hdr.nexus.targ_lun;
if (io->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = io->io_hdr.nexus.lun_map_fn(io->io_hdr.nexus.lun_map_arg, targ_lun);
if ((targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[targ_lun] != NULL))
@ -11042,7 +11091,7 @@ ctl_run_task_queue(struct ctl_softc *ctl_softc)
(uintmax_t)io->io_hdr.nexus.initid.id,
io->io_hdr.nexus.targ_port,
(uintmax_t)io->io_hdr.nexus.targ_target.id,
io->io_hdr.nexus.targ_lun,
io->io_hdr.nexus.targ_lun /* XXX */,
(io->io_hdr.io_type == CTL_IO_TASK) ?
io->taskio.tag_num : io->scsiio.tag_num);
STAILQ_REMOVE(&ctl_softc->task_queue, &io->io_hdr,
@ -11066,10 +11115,14 @@ ctl_handle_isc(union ctl_io *io)
int free_io;
struct ctl_lun *lun;
struct ctl_softc *ctl_softc;
uint32_t targ_lun;
ctl_softc = control_softc;
lun = ctl_softc->ctl_luns[io->io_hdr.nexus.targ_lun];
targ_lun = io->io_hdr.nexus.targ_lun;
if (io->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = io->io_hdr.nexus.lun_map_fn(io->io_hdr.nexus.lun_map_arg, targ_lun);
lun = ctl_softc->ctl_luns[targ_lun];
switch (io->io_hdr.msg_type) {
case CTL_MSG_SERIALIZE:
@ -12625,7 +12678,7 @@ ctl_queue_sense(union ctl_io *io)
{
struct ctl_lun *lun;
struct ctl_softc *ctl_softc;
uint32_t initidx;
uint32_t initidx, targ_lun;
ctl_softc = control_softc;
@ -12644,9 +12697,12 @@ ctl_queue_sense(union ctl_io *io)
* If we don't have a LUN for this, just toss the sense
* information.
*/
if ((io->io_hdr.nexus.targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[io->io_hdr.nexus.targ_lun] != NULL))
lun = ctl_softc->ctl_luns[io->io_hdr.nexus.targ_lun];
targ_lun = io->io_hdr.nexus.targ_lun;
if (io->io_hdr.nexus.lun_map_fn != NULL)
targ_lun = io->io_hdr.nexus.lun_map_fn(io->io_hdr.nexus.lun_map_arg, targ_lun);
if ((targ_lun < CTL_MAX_LUNS)
&& (ctl_softc->ctl_luns[targ_lun] != NULL))
lun = ctl_softc->ctl_luns[targ_lun];
else
goto bailout;
@ -13047,6 +13103,8 @@ ctl_isc_start(struct ctl_ha_component *c, ctl_ha_state state)
{
ctl_ha_comp_status ret = CTL_HA_COMP_STATUS_OK;
printf("%s: go\n", __func__);
// UNKNOWN->HA or UNKNOWN->SINGLE (bootstrap)
if (c->state == CTL_HA_STATE_UNKNOWN ) {
ctl_is_single = 0;

View File

@ -52,6 +52,7 @@ typedef enum {
CTL_PORT_SCSI = 0x02,
CTL_PORT_IOCTL = 0x04,
CTL_PORT_INTERNAL = 0x08,
CTL_PORT_ISCSI = 0x10,
CTL_PORT_ALL = 0xff,
CTL_PORT_ISC = 0x100 // FC port for inter-shelf communication
} ctl_port_type;

View File

@ -173,6 +173,12 @@ typedef void (*be_lun_config_t)(void *be_lun,
* The links field is for CTL internal use only, and should not be used by
* the backend.
*/
struct ctl_be_lun_option {
STAILQ_ENTRY(ctl_be_lun_option) links;
char *name;
char *value;
};
struct ctl_be_lun {
uint8_t lun_type; /* passed to CTL */
ctl_backend_lun_flags flags; /* passed to CTL */
@ -187,6 +193,7 @@ struct ctl_be_lun {
be_lun_config_t lun_config_status; /* passed to CTL */
struct ctl_backend_driver *be; /* passed to CTL */
void *ctl_lun; /* used by CTL */
STAILQ_HEAD(, ctl_be_lun_option) options; /* passed to CTL */
STAILQ_ENTRY(ctl_be_lun) links; /* used by CTL */
};

View File

@ -1639,6 +1639,7 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
STAILQ_INIT(&be_lun->input_queue);
STAILQ_INIT(&be_lun->config_write_queue);
STAILQ_INIT(&be_lun->datamove_queue);
STAILQ_INIT(&be_lun->ctl_be_lun.options);
sprintf(be_lun->lunname, "cblk%d", softc->num_luns);
mtx_init(&be_lun->lock, be_lun->lunname, NULL, MTX_DEF);
@ -1740,6 +1741,16 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
}
num_threads = tmp_num_threads;
} else if (strcmp(req->kern_be_args[i].kname, "file") != 0 &&
strcmp(req->kern_be_args[i].kname, "dev") != 0) {
struct ctl_be_lun_option *opt;
opt = malloc(sizeof(*opt), M_CTLBLK, M_WAITOK);
opt->name = malloc(strlen(req->kern_be_args[i].kname) + 1, M_CTLBLK, M_WAITOK);
strcpy(opt->name, req->kern_be_args[i].kname);
opt->value = malloc(strlen(req->kern_be_args[i].kvalue) + 1, M_CTLBLK, M_WAITOK);
strcpy(opt->value, req->kern_be_args[i].kvalue);
STAILQ_INSERT_TAIL(&be_lun->ctl_be_lun.options, opt, links);
}
}

View File

@ -491,7 +491,7 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
struct ctl_lun_create_params *params;
uint32_t blocksize;
char tmpstr[32];
int retval;
int i, retval;
retval = 0;
params = &req->reqdata.create;
@ -509,6 +509,7 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
sizeof(*be_lun));
goto bailout_error;
}
STAILQ_INIT(&be_lun->ctl_be_lun.options);
if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
be_lun->ctl_be_lun.lun_type = params->device_type;
@ -545,6 +546,17 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
be_lun->softc = softc;
for (i = 0; i < req->num_be_args; i++) {
struct ctl_be_lun_option *opt;
opt = malloc(sizeof(*opt), M_RAMDISK, M_WAITOK);
opt->name = malloc(strlen(req->kern_be_args[i].kname) + 1, M_RAMDISK, M_WAITOK);
strcpy(opt->name, req->kern_be_args[i].kname);
opt->value = malloc(strlen(req->kern_be_args[i].kvalue) + 1, M_RAMDISK, M_WAITOK);
strcpy(opt->value, req->kern_be_args[i].kvalue);
STAILQ_INSERT_TAIL(&be_lun->ctl_be_lun.options, opt, links);
}
be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED;
be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY;
be_lun->ctl_be_lun.be_lun = be_lun;

View File

@ -49,6 +49,9 @@ typedef enum {
typedef void (*port_func_t)(void *onoff_arg);
typedef int (*targ_func_t)(void *arg, struct ctl_id targ_id);
typedef int (*lun_func_t)(void *arg, struct ctl_id targ_id, int lun_id);
typedef int (*fe_ioctl_t)(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td);
typedef int (*fe_devid_t)(struct ctl_scsiio *ctsio, int alloc_len);
/*
* The ctl_frontend structure is the registration mechanism between a FETD
@ -213,6 +216,8 @@ struct ctl_frontend {
targ_func_t targ_disable; /* passed to CTL */
lun_func_t lun_enable; /* passed to CTL */
lun_func_t lun_disable; /* passed to CTL */
fe_ioctl_t ioctl; /* passed to CTL */
fe_devid_t devid; /* passed to CTL */
void *targ_lun_arg; /* passed to CTL */
void (*fe_datamove)(union ctl_io *io); /* passed to CTL */
void (*fe_done)(union ctl_io *io); /* passed to CTL */

View File

@ -204,6 +204,8 @@ struct ctl_nexus {
uint32_t targ_port; /* Target port, filled in by PORT */
struct ctl_id targ_target; /* Destination target */
uint32_t targ_lun; /* Destination lun */
uint32_t (*lun_map_fn)(void *arg, uint32_t lun);
void *lun_map_arg;
};
typedef enum {