47#include <sys/kernel.h>
50#include <sys/condvar.h>
51#include <sys/malloc.h>
53#include <sys/endian.h>
55#include <sys/sysctl.h>
58#include <sys/taskqueue.h>
59#include <machine/bus.h>
93struct mtx ctlfe_list_mtx;
94static char ctlfe_mtx_desc[] =
"ctlfelist";
97 CTLFE_LUN_NONE = 0x00,
98 CTLFE_LUN_WILDCARD = 0x01
130#define CTLFE_MAX_SEGS 32
140#define CTLFE_REQ_CTL_IO 4096
146#define CTLFE_ATIO_PER_LUN 1024
152#define CTLFE_IN_PER_LUN 1024
157#define CTLFE_TIMEOUT 5
168#define io_ptr ppriv_ptr0
171#define ccb_atio ppriv_ptr1
173#define PRIV_CCB(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[0])
174#define PRIV_INFO(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[1])
180static void ctlfeasync(
void *callback_arg, uint32_t code,
187 union ccb *done_ccb);
202 union ccb *
ccb,
int unlock);
225 STAILQ_INIT(&ctlfe_softc_list);
226 mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF);
239 mtx_destroy(&ctlfe_list_mtx);
251 printf(
"ctl: Failed to attach async callback due to CAM "
252 "status 0x%x!\n", status);
273 printf(
"%s: entered\n", __func__);
276 mtx_lock(&ctlfe_list_mtx);
277 STAILQ_FOREACH(softc, &ctlfe_softc_list, links) {
281 mtx_unlock(&ctlfe_list_mtx);
299 printf(
"%s: SIM %s%d doesn't support target mode\n",
307 printf(
"%s: CTL port for CAM path %u already exists\n",
318 softc = malloc(
sizeof(*softc), M_CTLFE, M_NOWAIT | M_ZERO);
320 printf(
"%s: unable to malloc %zd bytes for softc\n",
321 __func__,
sizeof(*softc));
332 softc->
maxio = DFLTPHYS;
333 mtx_init(&softc->
lun_softc_mtx,
"LUN softc mtx", NULL, MTX_DEF);
334 STAILQ_INIT(&softc->lun_softc_list);
372 printf(
"%s: ctl_port_register() failed with "
373 "error %d!\n", __func__, retval);
375 free(softc, M_CTLFE);
378 mtx_lock(&ctlfe_list_mtx);
379 STAILQ_INSERT_TAIL(&ctlfe_softc_list, softc, links);
380 mtx_unlock(&ctlfe_list_mtx);
391 mtx_lock(&ctlfe_list_mtx);
392 STAILQ_REMOVE(&ctlfe_softc_list, softc,
ctlfe_softc,
394 mtx_unlock(&ctlfe_list_mtx);
397 free(softc, M_CTLFE);
413 printf(
"%s: WWPN %#jx port 0x%06x path %u target %u %s\n",
414 __func__, dev_chg->
wwpn, dev_chg->
port,
416 (dev_chg->
arrived == 0) ?
"left" :
"arrived");
419 printf(
"%s: CTL port for CAM path %u not "
420 "found!\n", __func__,
433 printf(
"%s: could not %s port %d iid %u "
434 "WWPN %#jx!\n", __func__,
435 (dev_chg->
arrived != 0) ?
"add" :
438 (uintmax_t)dev_chg->
wwpn);
443 printf(
"%s: unsupported contract number %ju\n",
466 STAILQ_INIT(&softc->work_queue);
467 LIST_INIT(&softc->atio_list);
468 LIST_INIT(&softc->inot_list);
482 memset(&
ccb, 0,
sizeof(
ccb));
503 new_ccb = (
union ccb *)malloc(
sizeof(*new_ccb), M_CTLFE,
505 if (new_ccb == NULL) {
510 if (new_io == NULL) {
511 free(new_ccb, M_CTLFE);
515 cmd_info = malloc(
sizeof(*cmd_info), M_CTLFE,
517 if (cmd_info == NULL) {
519 free(new_ccb, M_CTLFE);
525 new_ccb->
ccb_h.io_ptr = new_io;
526 LIST_INSERT_HEAD(&softc->atio_list, &new_ccb->
ccb_h, periph_links.le);
535 free(cmd_info, M_CTLFE);
537 free(new_ccb, M_CTLFE);
545 "count, status = %#x\n", __func__, acstatus);
551 "status 0x%x\n", __func__, status);
559 new_ccb = (
union ccb *)malloc(
sizeof(*new_ccb), M_CTLFE,
561 if (new_ccb == NULL) {
566 if (new_io == NULL) {
567 free(new_ccb, M_CTLFE);
572 new_ccb->
ccb_h.io_ptr = new_io;
573 LIST_INSERT_HEAD(&softc->inot_list, &new_ccb->
ccb_h, periph_links.le);
598 "notify CCBs, status 0x%x\n", __func__, status);
602 STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, softc, links);
617 memset(&
ccb, 0,
sizeof(
ccb));
620 LIST_FOREACH(hdr, &softc->atio_list, periph_links.le) {
624 LIST_FOREACH(hdr, &softc->inot_list, periph_links.le) {
637 xpt_print(periph->
path,
"%s: Disable LUN failed, status 0x%x\n",
645 mtx_lock(&bus_softc->lun_softc_mtx);
646 STAILQ_REMOVE(&bus_softc->lun_softc_list, softc,
ctlfe_lun_softc, links);
647 mtx_unlock(&bus_softc->lun_softc_mtx);
657 KASSERT(softc->
ctios_sent == 0, (
"%s: ctios_sent %d != 0",
659 KASSERT(softc->
refcount == 0, (
"%s: refcount %d != 0",
661 KASSERT(softc->
atios_alloced == 0, (
"%s: atios_alloced %d != 0",
663 KASSERT(softc->
inots_alloced == 0, (
"%s: inots_alloced %d != 0",
666 free(softc, M_CTLFE);
672 u_int16_t *sglist_cnt)
677 bus_dma_segment_t *cam_sglist;
687 *flags &= ~CAM_DIR_MASK;
693 *flags &= ~CAM_DATA_MASK;
696 cmd_info->
flags &= ~CTLFE_CMD_PIECEWISE;
707 *dxfer_len = bus_softc->
maxio;
732 cam_sglist[i].ds_addr = (bus_addr_t)(uintptr_t)ctl_sglist[i + idx].
addr + off;
733 if (ctl_sglist[i + idx].
len - off <= bus_softc->maxio - *dxfer_len) {
734 cam_sglist[i].ds_len = ctl_sglist[idx + i].
len - off;
735 *dxfer_len += cam_sglist[i].ds_len;
737 cam_sglist[i].ds_len = bus_softc->
maxio - *dxfer_len;
741 *dxfer_len += cam_sglist[i].ds_len;
742 if (ctl_sglist[i].
len != 0)
761 *data_ptr = (uint8_t *)cam_sglist;
783 ccb_h = STAILQ_FIRST(&softc->work_queue);
788 STAILQ_REMOVE_HEAD(&softc->work_queue, periph_links.stqe);
790 io = (
union ctl_io *)ccb_h->io_ptr;
791 csio = &start_ccb->
csio;
804 ctlfedata(softc, io, &flags, &data_ptr, &dxfer_len,
816 printf(
"%s: tag %04x abort\n", __func__, atio->
tag_id);
843 printf(
"%s: tag %04x status %x\n", __func__,
853 printf(
"%s: %s: tag %04x flags %x ptr %p len %u\n", __func__,
878 printf(
"%s: tag %04x cdb %02x flags %#x dxfer_len "
882 printf(
"%s: tag %04x io status %#x\n", __func__,
913 if (!STAILQ_EMPTY(&softc->work_queue))
946 free(cmd_info, M_CTLFE);
959 KASSERT(softc->
atios_alloced >= 0, (
"%s: atios_alloced %d < 0",
961 KASSERT(softc->
inots_alloced >= 0, (
"%s: inots_alloced %d < 0",
974 taskqueue_enqueue(taskqueue_thread,
998 LIST_INSERT_HEAD(&softc->atio_list, &
ccb->
ccb_h, periph_links.le);
1000 LIST_INSERT_HEAD(&softc->inot_list, &
ccb->
ccb_h, periph_links.le);
1019 uint32_t num_blocks, nbc;
1024 switch (cmdbyt[0]) {
1031 num_blocks = cdb->
length;
1032 if (num_blocks == 0)
1037 cdb->
length = num_blocks;
1094 (
"CCB in ctlfedone() without CAM_UNLOCKED flag"));
1096 printf(
"%s: entered, func_code = %#x\n", __func__,
1120 LIST_REMOVE(&done_ccb->
ccb_h, periph_links.le);
1121 atio = &done_ccb->
atio;
1134 io = done_ccb->
ccb_h.io_ptr;
1141 done_ccb->
ccb_h.io_ptr = io;
1176 printf(
"%s: unhandled tag type %#x!!\n", __func__,
1181 printf(
"%s: WARNING: CDB len %d > ctl_io space %zd\n",
1188 printf(
"%s: %u:%u:%u: tag %04x CDB %02x\n", __func__,
1200 uint32_t srr_off = 0;
1207 printf(
"%s: got XPT_CONT_TARGET_IO tag %#x flags %#x\n",
1242 STAILQ_INSERT_HEAD(&softc->work_queue, &atio->
ccb_h,
1305 csio = &done_ccb->
csio;
1362 printf(
"%s: tag %04x no status or "
1363 "len cdb = %02x\n", __func__,
1366 printf(
"%s: tag %04x io status %#x\n",
1386 csio->
ccb_h.ccb_atio = atio;
1410 LIST_REMOVE(&done_ccb->
ccb_h, periph_links.le);
1411 inot = &done_ccb->
cin1;
1412 io = done_ccb->
ccb_h.io_ptr;
1419 inot->
ccb_h.io_ptr = io;
1440 switch (inot->
arg) {
1477 "%s: unsupported INOT message 0x%x\n",
1478 __func__, inot->
arg);
1485 "%s: unsupported INOT status 0x%x\n",
1496 if (send_ctl_io != 0) {
1516 panic(
"%s: unexpected CCB type %#x", __func__,
1537 printf(
"%s: unable to create path!\n", __func__);
1548 printf(
"%s: %s current WWNN %#jx\n", __func__,
1551 printf(
"%s: %s current WWPN %#jx\n", __func__,
1581 printf(
"%s: %s has no valid WWNN/WWPN\n", __func__,
1600 printf(
"%s: %s (path id %d) failed set WWNs: %#x\n",
1604 printf(
"%s: %s new WWNN %#jx\n", __func__,
1607 printf(
"%s: %s new WWPN %#jx\n", __func__,
1625 printf(
"%s: %s (path id %d) failed %s target role: %#x\n",
1629 printf(
"%s: %s (path id %d) target role %s succeeded\n",
1631 online ?
"enable" :
"disable");
1657 printf(
"%s: unable to create path for wildcard periph\n",
1662 lun_softc = malloc(
sizeof(*lun_softc), M_CTLFE, M_WAITOK | M_ZERO);
1666 if (periph != NULL) {
1670 free(lun_softc, M_CTLFE);
1674 lun_softc->
flags |= CTLFE_LUN_WILDCARD;
1691 printf(
"%s: CAM error %s (%#x) returned from "
1692 "cam_periph_alloc()\n", __func__, (entry != NULL) ?
1694 free(lun_softc, M_CTLFE);
1722 printf(
"%s: unable to create path for wildcard periph\n",
1754 printf(
"%s: could not create path, status %#x\n", __func__,
1759 softc = malloc(
sizeof(*softc), M_CTLFE, M_WAITOK | M_ZERO);
1762 if (periph != NULL) {
1766 free(softc, M_CTLFE);
1786 printf(
"%s: CAM error %s (%#x) returned from "
1787 "cam_periph_alloc()\n", __func__, (entry != NULL) ?
1789 free(softc, M_CTLFE);
1812 STAILQ_FOREACH(lun_softc, &softc->lun_softc_list, links) {
1822 if (lun_softc == NULL) {
1824 printf(
"%s: can't find lun %d\n", __func__, lun_id);
1841 printf(
"%s%d: max dev openings: %d, max tagged dev openings: %d\n",
1857 memset(&cgds, 0,
sizeof(cgds));
1863 "allocated %d, queued %d, held %d\n",
1870 STAILQ_FOREACH(hdr, &softc->work_queue, periph_links.stqe) {
1871 union ctl_io *io = hdr->io_ptr;
1891 "Total %u, Current %u, Resid %u\n",
1898 xpt_print(periph->
path,
"%d requests waiting for CCBs\n", num_items);
1915 (
"%s: unexpected I/O type %x", __func__, io->
io_hdr.
io_type));
1925 STAILQ_INSERT_TAIL(&softc->work_queue, &
ccb->
ccb_h,
1978 STAILQ_INSERT_TAIL(&softc->work_queue, &
ccb->
ccb_h,
1992 STAILQ_FOREACH(bus_softc, &ctlfe_softc_list, links) {
1994 STAILQ_FOREACH(lun_softc, &bus_softc->lun_softc_list, links)
const struct cam_status_entry * cam_fetch_status_entry(cam_status status)
#define CAM_TARGET_WILDCARD
#define CAM_EXTLUN_BYTE_SWIZZLE(lun)
#define CAM_PRIORITY_NORMAL
#define CAM_PRIORITY_NONE
#define RELSIM_ADJUST_OPENINGS
#define CAM_RSP_TMF_FAILED
#define CAM_RSP_TMF_SUCCEEDED
#define AC_CONTRACT_DEV_CHG
#define CAM_RSP_TMF_INCORRECT_LUN
#define CAM_RSP_TMF_REJECTED
static __inline void cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries, void(*cbfcnp)(struct cam_periph *, union ccb *), u_int32_t flags, u_int tag_action, u_int tag_id, u_int init_id, u_int scsi_status, u_int8_t *data_ptr, u_int32_t dxfer_len, u_int32_t timeout)
#define CAM_TAG_ACTION_NONE
#define CAM_RSP_TMF_COMPLETE
static __inline uint8_t * atio_cdb_ptr(struct ccb_accept_tio *ccb)
#define KNOB_VALID_ADDRESS
void cam_periph_release_locked(struct cam_periph *periph)
int periphdriver_unregister(void *data)
struct cam_periph * cam_periph_find(struct cam_path *path, char *name)
u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t openings, u_int32_t arg, int getcount_only)
void periphdriver_register(void *data)
int cam_periph_acquire(struct cam_periph *periph)
void cam_periph_release(struct cam_periph *periph)
void cam_periph_invalidate(struct cam_periph *periph)
cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, periph_oninv_t *periph_oninvalidate, periph_dtor_t *periph_dtor, periph_start_t *periph_start, char *name, cam_periph_type type, struct cam_path *path, ac_callback_t *ac_callback, ac_code code, void *arg)
cam_status periph_ctor_t(struct cam_periph *periph, void *arg)
#define CAM_PERIPH_INVALID
void periph_oninv_t(struct cam_periph *periph)
#define cam_periph_lock(periph)
#define CAM_PERIPH_DRV_EARLY
#define cam_periph_unlock(periph)
int() periph_deinit_t(void)
static __inline struct mtx * cam_periph_mtx(struct cam_periph *periph)
void periph_dtor_t(struct cam_periph *periph)
void periph_start_t(struct cam_periph *periph, union ccb *start_ccb)
#define cam_periph_sleep(periph, chan, priority, wmesg, timo)
void() periph_init_t(void)
LIST_HEAD(ccb_hdr_list, ccb_hdr)
union ccb * xpt_alloc_ccb(void)
void xpt_schedule(struct cam_periph *periph, u_int32_t new_priority)
cam_status xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id)
void xpt_setup_ccb_flags(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority, u_int32_t flags)
void xpt_print(struct cam_path *path, const char *fmt,...)
path_id_t xpt_path_path_id(struct cam_path *path)
void xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority)
void xpt_action(union ccb *start_ccb)
cam_status xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, struct cam_path *path)
lun_id_t xpt_path_lun_id(struct cam_path *path)
struct cam_sim * xpt_path_sim(struct cam_path *path)
void xpt_free_path(struct cam_path *path)
struct cam_periph * xpt_path_periph(struct cam_path *path)
void xpt_release_ccb(union ccb *free_ccb)
target_id_t xpt_path_target_id(struct cam_path *path)
void xpt_free_ccb(union ccb *free_ccb)
#define xpt_path_unlock(path)
#define xpt_path_lock(path)
uint32_t ctl_decode_lun(uint64_t encoded)
void ctl_free_io(union ctl_io *io)
union ctl_io * ctl_alloc_io_nowait(void *pool_ref)
int ctl_remove_initiator(struct ctl_port *port, int iid)
int ctl_add_initiator(struct ctl_port *port, int iid, uint64_t wwpn, char *name)
void ctl_datamove_done(union ctl_io *io, bool samethr)
int ctl_queue_sense(union ctl_io *io)
int ctl_queue(union ctl_io *io)
uint64_t ctl_encode_lun(uint32_t decoded)
void ctl_zero_io(union ctl_io *io)
void ctl_set_data_phase_error(struct ctl_scsiio *ctsio)
int ctl_port_deregister(struct ctl_port *port)
void ctl_port_set_wwns(struct ctl_port *port, int wwnn_valid, uint64_t wwnn, int wwpn_valid, uint64_t wwpn)
int ctl_port_register(struct ctl_port *port)
@ CTL_TASK_QUERY_ASYNC_EVENT
@ CTL_TASK_QUERY_TASK_SET
@ CTL_TASK_CLEAR_TASK_SET
@ CTL_TASK_ABORT_TASK_SET
@ CTL_TASK_LUN_DOES_NOT_EXIST
@ CTL_TASK_FUNCTION_REJECTED
@ CTL_TASK_FUNCTION_SUCCEEDED
@ CTL_TASK_FUNCTION_NOT_SUPPORTED
@ CTL_TASK_FUNCTION_COMPLETE
void ctl_io_error_print(union ctl_io *io, struct scsi_inquiry_data *inq_data)
static __inline uint32_t scsi_3btoul(const uint8_t *bytes)
static __inline uint64_t scsi_8btou64(const uint8_t *bytes)
static __inline uint32_t scsi_2btoul(const uint8_t *bytes)
static __inline void scsi_ulto2b(u_int32_t val, u_int8_t *bytes)
static __inline uint32_t scsi_4btoul(const uint8_t *bytes)
static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes)
static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes)
static __inline void scsi_ulto3b(u_int32_t val, u_int8_t *bytes)
static int ctlfeinitialize(void)
static void ctlfe_offline(void *arg)
CTL_FRONTEND_DECLARE(ctlfe, ctlfe_frontend)
static void ctlfe_done(union ctl_io *io)
static struct ctl_frontend ctlfe_frontend
static void ctlfe_datamove(union ctl_io *io)
static void ctlfe_free_ccb(struct cam_periph *periph, union ccb *ccb)
MALLOC_DEFINE(M_CTLFE, "CAM CTL FE", "CAM CTL FE interface")
static void ctlfe_onoffline(void *arg, int online)
static periph_deinit_t ctlfeperiphdeinit
static void ctlfe_online(void *arg)
static periph_oninv_t ctlfeoninvalidate
static void ctlfedata(struct ctlfe_lun_softc *softc, union ctl_io *io, ccb_flags *flags, uint8_t **data_ptr, uint32_t *dxfer_len, u_int16_t *sglist_cnt)
static int ctlfe_lun_enable(void *arg, int lun_id)
static periph_start_t ctlfestart
static void ctlfe_drain(void *context, int pending)
static void ctlfedone(struct cam_periph *periph, union ccb *done_ccb)
static periph_ctor_t ctlferegister
static void ctlfe_requeue_ccb(struct cam_periph *periph, union ccb *ccb, int unlock)
static periph_init_t ctlfeperiphinit
static struct periph_driver ctlfe_driver
static void ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
static void ctlfe_dump_sim(struct cam_sim *sim)
static periph_dtor_t ctlfecleanup
static void ctlfe_dump(void)
static int ctlfe_lun_disable(void *arg, int lun_id)
static int ctlfe_adjust_cdb(struct ccb_accept_tio *atio, uint32_t offset)
static int ctlfeshutdown(void)
#define CTLFE_ATIO_PER_LUN
static void ctlfe_dump_queue(struct ctlfe_lun_softc *softc)
#define MSG_HEAD_OF_QUEUE_TASK
#define MSG_ABORT_TASK_SET
#define MSG_QUERY_TASK_SET
#define MSG_QUERY_ASYNC_EVENT
#define MSG_CLEAR_TASK_SET
#define MSG_LOGICAL_UNIT_RESET
u_int64_t contract_number
u_int8_t contract_data[AC_CONTRACT_DATA_MAX]
int max_tagged_dev_openings
void(* cbfcnp)(struct cam_periph *, union ccb *)
struct scsi_sense_data sense_data
union ccb_sim_knob::@5 xport_specific
struct ccb_sim_knob_settings_fc fc
char name[CTL_DRIVER_NAME_LEN]
struct ctl_frontend * frontend
void(* fe_datamove)(union ctl_io *io)
void(* fe_done)(union ctl_io *io)
struct scsi_sense_data sense_data
uint8_t cdb[CTL_MAX_CDBLEN]
ctl_task_type task_action
bus_dma_segment_t cam_sglist[CTLFE_MAX_SEGS]
struct ctlfe_softc * parent_softc
struct cam_periph * periph
struct task refdrain_task
char port_name[DEV_IDLEN]
struct ccb_notify_acknowledge cna2
struct ccb_immediate_notify cin1
struct ccb_accept_tio atio