diff options
author | mav <mav@FreeBSD.org> | 2015-11-13 19:24:44 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2015-11-13 19:24:44 +0000 |
commit | 747538c2de6eb571e0eff6a8129c0c9d7b0bd7b8 (patch) | |
tree | 3b3001bc4ed57f16d6d538305b52e778fea32318 /sys | |
parent | 800769b3180e3137c36d2185a689835c2b4dfd28 (diff) | |
download | FreeBSD-src-747538c2de6eb571e0eff6a8129c0c9d7b0bd7b8.zip FreeBSD-src-747538c2de6eb571e0eff6a8129c0c9d7b0bd7b8.tar.gz |
MFC r289881: Give CTL support for PIM_EXTLUNS when talking to CAM.
CTL itself still lives in flat LUN space, but it can generate extended
numbers if CAM SIM reports such capability.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/cam/ctl/ctl.c | 94 | ||||
-rw-r--r-- | sys/cam/ctl/ctl.h | 3 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend_cam_sim.c | 11 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend_iscsi.c | 61 | ||||
-rw-r--r-- | sys/cam/ctl/scsi_ctl.c | 35 |
5 files changed, 103 insertions, 101 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 926ab75..9635d51 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -3540,6 +3540,67 @@ ctl_lun_map_to_port(struct ctl_port *port, uint32_t lun_id) return (UINT32_MAX); } +uint32_t +ctl_decode_lun(uint64_t encoded) +{ + uint8_t lun[8]; + uint32_t result = 0xffffffff; + + be64enc(lun, encoded); + switch (lun[0] & RPL_LUNDATA_ATYP_MASK) { + case RPL_LUNDATA_ATYP_PERIPH: + if ((lun[0] & 0x3f) == 0 && lun[2] == 0 && lun[3] == 0 && + lun[4] == 0 && lun[5] == 0 && lun[6] == 0 && lun[7] == 0) + result = lun[1]; + break; + case RPL_LUNDATA_ATYP_FLAT: + if (lun[2] == 0 && lun[3] == 0 && lun[4] == 0 && lun[5] == 0 && + lun[6] == 0 && lun[7] == 0) + result = ((lun[0] & 0x3f) << 8) + lun[1]; + break; + case RPL_LUNDATA_ATYP_EXTLUN: + switch (lun[0] & RPL_LUNDATA_EXT_EAM_MASK) { + case 0x02: + switch (lun[0] & RPL_LUNDATA_EXT_LEN_MASK) { + case 0x00: + result = lun[1]; + break; + case 0x10: + result = (lun[1] << 16) + (lun[2] << 8) + + lun[3]; + break; + case 0x20: + if (lun[1] == 0 && lun[6] == 0 && lun[7] == 0) + result = (lun[2] << 24) + + (lun[3] << 16) + (lun[4] << 8) + + lun[5]; + break; + } + break; + case RPL_LUNDATA_EXT_EAM_NOT_SPEC: + result = 0xffffffff; + break; + } + break; + } + return (result); +} + +uint64_t +ctl_encode_lun(uint32_t decoded) +{ + uint64_t l = decoded; + + if (l <= 0xff) + return (((uint64_t)RPL_LUNDATA_ATYP_PERIPH << 56) | (l << 48)); + if (l <= 0x3fff) + return (((uint64_t)RPL_LUNDATA_ATYP_FLAT << 56) | (l << 48)); + if (l <= 0xffffff) + return (((uint64_t)(RPL_LUNDATA_ATYP_EXTLUN | 0x12) << 56) | + (l << 32)); + return ((((uint64_t)RPL_LUNDATA_ATYP_EXTLUN | 0x22) << 56) | (l << 16)); +} + static struct ctl_port * ctl_io_port(struct ctl_io_hdr *io_hdr) { @@ -9063,36 +9124,9 @@ ctl_report_luns(struct ctl_scsiio *ctsio) if (lun == NULL) continue; - 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] = targ_lun_id; - num_filled++; - } else if (targ_lun_id <= 0x3fff) { - /* - * Flat addressing method. - */ - lun_data->luns[num_filled].lundata[0] = - RPL_LUNDATA_ATYP_FLAT | (targ_lun_id >> 8); - lun_data->luns[num_filled].lundata[1] = - (targ_lun_id & 0xff); - num_filled++; - } else if (targ_lun_id <= 0xffffff) { - /* - * Extended flat addressing method. - */ - lun_data->luns[num_filled].lundata[0] = - RPL_LUNDATA_ATYP_EXTLUN | 0x12; - scsi_ulto3b(targ_lun_id, - &lun_data->luns[num_filled].lundata[1]); - num_filled++; - } else { - printf("ctl_report_luns: bogus LUN number %jd, " - "skipping\n", (intmax_t)targ_lun_id); - } + be64enc(lun_data->luns[num_filled++].lundata, + ctl_encode_lun(targ_lun_id)); + /* * According to SPC-3, rev 14 section 6.21: * diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h index 35fc4c3..ba78ff0 100644 --- a/sys/cam/ctl/ctl.h +++ b/sys/cam/ctl/ctl.h @@ -191,6 +191,9 @@ void ctl_clr_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua); void ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx, ctl_ua_type ua_type); +uint32_t ctl_decode_lun(uint64_t encoded); +uint64_t ctl_encode_lun(uint32_t decoded); + void ctl_isc_announce_lun(struct ctl_lun *lun); void ctl_isc_announce_port(struct ctl_port *port); void ctl_isc_announce_iid(struct ctl_port *port, int iid); diff --git a/sys/cam/ctl/ctl_frontend_cam_sim.c b/sys/cam/ctl/ctl_frontend_cam_sim.c index 428cf44..9f9ea15 100644 --- a/sys/cam/ctl/ctl_frontend_cam_sim.c +++ b/sys/cam/ctl/ctl_frontend_cam_sim.c @@ -549,7 +549,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) io->io_hdr.io_type = CTL_IO_SCSI; io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; + io->io_hdr.nexus.targ_lun = ctl_decode_lun( + CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); /* * This tag scheme isn't the best, since we could in theory * have a very long-lived I/O and tag collision, especially @@ -638,7 +639,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) io->io_hdr.io_type = CTL_IO_TASK; io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; + io->io_hdr.nexus.targ_lun = ctl_decode_lun( + CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); io->taskio.task_action = CTL_TASK_ABORT_TASK; io->taskio.tag_num = abort_ccb->csio.tag_id; switch (abort_ccb->csio.tag_action) { @@ -733,7 +735,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) io->io_hdr.io_type = CTL_IO_TASK; io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; + io->io_hdr.nexus.targ_lun = ctl_decode_lun( + CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); if (ccb->ccb_h.func_code == XPT_RESET_BUS) io->taskio.task_action = CTL_TASK_BUS_RESET; else @@ -760,7 +763,7 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) cpi->version_num = 0; cpi->hba_inquiry = PI_TAG_ABLE; cpi->target_sprt = 0; - cpi->hba_misc = 0; + cpi->hba_misc = PIM_EXTLUNS; cpi->hba_eng_cnt = 0; cpi->max_target = 1; cpi->max_lun = 1024; diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 778a6ba..399e141 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/capsicum.h> #include <sys/condvar.h> +#include <sys/endian.h> #include <sys/file.h> #include <sys/kernel.h> #include <sys/kthread.h> @@ -413,62 +414,6 @@ cfiscsi_pdu_queue(struct icl_pdu *response) CFISCSI_SESSION_UNLOCK(cs); } -static uint32_t -cfiscsi_decode_lun(uint64_t encoded) -{ - uint8_t lun[8]; - uint32_t result; - - /* - * The LUN field in iSCSI PDUs may look like an ordinary 64 bit number, - * but is in fact an evil, multidimensional structure defined - * in SCSI Architecture Model 5 (SAM-5), section 4.6. - */ - memcpy(lun, &encoded, sizeof(lun)); - switch (lun[0] & 0xC0) { - case 0x00: - if ((lun[0] & 0x3f) != 0 || lun[2] != 0 || lun[3] != 0 || - lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0) { - CFISCSI_WARN("malformed LUN " - "(peripheral device addressing method): 0x%jx", - (uintmax_t)encoded); - result = 0xffffffff; - break; - } - result = lun[1]; - break; - case 0x40: - if (lun[2] != 0 || lun[3] != 0 || lun[4] != 0 || lun[5] != 0 || - lun[6] != 0 || lun[7] != 0) { - CFISCSI_WARN("malformed LUN " - "(flat address space addressing method): 0x%jx", - (uintmax_t)encoded); - result = 0xffffffff; - break; - } - result = ((lun[0] & 0x3f) << 8) + lun[1]; - break; - case 0xC0: - if (lun[0] != 0xD2 || lun[4] != 0 || lun[5] != 0 || - lun[6] != 0 || lun[7] != 0) { - CFISCSI_WARN("malformed LUN (extended flat " - "address space addressing method): 0x%jx", - (uintmax_t)encoded); - result = 0xffffffff; - break; - } - result = (lun[1] << 16) + (lun[2] << 8) + lun[3]; - break; - default: - CFISCSI_WARN("unsupported LUN format 0x%jx", - (uintmax_t)encoded); - result = 0xffffffff; - break; - } - - return (result); -} - static void cfiscsi_pdu_handle_nop_out(struct icl_pdu *request) { @@ -563,7 +508,7 @@ cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request) io->io_hdr.io_type = CTL_IO_SCSI; io->io_hdr.nexus.initid = cs->cs_ctl_initid; io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port; - io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun); + io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhssc->bhssc_lun)); io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag; switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) { case BHSSC_FLAGS_ATTR_UNTAGGED: @@ -619,7 +564,7 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request) io->io_hdr.io_type = CTL_IO_TASK; io->io_hdr.nexus.initid = cs->cs_ctl_initid; io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port; - io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun); + io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhstmr->bhstmr_lun)); io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ switch (bhstmr->bhstmr_function & ~0x80) { diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index 85a341e..2705240 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2008, 2009 Silicon Graphics International Corp. + * Copyright (c) 2014-2015 Alexander Motin <mav@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,13 +74,14 @@ __FBSDID("$FreeBSD$"); #include <cam/ctl/ctl_error.h> struct ctlfe_softc { - struct ctl_port port; - path_id_t path_id; - target_id_t target_id; - u_int maxio; + struct ctl_port port; + path_id_t path_id; + target_id_t target_id; + uint32_t hba_misc; + u_int maxio; struct cam_sim *sim; - char port_name[DEV_IDLEN]; - struct mtx lun_softc_mtx; + char port_name[DEV_IDLEN]; + struct mtx lun_softc_mtx; STAILQ_HEAD(, ctlfe_lun_softc) lun_softc_list; STAILQ_ENTRY(ctlfe_softc) links; }; @@ -355,6 +357,7 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) softc->path_id = cpi->ccb_h.path_id; softc->target_id = cpi->initiator_id; softc->sim = xpt_path_sim(path); + softc->hba_misc = cpi->hba_misc; if (cpi->maxio != 0) softc->maxio = cpi->maxio; else @@ -1166,7 +1169,12 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) io->io_hdr.io_type = CTL_IO_SCSI; io->io_hdr.nexus.initid = atio->init_id; io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; - io->io_hdr.nexus.targ_lun = atio->ccb_h.target_lun; + if (bus_softc->hba_misc & PIM_EXTLUNS) { + io->io_hdr.nexus.targ_lun = ctl_decode_lun( + CAM_EXTLUN_BYTE_SWIZZLE(atio->ccb_h.target_lun)); + } else { + io->io_hdr.nexus.targ_lun = atio->ccb_h.target_lun; + } io->scsiio.tag_num = atio->tag_id; switch (atio->tag_action) { case CAM_TAG_ACTION_NONE: @@ -1440,7 +1448,12 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) inot->ccb_h.io_ptr = io; io->io_hdr.nexus.initid = inot->initiator_id; io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; - io->io_hdr.nexus.targ_lun = inot->ccb_h.target_lun; + if (bus_softc->hba_misc & PIM_EXTLUNS) { + io->io_hdr.nexus.targ_lun = ctl_decode_lun( + CAM_EXTLUN_BYTE_SWIZZLE(inot->ccb_h.target_lun)); + } else { + io->io_hdr.nexus.targ_lun = inot->ccb_h.target_lun; + } /* XXX KDM should this be the tag_id? */ io->taskio.tag_num = inot->seq_id; @@ -1820,9 +1833,11 @@ ctlfe_lun_enable(void *arg, int lun_id) cam_status status; bus_softc = (struct ctlfe_softc *)arg; + if (bus_softc->hba_misc & PIM_EXTLUNS) + lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id)); status = xpt_create_path(&path, /*periph*/ NULL, - bus_softc->path_id, bus_softc->target_id, lun_id); + bus_softc->path_id, bus_softc->target_id, lun_id); /* XXX KDM need some way to return status to CTL here? */ if (status != CAM_REQ_CMP) { printf("%s: could not create path, status %#x\n", __func__, @@ -1879,6 +1894,8 @@ ctlfe_lun_disable(void *arg, int lun_id) struct ctlfe_lun_softc *lun_softc; softc = (struct ctlfe_softc *)arg; + if (softc->hba_misc & PIM_EXTLUNS) + lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id)); mtx_lock(&softc->lun_softc_mtx); STAILQ_FOREACH(lun_softc, &softc->lun_softc_list, links) { |