From owner-svn-src-stable-10@FreeBSD.ORG Tue Jul 15 18:23:15 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 1425F409; Tue, 15 Jul 2014 18:23:15 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F30E524E0; Tue, 15 Jul 2014 18:23:14 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s6FINEEx025999; Tue, 15 Jul 2014 18:23:14 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s6FINEff025998; Tue, 15 Jul 2014 18:23:14 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201407151823.s6FINEff025998@svn.freebsd.org> From: Alexander Motin Date: Tue, 15 Jul 2014 18:23:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r268705 - stable/10/sys/dev/iscsi X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Jul 2014 18:23:15 -0000 Author: mav Date: Tue Jul 15 18:23:14 2014 New Revision: 268705 URL: http://svnweb.freebsd.org/changeset/base/268705 Log: MFC r268388: Add XPT_ABORT support to iSCSI initiator. While CAM does not use it normally, it is useful for targets testing. Modified: stable/10/sys/dev/iscsi/iscsi.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/iscsi/iscsi.c ============================================================================== --- stable/10/sys/dev/iscsi/iscsi.c Tue Jul 15 18:22:17 2014 (r268704) +++ stable/10/sys/dev/iscsi/iscsi.c Tue Jul 15 18:23:14 2014 (r268705) @@ -157,6 +157,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); @@ -168,7 +169,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); @@ -279,27 +280,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); } } @@ -698,6 +707,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; @@ -818,7 +830,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); @@ -918,6 +930,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; @@ -929,7 +973,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); @@ -1042,7 +1086,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); @@ -1866,7 +1910,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) { @@ -1880,12 +1938,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 @@ -1899,11 +1957,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; @@ -1979,8 +2092,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); @@ -2086,12 +2199,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;