summaryrefslogtreecommitdiffstats
path: root/sys/cam/ctl/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/ctl/ctl.c')
-rw-r--r--sys/cam/ctl/ctl.c100
1 files changed, 99 insertions, 1 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 0073904..981ab72 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -409,6 +409,8 @@ static int ctl_target_reset(struct ctl_softc *ctl_softc, union ctl_io *io,
static int ctl_lun_reset(struct ctl_lun *lun, union ctl_io *io,
ctl_ua_type ua_type);
static int ctl_abort_task(union ctl_io *io);
+static int ctl_abort_task_set(union ctl_io *io);
+static int ctl_i_t_nexus_reset(union ctl_io *io);
static void ctl_run_task(union ctl_io *io);
#ifdef CTL_IO_DELAY
static void ctl_datamove_timer_wakeup(void *arg);
@@ -7484,7 +7486,8 @@ ctl_report_supported_tmf(struct ctl_scsiio *ctsio)
ctsio->kern_rel_offset = 0;
data = (struct scsi_report_supported_tmf_data *)ctsio->kern_data_ptr;
- data->byte1 |= RST_ATS | RST_LURS | RST_TRS;
+ data->byte1 |= RST_ATS | RST_ATSS | RST_LURS | RST_TRS;
+ data->byte2 |= RST_ITNRS;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
@@ -11675,6 +11678,97 @@ ctl_lun_reset(struct ctl_lun *lun, union ctl_io *io, ctl_ua_type ua_type)
}
static int
+ctl_abort_tasks_lun(struct ctl_lun *lun, uint32_t targ_port, uint32_t init_id,
+ int other_sc)
+{
+ union ctl_io *xio;
+ int found;
+
+ mtx_assert(&lun->lun_lock, MA_OWNED);
+
+ /*
+ * Run through the OOA queue and attempt to find the given I/O.
+ * The target port, initiator ID, tag type and tag number have to
+ * match the values that we got from the initiator. If we have an
+ * untagged command to abort, simply abort the first untagged command
+ * we come to. We only allow one untagged command at a time of course.
+ */
+ for (xio = (union ctl_io *)TAILQ_FIRST(&lun->ooa_queue); xio != NULL;
+ xio = (union ctl_io *)TAILQ_NEXT(&xio->io_hdr, ooa_links)) {
+
+ if ((targ_port == xio->io_hdr.nexus.targ_port) &&
+ (init_id == xio->io_hdr.nexus.initid.id)) {
+ xio->io_hdr.flags |= CTL_FLAG_ABORT;
+ found = 1;
+ if (!other_sc && !(lun->flags & CTL_LUN_PRIMARY_SC)) {
+ union ctl_ha_msg msg_info;
+
+ msg_info.hdr.nexus = xio->io_hdr.nexus;
+ msg_info.task.task_action = CTL_TASK_ABORT_TASK;
+ msg_info.task.tag_num = xio->scsiio.tag_num;
+ msg_info.task.tag_type = xio->scsiio.tag_type;
+ msg_info.hdr.msg_type = CTL_MSG_MANAGE_TASKS;
+ msg_info.hdr.original_sc = NULL;
+ msg_info.hdr.serializing_sc = NULL;
+ ctl_ha_msg_send(CTL_HA_CHAN_CTL,
+ (void *)&msg_info, sizeof(msg_info), 0);
+ }
+ }
+ }
+ return (found);
+}
+
+static int
+ctl_abort_task_set(union ctl_io *io)
+{
+ struct ctl_softc *softc = control_softc;
+ struct ctl_lun *lun;
+ uint32_t targ_lun;
+
+ /*
+ * Look up the LUN.
+ */
+ targ_lun = io->io_hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun < CTL_MAX_LUNS) && (softc->ctl_luns[targ_lun] != NULL))
+ lun = softc->ctl_luns[targ_lun];
+ else {
+ mtx_unlock(&softc->ctl_lock);
+ return (1);
+ }
+
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
+ ctl_abort_tasks_lun(lun, io->io_hdr.nexus.targ_port,
+ io->io_hdr.nexus.initid.id,
+ (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0);
+ mtx_unlock(&lun->lun_lock);
+ return (0);
+}
+
+static int
+ctl_i_t_nexus_reset(union ctl_io *io)
+{
+ struct ctl_softc *softc = control_softc;
+ struct ctl_lun *lun;
+ uint32_t initindex;
+
+ initindex = ctl_get_initindex(&io->io_hdr.nexus);
+ mtx_lock(&softc->ctl_lock);
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ mtx_lock(&lun->lun_lock);
+ ctl_abort_tasks_lun(lun, io->io_hdr.nexus.targ_port,
+ io->io_hdr.nexus.initid.id,
+ (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0);
+ ctl_clear_mask(lun->have_ca, initindex);
+ lun->pending_sense[initindex].ua_pending |= CTL_UA_I_T_NEXUS_LOSS;
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
+ return (0);
+}
+
+static int
ctl_abort_task(union ctl_io *io)
{
union ctl_io *xio;
@@ -11873,11 +11967,15 @@ ctl_run_task(union ctl_io *io)
retval = ctl_abort_task(io);
break;
case CTL_TASK_ABORT_TASK_SET:
+ retval = ctl_abort_task_set(io);
break;
case CTL_TASK_CLEAR_ACA:
break;
case CTL_TASK_CLEAR_TASK_SET:
break;
+ case CTL_TASK_I_T_NEXUS_RESET:
+ retval = ctl_i_t_nexus_reset(io);
+ break;
case CTL_TASK_LUN_RESET: {
struct ctl_lun *lun;
uint32_t targ_lun;
OpenPOWER on IntegriCloud