Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Jul 2014 09:37:41 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r268388 - head/sys/dev/iscsi
Message-ID:  <201407080937.s689bfSY058865@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Tue Jul  8 09:37:41 2014
New Revision: 268388
URL: http://svnweb.freebsd.org/changeset/base/268388

Log:
  Add XPT_ABORT support to iSCSI initiator.
  
  While CAM does not use it normally, it is useful for targets testing.
  
  MFC after:	2 weeks

Modified:
  head/sys/dev/iscsi/iscsi.c

Modified: head/sys/dev/iscsi/iscsi.c
==============================================================================
--- head/sys/dev/iscsi/iscsi.c	Tue Jul  8 08:34:34 2014	(r268387)
+++ head/sys/dev/iscsi/iscsi.c	Tue Jul  8 09:37:41 2014	(r268388)
@@ -152,6 +152,7 @@ static void	iscsi_pdu_queue(struct icl_p
 static void	iscsi_pdu_update_statsn(const struct icl_pdu *response);
 static void	iscsi_pdu_handle_nop_in(struct icl_pdu *response);
 static void	iscsi_pdu_handle_scsi_response(struct icl_pdu *response);
+static void	iscsi_pdu_handle_task_response(struct icl_pdu *response);
 static void	iscsi_pdu_handle_data_in(struct icl_pdu *response);
 static void	iscsi_pdu_handle_logout_response(struct icl_pdu *response);
 static void	iscsi_pdu_handle_r2t(struct icl_pdu *response);
@@ -163,7 +164,7 @@ static void	iscsi_action(struct cam_sim 
 static void	iscsi_poll(struct cam_sim *sim);
 static struct iscsi_outstanding	*iscsi_outstanding_find(struct iscsi_session *is,
 		    uint32_t initiator_task_tag);
-static int	iscsi_outstanding_add(struct iscsi_session *is,
+static struct iscsi_outstanding	*iscsi_outstanding_add(struct iscsi_session *is,
 		    uint32_t initiator_task_tag, union ccb *ccb);
 static void	iscsi_outstanding_remove(struct iscsi_session *is,
 		    struct iscsi_outstanding *io);
@@ -274,27 +275,35 @@ iscsi_session_logout(struct iscsi_sessio
 }
 
 static void
-iscsi_session_terminate_tasks(struct iscsi_session *is, bool requeue)
+iscsi_session_terminate_task(struct iscsi_session *is,
+    struct iscsi_outstanding *io, bool requeue)
 {
-	struct iscsi_outstanding *io, *tmp;
 
-	ISCSI_SESSION_LOCK_ASSERT(is);
-	
-	TAILQ_FOREACH_SAFE(io, &is->is_outstanding, io_next, tmp) {
-		if (requeue) {
-			io->io_ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+	if (io->io_ccb != NULL) {
+		io->io_ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK);
+		if (requeue)
 			io->io_ccb->ccb_h.status |= CAM_REQUEUE_REQ;
-		} else {
-			io->io_ccb->ccb_h.status = CAM_REQ_ABORTED;
-		}
-
+		else
+			io->io_ccb->ccb_h.status |= CAM_REQ_ABORTED;
 		if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
+			io->io_ccb->ccb_h.status |= CAM_DEV_QFRZN;
 			xpt_freeze_devq(io->io_ccb->ccb_h.path, 1);
 			ISCSI_SESSION_DEBUG(is, "freezing devq");
 		}
-		io->io_ccb->ccb_h.status |= CAM_DEV_QFRZN;
 		xpt_done(io->io_ccb);
-		iscsi_outstanding_remove(is, io);
+	}
+	iscsi_outstanding_remove(is, io);
+}
+
+static void
+iscsi_session_terminate_tasks(struct iscsi_session *is, bool requeue)
+{
+	struct iscsi_outstanding *io, *tmp;
+
+	ISCSI_SESSION_LOCK_ASSERT(is);
+
+	TAILQ_FOREACH_SAFE(io, &is->is_outstanding, io_next, tmp) {
+		iscsi_session_terminate_task(is, io, requeue);
 	}
 }
 
@@ -693,6 +702,9 @@ iscsi_receive_callback(struct icl_pdu *r
 	case ISCSI_BHS_OPCODE_SCSI_RESPONSE:
 		iscsi_pdu_handle_scsi_response(response);
 		break;
+	case ISCSI_BHS_OPCODE_TASK_RESPONSE:
+		iscsi_pdu_handle_task_response(response);
+		break;
 	case ISCSI_BHS_OPCODE_SCSI_DATA_IN:
 		iscsi_pdu_handle_data_in(response);
 		break;
@@ -813,7 +825,7 @@ iscsi_pdu_handle_scsi_response(struct ic
 
 	bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
 	io = iscsi_outstanding_find(is, bhssr->bhssr_initiator_task_tag);
-	if (io == NULL) {
+	if (io == NULL || io->io_ccb == NULL) {
 		ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhssr->bhssr_initiator_task_tag);
 		icl_pdu_free(response);
 		iscsi_session_reconnect(is);
@@ -913,6 +925,38 @@ out:
 }
 
 static void
+iscsi_pdu_handle_task_response(struct icl_pdu *response)
+{
+	struct iscsi_bhs_task_management_response *bhstmr;
+	struct iscsi_outstanding *io, *aio;
+	struct iscsi_session *is;
+
+	is = PDU_SESSION(response);
+
+	bhstmr = (struct iscsi_bhs_task_management_response *)response->ip_bhs;
+	io = iscsi_outstanding_find(is, bhstmr->bhstmr_initiator_task_tag);
+	if (io == NULL || io->io_ccb != NULL) {
+		ISCSI_SESSION_WARN(is, "bad itt 0x%x",
+		    bhstmr->bhstmr_initiator_task_tag);
+		icl_pdu_free(response);
+		iscsi_session_reconnect(is);
+		return;
+	}
+
+	if (bhstmr->bhstmr_response != BHSTMR_RESPONSE_FUNCTION_COMPLETE) {
+		ISCSI_SESSION_WARN(is, "task response 0x%x",
+		    bhstmr->bhstmr_response);
+	} else {
+		aio = iscsi_outstanding_find(is, io->io_datasn);
+		if (aio != NULL && aio->io_ccb != NULL)
+			iscsi_session_terminate_task(is, aio, false);
+	}
+
+	iscsi_outstanding_remove(is, io);
+	icl_pdu_free(response);
+}
+
+static void
 iscsi_pdu_handle_data_in(struct icl_pdu *response)
 {
 	struct iscsi_bhs_data_in *bhsdi;
@@ -924,7 +968,7 @@ iscsi_pdu_handle_data_in(struct icl_pdu 
 	is = PDU_SESSION(response);
 	bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
 	io = iscsi_outstanding_find(is, bhsdi->bhsdi_initiator_task_tag);
-	if (io == NULL) {
+	if (io == NULL || io->io_ccb == NULL) {
 		ISCSI_SESSION_WARN(is, "bad itt 0x%x", bhsdi->bhsdi_initiator_task_tag);
 		icl_pdu_free(response);
 		iscsi_session_reconnect(is);
@@ -1037,7 +1081,7 @@ iscsi_pdu_handle_r2t(struct icl_pdu *res
 
 	bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
 	io = iscsi_outstanding_find(is, bhsr2t->bhsr2t_initiator_task_tag);
-	if (io == NULL) {
+	if (io == NULL || io->io_ccb == NULL) {
 		ISCSI_SESSION_WARN(is, "bad itt 0x%x; reconnecting",
 		    bhsr2t->bhsr2t_initiator_task_tag);
 		icl_pdu_free(response);
@@ -1878,7 +1922,21 @@ iscsi_outstanding_find(struct iscsi_sess
 	return (NULL);
 }
 
-static int
+static struct iscsi_outstanding *
+iscsi_outstanding_find_ccb(struct iscsi_session *is, union ccb *ccb)
+{
+	struct iscsi_outstanding *io;
+
+	ISCSI_SESSION_LOCK_ASSERT(is);
+
+	TAILQ_FOREACH(io, &is->is_outstanding, io_next) {
+		if (io->io_ccb == ccb)
+			return (io);
+	}
+	return (NULL);
+}
+
+static struct iscsi_outstanding *
 iscsi_outstanding_add(struct iscsi_session *is,
     uint32_t initiator_task_tag, union ccb *ccb)
 {
@@ -1892,12 +1950,12 @@ iscsi_outstanding_add(struct iscsi_sessi
 	io = uma_zalloc(iscsi_outstanding_zone, M_NOWAIT | M_ZERO);
 	if (io == NULL) {
 		ISCSI_SESSION_WARN(is, "failed to allocate %zd bytes", sizeof(*io));
-		return (ENOMEM);
+		return (NULL);
 	}
 	io->io_initiator_task_tag = initiator_task_tag;
 	io->io_ccb = ccb;
 	TAILQ_INSERT_TAIL(&is->is_outstanding, io, io_next);
-	return (0);
+	return (io);
 }
 
 static void
@@ -1911,11 +1969,66 @@ iscsi_outstanding_remove(struct iscsi_se
 }
 
 static void
+iscsi_action_abort(struct iscsi_session *is, union ccb *ccb)
+{
+	struct icl_pdu *request;
+	struct iscsi_bhs_task_management_request *bhstmr;
+	struct ccb_abort *cab = &ccb->cab;
+	struct iscsi_outstanding *io, *aio;
+
+	ISCSI_SESSION_LOCK_ASSERT(is);
+
+#if 0
+	KASSERT(is->is_login_phase == false, ("%s called during Login Phase", __func__));
+#else
+	if (is->is_login_phase) {
+		ccb->ccb_h.status = CAM_REQ_ABORTED;
+		xpt_done(ccb);
+		return;
+	}
+#endif
+
+	aio = iscsi_outstanding_find_ccb(is, cab->abort_ccb);
+	if (aio == NULL) {
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		xpt_done(ccb);
+		return;
+	}
+
+	request = icl_pdu_new_bhs(is->is_conn, M_NOWAIT);
+	if (request == NULL) {
+		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+		xpt_done(ccb);
+		return;
+	}
+
+	bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
+	bhstmr->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_REQUEST;
+	bhstmr->bhstmr_function = 0x80 | BHSTMR_FUNCTION_ABORT_TASK;
+
+	bhstmr->bhstmr_lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
+	bhstmr->bhstmr_initiator_task_tag = is->is_initiator_task_tag;
+	is->is_initiator_task_tag++;
+	bhstmr->bhstmr_referenced_task_tag = aio->io_initiator_task_tag;
+
+	io = iscsi_outstanding_add(is, bhstmr->bhstmr_initiator_task_tag, NULL);
+	if (io == NULL) {
+		icl_pdu_free(request);
+		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+		xpt_done(ccb);
+		return;
+	}
+	io->io_datasn = aio->io_initiator_task_tag;
+	iscsi_pdu_queue_locked(request);
+}
+
+static void
 iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
 {
 	struct icl_pdu *request;
 	struct iscsi_bhs_scsi_command *bhssc;
 	struct ccb_scsiio *csio;
+	struct iscsi_outstanding *io;
 	size_t len;
 	int error;
 
@@ -1991,8 +2104,8 @@ iscsi_action_scsiio(struct iscsi_session
 	else
 		memcpy(&bhssc->bhssc_cdb, csio->cdb_io.cdb_bytes, csio->cdb_len);
 
-	error = iscsi_outstanding_add(is, bhssc->bhssc_initiator_task_tag, ccb);
-	if (error != 0) {
+	io = iscsi_outstanding_add(is, bhssc->bhssc_initiator_task_tag, ccb);
+	if (io == NULL) {
 		icl_pdu_free(request);
 		if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
 			xpt_freeze_devq(ccb->ccb_h.path, 1);
@@ -2096,12 +2209,14 @@ iscsi_action(struct cam_sim *sim, union 
 	 * XXX: What's the point?
 	 */
 	case XPT_RESET_BUS:
-	case XPT_ABORT:
 	case XPT_TERM_IO:
 		ISCSI_SESSION_DEBUG(is, "faking success for reset, abort, or term_io");
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
 #endif
+	case XPT_ABORT:
+		iscsi_action_abort(is, ccb);
+		return;
 	case XPT_SCSI_IO:
 		iscsi_action_scsiio(is, ccb);
 		return;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407080937.s689bfSY058865>