11bdd6c0eSSue Gleeson /*
21bdd6c0eSSue Gleeson  * CDDL HEADER START
31bdd6c0eSSue Gleeson  *
41bdd6c0eSSue Gleeson  * The contents of this file are subject to the terms of the
51bdd6c0eSSue Gleeson  * Common Development and Distribution License (the "License").
61bdd6c0eSSue Gleeson  * You may not use this file except in compliance with the License.
71bdd6c0eSSue Gleeson  *
81bdd6c0eSSue Gleeson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91bdd6c0eSSue Gleeson  * or http://www.opensolaris.org/os/licensing.
101bdd6c0eSSue Gleeson  * See the License for the specific language governing permissions
111bdd6c0eSSue Gleeson  * and limitations under the License.
121bdd6c0eSSue Gleeson  *
131bdd6c0eSSue Gleeson  * When distributing Covered Code, include this CDDL HEADER in each
141bdd6c0eSSue Gleeson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151bdd6c0eSSue Gleeson  * If applicable, add the following below this CDDL HEADER, with the
161bdd6c0eSSue Gleeson  * fields enclosed by brackets "[]" replaced with your own identifying
171bdd6c0eSSue Gleeson  * information: Portions Copyright [yyyy] [name of copyright owner]
181bdd6c0eSSue Gleeson  *
191bdd6c0eSSue Gleeson  * CDDL HEADER END
201bdd6c0eSSue Gleeson  */
211bdd6c0eSSue Gleeson 
221bdd6c0eSSue Gleeson /*
23c3a558e7SSue Gleeson  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
241bdd6c0eSSue Gleeson  */
251bdd6c0eSSue Gleeson 
261bdd6c0eSSue Gleeson /*
271bdd6c0eSSue Gleeson  * SCSI Target Port I/F for Solaris SCSI RDMA Protocol Target (SRP)
281bdd6c0eSSue Gleeson  * port provider module for the COMSTAR framework.
291bdd6c0eSSue Gleeson  */
301bdd6c0eSSue Gleeson 
311bdd6c0eSSue Gleeson #include <sys/cpuvar.h>
321bdd6c0eSSue Gleeson #include <sys/types.h>
331bdd6c0eSSue Gleeson #include <sys/conf.h>
341bdd6c0eSSue Gleeson #include <sys/stat.h>
351bdd6c0eSSue Gleeson #include <sys/file.h>
361bdd6c0eSSue Gleeson #include <sys/ddi.h>
371bdd6c0eSSue Gleeson #include <sys/sunddi.h>
381bdd6c0eSSue Gleeson #include <sys/modctl.h>
391bdd6c0eSSue Gleeson #include <sys/sysmacros.h>
401bdd6c0eSSue Gleeson #include <sys/sdt.h>
411bdd6c0eSSue Gleeson #include <sys/taskq.h>
421bdd6c0eSSue Gleeson #include <sys/atomic.h>
431bdd6c0eSSue Gleeson 
444558d122SViswanathan Kannappan #include <sys/stmf.h>
454558d122SViswanathan Kannappan #include <sys/stmf_ioctl.h>
464558d122SViswanathan Kannappan #include <sys/portif.h>
471bdd6c0eSSue Gleeson 
48*716c1805SNattuvetty Bhavyan #include <sys/scsi/generic/persist.h>
491bdd6c0eSSue Gleeson #include <sys/ib/mgt/ibdma/ibdma.h>
501bdd6c0eSSue Gleeson 
511bdd6c0eSSue Gleeson #include "srp.h"
521bdd6c0eSSue Gleeson #include "srpt_impl.h"
531bdd6c0eSSue Gleeson #include "srpt_cm.h"
541bdd6c0eSSue Gleeson #include "srpt_ioc.h"
551bdd6c0eSSue Gleeson #include "srpt_ch.h"
561bdd6c0eSSue Gleeson #include "srpt_stp.h"
571bdd6c0eSSue Gleeson 
581bdd6c0eSSue Gleeson extern srpt_ctxt_t	*srpt_ctxt;
59989ca640SSue Gleeson extern uint32_t		srpt_iu_size;
601bdd6c0eSSue Gleeson 
611bdd6c0eSSue Gleeson /*
621bdd6c0eSSue Gleeson  * STMF LPort Interface Prototypes
631bdd6c0eSSue Gleeson  */
641bdd6c0eSSue Gleeson static stmf_status_t srpt_stp_xfer_data(struct scsi_task *task,
651bdd6c0eSSue Gleeson 	struct stmf_data_buf *dbuf, uint32_t ioflags);
661bdd6c0eSSue Gleeson stmf_status_t srpt_stp_send_status(struct scsi_task *task,
671bdd6c0eSSue Gleeson 	uint32_t ioflags);
681bdd6c0eSSue Gleeson static void srpt_stp_task_free(struct scsi_task *task);
691bdd6c0eSSue Gleeson static stmf_status_t srpt_stp_abort(struct stmf_local_port *lport,
701bdd6c0eSSue Gleeson 	int abort_cmd, void *arg, uint32_t flags);
711bdd6c0eSSue Gleeson static void srpt_stp_task_poll(struct scsi_task *task);
721bdd6c0eSSue Gleeson static void srpt_stp_ctl(struct stmf_local_port *lport,
731bdd6c0eSSue Gleeson 	int cmd, void *arg);
741bdd6c0eSSue Gleeson static stmf_status_t srpt_stp_info(uint32_t cmd,
751bdd6c0eSSue Gleeson 	struct stmf_local_port *lport, void *arg, uint8_t *buf,
761bdd6c0eSSue Gleeson 	uint32_t *bufsizep);
771bdd6c0eSSue Gleeson static void srpt_stp_event_handler(struct stmf_local_port *lport,
781bdd6c0eSSue Gleeson 	int eventid, void *arg, uint32_t flags);
791bdd6c0eSSue Gleeson 
801bdd6c0eSSue Gleeson static void srpt_format_login_rsp(srp_login_req_t *req,
811bdd6c0eSSue Gleeson 	srp_login_rsp_t *rsp, uint8_t flags);
821bdd6c0eSSue Gleeson static void srpt_format_login_rej(srp_login_req_t *req,
831bdd6c0eSSue Gleeson 	srp_login_rej_t *rej, uint32_t reason);
841bdd6c0eSSue Gleeson 
851bdd6c0eSSue Gleeson static scsi_devid_desc_t *srpt_stp_alloc_scsi_devid_desc(uint64_t guid);
861bdd6c0eSSue Gleeson static void srpt_stp_free_scsi_devid_desc(scsi_devid_desc_t *sdd);
871bdd6c0eSSue Gleeson 
881bdd6c0eSSue Gleeson extern uint16_t srpt_send_msg_depth;
891bdd6c0eSSue Gleeson 
901bdd6c0eSSue Gleeson /*
911bdd6c0eSSue Gleeson  * srpt_stp_start_srp() - Start SRP service
921bdd6c0eSSue Gleeson  *
931bdd6c0eSSue Gleeson  * Enable the SRP service for the specified SCSI Target Port.
941bdd6c0eSSue Gleeson  */
951bdd6c0eSSue Gleeson int
srpt_stp_start_srp(srpt_target_port_t * tgt)961bdd6c0eSSue Gleeson srpt_stp_start_srp(srpt_target_port_t *tgt)
971bdd6c0eSSue Gleeson {
981bdd6c0eSSue Gleeson 	ibt_status_t		status;
991bdd6c0eSSue Gleeson 	ibdma_status_t		dma_status;
1001bdd6c0eSSue Gleeson 	int			port;
1011bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
1021bdd6c0eSSue Gleeson 
1031bdd6c0eSSue Gleeson 	if (tgt == NULL) {
1041bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_start_srp, NULL SCSI target port");
1051bdd6c0eSSue Gleeson 		return (IBT_FAILURE);
1061bdd6c0eSSue Gleeson 	}
1071bdd6c0eSSue Gleeson 
1081bdd6c0eSSue Gleeson 	if (tgt->tp_ioc == NULL) {
1091bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_start_srp, SCSI target port NULL"
1101bdd6c0eSSue Gleeson 		    " IOC pointer");
1111bdd6c0eSSue Gleeson 		return (IBT_FAILURE);
1121bdd6c0eSSue Gleeson 	}
1131bdd6c0eSSue Gleeson 	ioc = tgt->tp_ioc;
1141bdd6c0eSSue Gleeson 
1151bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_start_srp, register SRP service for"
1161bdd6c0eSSue Gleeson 	    " svc_id (%016llx)", (u_longlong_t)tgt->tp_ibt_svc_id);
1171bdd6c0eSSue Gleeson 	status = ibt_register_service(srpt_ctxt->sc_ibt_hdl,
1181bdd6c0eSSue Gleeson 	    &tgt->tp_ibt_svc_desc, tgt->tp_ibt_svc_id, 1,
1191bdd6c0eSSue Gleeson 	    &tgt->tp_ibt_svc_hdl, NULL);
1201bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
1211bdd6c0eSSue Gleeson 		tgt->tp_ibt_svc_hdl = NULL;
1221bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_start_srp, SRP service creation err (%d)",
1231bdd6c0eSSue Gleeson 		    status);
1241bdd6c0eSSue Gleeson 		return (status);
1251bdd6c0eSSue Gleeson 	}
1261bdd6c0eSSue Gleeson 
1271bdd6c0eSSue Gleeson 	/*
1281bdd6c0eSSue Gleeson 	 * Bind the service associated with the SCSI target port to
1291bdd6c0eSSue Gleeson 	 * each active port of the I/O Controller.
1301bdd6c0eSSue Gleeson 	 */
1311bdd6c0eSSue Gleeson 	for (port = 0; port < ioc->ioc_attr.hca_nports; port++) {
1321bdd6c0eSSue Gleeson 		status = srpt_ioc_svc_bind(tgt, port+1);
1331bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS &&
1341bdd6c0eSSue Gleeson 		    status != IBT_HCA_PORT_NOT_ACTIVE) {
1351bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("start_srp, Unable to bind"
1361bdd6c0eSSue Gleeson 			    " service (%d)", status);
1371bdd6c0eSSue Gleeson 			goto srp_start_err;
1381bdd6c0eSSue Gleeson 		}
1391bdd6c0eSSue Gleeson 	}
1403baa0db4SSue Gleeson 
1413baa0db4SSue Gleeson 	/* don't online if we have no active ports */
1423baa0db4SSue Gleeson 	if (tgt->tp_num_active_ports == 0) {
1433baa0db4SSue Gleeson 		SRPT_DPRINTF_L2("start_srp, no ports active for svc_id %016llx",
1443baa0db4SSue Gleeson 		    (u_longlong_t)tgt->tp_ibt_svc_id);
1453baa0db4SSue Gleeson 		status = IBT_HCA_PORT_NOT_ACTIVE;
1463baa0db4SSue Gleeson 		goto srp_start_err;
1473baa0db4SSue Gleeson 	}
1483baa0db4SSue Gleeson 
1491bdd6c0eSSue Gleeson 	tgt->tp_srp_enabled = 1;
1501bdd6c0eSSue Gleeson 
1511bdd6c0eSSue Gleeson 	/*
1521bdd6c0eSSue Gleeson 	 * Calculate the new I/O Controller profile and either update the
1531bdd6c0eSSue Gleeson 	 * profile if previously registered or register it with the IB
1541bdd6c0eSSue Gleeson 	 * Device Management Agent.
1551bdd6c0eSSue Gleeson 	 */
1561bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("start_srp, update I/O Controller profile (%016llx)",
1571bdd6c0eSSue Gleeson 	    (u_longlong_t)ioc->ioc_guid);
1581bdd6c0eSSue Gleeson 
1591bdd6c0eSSue Gleeson 	srpt_ioc_init_profile(ioc);
1601bdd6c0eSSue Gleeson 	if (ioc->ioc_ibdma_hdl == NULL) {
1611bdd6c0eSSue Gleeson 		ioc->ioc_ibdma_hdl =
1621bdd6c0eSSue Gleeson 		    srpt_ctxt->sc_ibdma_ops.ibdma_register(ioc->ioc_guid,
1631bdd6c0eSSue Gleeson 		    &ioc->ioc_profile, &ioc->ioc_svc);
1641bdd6c0eSSue Gleeson 		if (ioc->ioc_ibdma_hdl == NULL) {
1651bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("start_srp, Unable to register"
1663baa0db4SSue Gleeson 			    " I/O Profile for svc_id %016llx",
1673baa0db4SSue Gleeson 			    (u_longlong_t)tgt->tp_ibt_svc_id);
1683baa0db4SSue Gleeson 			status = IBT_FAILURE;
1691bdd6c0eSSue Gleeson 			goto srp_start_err;
1701bdd6c0eSSue Gleeson 		}
1711bdd6c0eSSue Gleeson 	} else {
1721bdd6c0eSSue Gleeson 		dma_status =
1731bdd6c0eSSue Gleeson 		    srpt_ctxt->sc_ibdma_ops.ibdma_update(ioc->ioc_ibdma_hdl,
1741bdd6c0eSSue Gleeson 		    &ioc->ioc_profile, &ioc->ioc_svc);
1751bdd6c0eSSue Gleeson 		if (dma_status != IBDMA_SUCCESS) {
1761bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("start_srp, Unable to update I/O"
1773baa0db4SSue Gleeson 			    " Profile for svc_id %016llxi (%d)",
1783baa0db4SSue Gleeson 			    (u_longlong_t)tgt->tp_ibt_svc_id, dma_status);
1793baa0db4SSue Gleeson 			status = IBT_FAILURE;
1801bdd6c0eSSue Gleeson 			goto srp_start_err;
1811bdd6c0eSSue Gleeson 		}
1821bdd6c0eSSue Gleeson 	}
1831bdd6c0eSSue Gleeson 
1841bdd6c0eSSue Gleeson 	return (IBT_SUCCESS);
1851bdd6c0eSSue Gleeson 
1861bdd6c0eSSue Gleeson srp_start_err:
1871bdd6c0eSSue Gleeson 	tgt->tp_srp_enabled = 0;
1881bdd6c0eSSue Gleeson 	srpt_ioc_svc_unbind_all(tgt);
1893baa0db4SSue Gleeson 	tgt->tp_num_active_ports = 0;
1901bdd6c0eSSue Gleeson 	if (tgt->tp_ibt_svc_hdl != NULL) {
191aedf2b3bSsrivijitha dugganapalli 		(void) ibt_deregister_service(srpt_ctxt->sc_ibt_hdl,
1921bdd6c0eSSue Gleeson 		    tgt->tp_ibt_svc_hdl);
1931bdd6c0eSSue Gleeson 		tgt->tp_ibt_svc_hdl = NULL;
1941bdd6c0eSSue Gleeson 	}
1951bdd6c0eSSue Gleeson 	return (status);
1961bdd6c0eSSue Gleeson }
1971bdd6c0eSSue Gleeson 
1981bdd6c0eSSue Gleeson /*
1991bdd6c0eSSue Gleeson  * srpt_stp_stop_srp() - Stop SRP service.
2001bdd6c0eSSue Gleeson  *
2011bdd6c0eSSue Gleeson  * Disable the SRP service on the specified SCSI Target Port.
2021bdd6c0eSSue Gleeson  */
2031bdd6c0eSSue Gleeson void
srpt_stp_stop_srp(srpt_target_port_t * tgt)2041bdd6c0eSSue Gleeson srpt_stp_stop_srp(srpt_target_port_t *tgt)
2051bdd6c0eSSue Gleeson {
2061bdd6c0eSSue Gleeson 	ibt_status_t		status;
2071bdd6c0eSSue Gleeson 	ibdma_status_t		dma_status;
2081bdd6c0eSSue Gleeson 	srpt_ioc_t		*ioc;
2091bdd6c0eSSue Gleeson 	srpt_channel_t		*ch;
2101bdd6c0eSSue Gleeson 
2111bdd6c0eSSue Gleeson 	if (tgt == NULL) {
2121bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_stop_srp, NULL SCSI Target Port"
2131bdd6c0eSSue Gleeson 		    " specified");
2141bdd6c0eSSue Gleeson 		return;
2151bdd6c0eSSue Gleeson 	}
2161bdd6c0eSSue Gleeson 
2171bdd6c0eSSue Gleeson 	if (tgt->tp_ioc == NULL) {
2181bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_stop_srp, bad Target, IOC NULL");
2191bdd6c0eSSue Gleeson 		return;
2201bdd6c0eSSue Gleeson 	}
2211bdd6c0eSSue Gleeson 	ioc = tgt->tp_ioc;
2221bdd6c0eSSue Gleeson 
2231bdd6c0eSSue Gleeson 	/*
2241bdd6c0eSSue Gleeson 	 * Update the I/O Controller profile to remove the SRP service
2251bdd6c0eSSue Gleeson 	 * for this SCSI target port.
2261bdd6c0eSSue Gleeson 	 */
2271bdd6c0eSSue Gleeson 	tgt->tp_srp_enabled = 0;
2281bdd6c0eSSue Gleeson 
2291bdd6c0eSSue Gleeson 	if (ioc->ioc_ibdma_hdl != NULL) {
2301bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_stop_srp, update I/O Controller"
2311bdd6c0eSSue Gleeson 		    " profile (%016llx)", (u_longlong_t)ioc->ioc_guid);
2321bdd6c0eSSue Gleeson 		srpt_ioc_init_profile(ioc);
2331bdd6c0eSSue Gleeson 
2341bdd6c0eSSue Gleeson 		if (ioc->ioc_profile.ioc_service_entries == 0) {
2351bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L3("stp_stop_srp, no services active"
2361bdd6c0eSSue Gleeson 			    " unregister IOC profile");
2371bdd6c0eSSue Gleeson 			srpt_ctxt->sc_ibdma_ops.ibdma_unregister(
2381bdd6c0eSSue Gleeson 			    ioc->ioc_ibdma_hdl);
2391bdd6c0eSSue Gleeson 			ioc->ioc_ibdma_hdl = NULL;
2401bdd6c0eSSue Gleeson 		} else {
2411bdd6c0eSSue Gleeson 			dma_status = srpt_ctxt->sc_ibdma_ops.ibdma_update(
2421bdd6c0eSSue Gleeson 			    ioc->ioc_ibdma_hdl, &ioc->ioc_profile,
2431bdd6c0eSSue Gleeson 			    &ioc->ioc_svc);
2441bdd6c0eSSue Gleeson 			if (dma_status != IBDMA_SUCCESS) {
2451bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L1("stp_stop_srp, Unable to"
2461bdd6c0eSSue Gleeson 				    " update I/O Profile (%d)", dma_status);
2471bdd6c0eSSue Gleeson 				return;
2481bdd6c0eSSue Gleeson 			}
2491bdd6c0eSSue Gleeson 		}
2501bdd6c0eSSue Gleeson 	}
2511bdd6c0eSSue Gleeson 
2521bdd6c0eSSue Gleeson 	/*
2531bdd6c0eSSue Gleeson 	 * Unbind the SRP service associated with the SCSI target port
2541bdd6c0eSSue Gleeson 	 * from all of the I/O Controller physical ports.
2551bdd6c0eSSue Gleeson 	 */
2561bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_stop_srp, unbind and de-register service"
2571bdd6c0eSSue Gleeson 	    "(%016llx)", (u_longlong_t)tgt->tp_ibt_svc_id);
2581bdd6c0eSSue Gleeson 	if (tgt->tp_ibt_svc_hdl != NULL) {
2591bdd6c0eSSue Gleeson 		srpt_ioc_svc_unbind_all(tgt);
2601bdd6c0eSSue Gleeson 	}
2611bdd6c0eSSue Gleeson 
2621bdd6c0eSSue Gleeson 	if (tgt->tp_ibt_svc_hdl != NULL) {
2631bdd6c0eSSue Gleeson 		status = ibt_deregister_service(srpt_ctxt->sc_ibt_hdl,
2641bdd6c0eSSue Gleeson 		    tgt->tp_ibt_svc_hdl);
2651bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
2661bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("stp_stop_srp, de-register service"
2671bdd6c0eSSue Gleeson 			    " error(%d)", status);
2681bdd6c0eSSue Gleeson 		}
2691bdd6c0eSSue Gleeson 		tgt->tp_ibt_svc_hdl = NULL;
2701bdd6c0eSSue Gleeson 	}
2711bdd6c0eSSue Gleeson 
2721bdd6c0eSSue Gleeson 	/*
2731bdd6c0eSSue Gleeson 	 * SRP service is now off-line for this SCSI Target Port.
2741bdd6c0eSSue Gleeson 	 * We force a disconnect (i.e. SRP Target Logout) for any
2751bdd6c0eSSue Gleeson 	 * active SRP logins.
2761bdd6c0eSSue Gleeson 	 */
2771bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_ch_list_lock);
2781bdd6c0eSSue Gleeson 	ch = list_head(&tgt->tp_ch_list);
2791bdd6c0eSSue Gleeson 	while (ch != NULL) {
2801bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_stop_srp, disconnect ch(%p)",
2811bdd6c0eSSue Gleeson 		    (void *)ch);
2821bdd6c0eSSue Gleeson 		srpt_ch_disconnect(ch);
2831bdd6c0eSSue Gleeson 		ch = list_next(&tgt->tp_ch_list, ch);
2841bdd6c0eSSue Gleeson 	}
2851bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_ch_list_lock);
2861bdd6c0eSSue Gleeson 
2871bdd6c0eSSue Gleeson 	/*
2881bdd6c0eSSue Gleeson 	 * wait for all sessions to terminate before returning
2891bdd6c0eSSue Gleeson 	 */
2901bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_sess_list_lock);
2911bdd6c0eSSue Gleeson 	while (!list_is_empty(&tgt->tp_sess_list)) {
2921bdd6c0eSSue Gleeson 		cv_wait(&tgt->tp_sess_complete, &tgt->tp_sess_list_lock);
2931bdd6c0eSSue Gleeson 	}
2941bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_sess_list_lock);
2951bdd6c0eSSue Gleeson }
2961bdd6c0eSSue Gleeson 
2971bdd6c0eSSue Gleeson /*
2981bdd6c0eSSue Gleeson  * srpt_stp_alloc_port() - Allocate SCSI Target Port
2991bdd6c0eSSue Gleeson  */
3001bdd6c0eSSue Gleeson srpt_target_port_t *
srpt_stp_alloc_port(srpt_ioc_t * ioc,ib_guid_t guid)3011bdd6c0eSSue Gleeson srpt_stp_alloc_port(srpt_ioc_t *ioc, ib_guid_t guid)
3021bdd6c0eSSue Gleeson {
3031bdd6c0eSSue Gleeson 	stmf_status_t		status;
3041bdd6c0eSSue Gleeson 	srpt_target_port_t	*tgt;
3051bdd6c0eSSue Gleeson 	stmf_local_port_t	*lport;
3061bdd6c0eSSue Gleeson 	uint64_t		temp;
3071bdd6c0eSSue Gleeson 
3081bdd6c0eSSue Gleeson 	if (ioc == NULL) {
3091bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_alloc_port, NULL I/O Controller");
3101bdd6c0eSSue Gleeson 		return (NULL);
3111bdd6c0eSSue Gleeson 	}
3121bdd6c0eSSue Gleeson 
3131bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_alloc_port, allocate STMF local port");
3141bdd6c0eSSue Gleeson 	lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT, sizeof (*tgt), 0);
3151bdd6c0eSSue Gleeson 	if (lport == NULL) {
3161bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("tgt_alloc_port, stmf_alloc failed");
3171bdd6c0eSSue Gleeson 		return (NULL);
3181bdd6c0eSSue Gleeson 	}
3191bdd6c0eSSue Gleeson 
3201bdd6c0eSSue Gleeson 	tgt = lport->lport_port_private;
3211bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
3221bdd6c0eSSue Gleeson 
3231bdd6c0eSSue Gleeson 	mutex_init(&tgt->tp_lock, NULL, MUTEX_DRIVER, NULL);
3241bdd6c0eSSue Gleeson 
3251bdd6c0eSSue Gleeson 	mutex_init(&tgt->tp_ch_list_lock, NULL, MUTEX_DRIVER, NULL);
3261bdd6c0eSSue Gleeson 	cv_init(&tgt->tp_offline_complete, NULL, CV_DRIVER, NULL);
3271bdd6c0eSSue Gleeson 	list_create(&tgt->tp_ch_list, sizeof (srpt_channel_t),
3281bdd6c0eSSue Gleeson 	    offsetof(srpt_channel_t, ch_stp_node));
3291bdd6c0eSSue Gleeson 
3301bdd6c0eSSue Gleeson 	mutex_init(&tgt->tp_sess_list_lock, NULL, MUTEX_DRIVER, NULL);
3311bdd6c0eSSue Gleeson 	cv_init(&tgt->tp_sess_complete, NULL, CV_DRIVER, NULL);
3321bdd6c0eSSue Gleeson 	list_create(&tgt->tp_sess_list, sizeof (srpt_session_t),
3331bdd6c0eSSue Gleeson 	    offsetof(srpt_session_t, ss_node));
3341bdd6c0eSSue Gleeson 
3351bdd6c0eSSue Gleeson 	tgt->tp_state	 = SRPT_TGT_STATE_OFFLINE;
3361bdd6c0eSSue Gleeson 	tgt->tp_drv_disabled  = 0;
3371bdd6c0eSSue Gleeson 	tgt->tp_srp_enabled   = 0;
3381bdd6c0eSSue Gleeson 	tgt->tp_lport	 = lport;
3391bdd6c0eSSue Gleeson 	tgt->tp_ioc	   = ioc;
3401bdd6c0eSSue Gleeson 	tgt->tp_ibt_svc_id = guid;
3411bdd6c0eSSue Gleeson 	tgt->tp_ibt_svc_desc.sd_handler = srpt_cm_hdlr;
3421bdd6c0eSSue Gleeson 	tgt->tp_ibt_svc_desc.sd_flags   = IBT_SRV_NO_FLAGS;
3431bdd6c0eSSue Gleeson 	temp = h2b64(tgt->tp_ibt_svc_id);
3441bdd6c0eSSue Gleeson 	bcopy(&temp, &tgt->tp_srp_port_id[0], 8);
3451bdd6c0eSSue Gleeson 	temp = h2b64(tgt->tp_ioc->ioc_guid);
3461bdd6c0eSSue Gleeson 	bcopy(&temp, &tgt->tp_srp_port_id[8], 8);
3471bdd6c0eSSue Gleeson 
3481bdd6c0eSSue Gleeson 	tgt->tp_nports  = ioc->ioc_attr.hca_nports;
3491bdd6c0eSSue Gleeson 	tgt->tp_hw_port =
3501bdd6c0eSSue Gleeson 	    kmem_zalloc(sizeof (srpt_hw_port_t) * tgt->tp_nports, KM_SLEEP);
3513baa0db4SSue Gleeson 	tgt->tp_num_active_ports = 0;
3523baa0db4SSue Gleeson 	tgt->tp_requested_state = SRPT_TGT_STATE_OFFLINE;
3531bdd6c0eSSue Gleeson 
3541bdd6c0eSSue Gleeson 	tgt->tp_scsi_devid = srpt_stp_alloc_scsi_devid_desc(tgt->tp_ibt_svc_id);
3553baa0db4SSue Gleeson 
3561bdd6c0eSSue Gleeson 	lport->lport_id = tgt->tp_scsi_devid;
3571bdd6c0eSSue Gleeson 	lport->lport_pp = srpt_ctxt->sc_pp;
3581bdd6c0eSSue Gleeson 	lport->lport_ds	= ioc->ioc_stmf_ds;
3591bdd6c0eSSue Gleeson 	lport->lport_xfer_data	= &srpt_stp_xfer_data;
3601bdd6c0eSSue Gleeson 	lport->lport_send_status = &srpt_stp_send_status;
3611bdd6c0eSSue Gleeson 	lport->lport_task_free	= &srpt_stp_task_free;
3621bdd6c0eSSue Gleeson 	lport->lport_abort	= &srpt_stp_abort;
3632d361592SSue Gleeson 	lport->lport_abort_timeout = 300;	/* 5 minutes */
3641bdd6c0eSSue Gleeson 	lport->lport_task_poll	= &srpt_stp_task_poll;
3651bdd6c0eSSue Gleeson 	lport->lport_ctl	= &srpt_stp_ctl;
3661bdd6c0eSSue Gleeson 	lport->lport_info	= &srpt_stp_info;
3671bdd6c0eSSue Gleeson 	lport->lport_event_handler = &srpt_stp_event_handler;
3681bdd6c0eSSue Gleeson 
369cd36db67SJohn Forte 	/* set up as alua participating port */
370cd36db67SJohn Forte 	stmf_set_port_alua(lport);
371cd36db67SJohn Forte 
3721bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_alloc_port, register STMF LPORT");
3731bdd6c0eSSue Gleeson 
3741bdd6c0eSSue Gleeson retry_registration:
3751bdd6c0eSSue Gleeson 	status = stmf_register_local_port(lport);
3761bdd6c0eSSue Gleeson 	if (status == STMF_SUCCESS) {
3771bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_alloc_port, LPORT successfully"
3781bdd6c0eSSue Gleeson 		    " registered");
3791bdd6c0eSSue Gleeson 		return (tgt);
3801bdd6c0eSSue Gleeson 	}
3811bdd6c0eSSue Gleeson 
3821bdd6c0eSSue Gleeson 	if (status == STMF_BUSY) {
3831bdd6c0eSSue Gleeson 		/*
3841bdd6c0eSSue Gleeson 		 * This is only done on an administrative thread of
3851bdd6c0eSSue Gleeson 		 * execution so it is ok to take a while.
3861bdd6c0eSSue Gleeson 		 */
3871bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_alloc_port, delaying");
3881bdd6c0eSSue Gleeson 		delay(2 * drv_usectohz(1000000));
3891bdd6c0eSSue Gleeson 		goto retry_registration;
3901bdd6c0eSSue Gleeson 	}
3911bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L1("stp_alloc_port, STMF register local port err(0x%llx)",
3921bdd6c0eSSue Gleeson 	    (u_longlong_t)status);
3931bdd6c0eSSue Gleeson 
3941bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_alloc_port, free STMF local port");
3951bdd6c0eSSue Gleeson 	cv_destroy(&tgt->tp_offline_complete);
3961bdd6c0eSSue Gleeson 	mutex_destroy(&tgt->tp_ch_list_lock);
3971bdd6c0eSSue Gleeson 	mutex_destroy(&tgt->tp_lock);
3981bdd6c0eSSue Gleeson 	if (tgt->tp_hw_port) {
3991bdd6c0eSSue Gleeson 		kmem_free(tgt->tp_hw_port,
4001bdd6c0eSSue Gleeson 		    sizeof (srpt_hw_port_t) * tgt->tp_nports);
4011bdd6c0eSSue Gleeson 	}
4021bdd6c0eSSue Gleeson 	if (tgt->tp_scsi_devid) {
4031bdd6c0eSSue Gleeson 		srpt_stp_free_scsi_devid_desc(tgt->tp_scsi_devid);
4041bdd6c0eSSue Gleeson 	}
4051bdd6c0eSSue Gleeson 
4061bdd6c0eSSue Gleeson 	stmf_free(lport);
4071bdd6c0eSSue Gleeson 
4081bdd6c0eSSue Gleeson 	return (NULL);
4091bdd6c0eSSue Gleeson }
4101bdd6c0eSSue Gleeson 
4111bdd6c0eSSue Gleeson /*
4121bdd6c0eSSue Gleeson  * srpt_stp_free_port() - Free SCSI Target Port
4131bdd6c0eSSue Gleeson  */
4141bdd6c0eSSue Gleeson stmf_status_t
srpt_stp_free_port(srpt_target_port_t * tgt)4151bdd6c0eSSue Gleeson srpt_stp_free_port(srpt_target_port_t *tgt)
4161bdd6c0eSSue Gleeson {
4171bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
4181bdd6c0eSSue Gleeson 	ASSERT(list_is_empty(&tgt->tp_sess_list));
4191bdd6c0eSSue Gleeson 	ASSERT(list_is_empty(&tgt->tp_ch_list));
4201bdd6c0eSSue Gleeson 
4211bdd6c0eSSue Gleeson 	list_destroy(&tgt->tp_ch_list);
4221bdd6c0eSSue Gleeson 	list_destroy(&tgt->tp_sess_list);
4231bdd6c0eSSue Gleeson 
4241bdd6c0eSSue Gleeson 	cv_destroy(&tgt->tp_sess_complete);
4251bdd6c0eSSue Gleeson 	cv_destroy(&tgt->tp_offline_complete);
4261bdd6c0eSSue Gleeson 
4271bdd6c0eSSue Gleeson 	mutex_destroy(&tgt->tp_sess_list_lock);
4281bdd6c0eSSue Gleeson 	mutex_destroy(&tgt->tp_ch_list_lock);
4291bdd6c0eSSue Gleeson 	mutex_destroy(&tgt->tp_lock);
4301bdd6c0eSSue Gleeson 
4311bdd6c0eSSue Gleeson 
4321bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_free_port, free STMF local port");
4331bdd6c0eSSue Gleeson 	if (tgt->tp_hw_port) {
4341bdd6c0eSSue Gleeson 		kmem_free(tgt->tp_hw_port,
4351bdd6c0eSSue Gleeson 		    sizeof (srpt_hw_port_t) * tgt->tp_nports);
4361bdd6c0eSSue Gleeson 	}
4371bdd6c0eSSue Gleeson 
4381bdd6c0eSSue Gleeson 	if (tgt->tp_scsi_devid) {
4391bdd6c0eSSue Gleeson 		srpt_stp_free_scsi_devid_desc(tgt->tp_scsi_devid);
4401bdd6c0eSSue Gleeson 	}
4411bdd6c0eSSue Gleeson 
4421bdd6c0eSSue Gleeson 	stmf_free(tgt->tp_lport);
4431bdd6c0eSSue Gleeson 
4441bdd6c0eSSue Gleeson 	return (STMF_SUCCESS);
4451bdd6c0eSSue Gleeson }
4461bdd6c0eSSue Gleeson 
4471bdd6c0eSSue Gleeson /*
448c3a558e7SSue Gleeson  * srpt_stp_destroy_port()
4491bdd6c0eSSue Gleeson  */
4501bdd6c0eSSue Gleeson stmf_status_t
srpt_stp_destroy_port(srpt_target_port_t * tgt)451c3a558e7SSue Gleeson srpt_stp_destroy_port(srpt_target_port_t *tgt)
4521bdd6c0eSSue Gleeson {
4531bdd6c0eSSue Gleeson 	stmf_status_t		status;
454c3a558e7SSue Gleeson 	stmf_change_status_t	cstatus;
455c3a558e7SSue Gleeson 	uint64_t		guid;
4561bdd6c0eSSue Gleeson 
4571bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
4581bdd6c0eSSue Gleeson 	ASSERT(tgt->tp_lport != NULL);
4591bdd6c0eSSue Gleeson 
460c3a558e7SSue Gleeson 	SRPT_DPRINTF_L3("stp_destroy_port, de-register STMF LPORT");
4611bdd6c0eSSue Gleeson 
462c3a558e7SSue Gleeson 	mutex_enter(&tgt->tp_lock);
463c3a558e7SSue Gleeson 	if (tgt->tp_drv_disabled != 0) {
464c3a558e7SSue Gleeson 		/* already being destroyed, get out now - should not happen */
465c3a558e7SSue Gleeson 		mutex_exit(&tgt->tp_lock);
466c3a558e7SSue Gleeson 		return (STMF_ALREADY);
4671bdd6c0eSSue Gleeson 	}
468c3a558e7SSue Gleeson 
469c3a558e7SSue Gleeson 	tgt->tp_drv_disabled = 1;
470c3a558e7SSue Gleeson 	guid = tgt->tp_ioc->ioc_guid;
471c3a558e7SSue Gleeson 	mutex_exit(&tgt->tp_lock);
472c3a558e7SSue Gleeson 
473c3a558e7SSue Gleeson 	SRPT_DPRINTF_L2("stp_destroy_port: unbind and de-register"
474c3a558e7SSue Gleeson 	    " services for GUID(%016llx)", (u_longlong_t)guid);
475c3a558e7SSue Gleeson 
476c3a558e7SSue Gleeson 	cstatus.st_completion_status = STMF_SUCCESS;
477c3a558e7SSue Gleeson 	cstatus.st_additional_info = NULL;
478c3a558e7SSue Gleeson 
479c3a558e7SSue Gleeson 	status = stmf_ctl(STMF_CMD_LPORT_OFFLINE, tgt->tp_lport, &cstatus);
480c3a558e7SSue Gleeson 
4811bdd6c0eSSue Gleeson 	/*
482c3a558e7SSue Gleeson 	 * Wait for asynchronous target off-line operation
483c3a558e7SSue Gleeson 	 * to complete and then deregister the target
484c3a558e7SSue Gleeson 	 * port.
4851bdd6c0eSSue Gleeson 	 */
486c3a558e7SSue Gleeson 	mutex_enter(&tgt->tp_lock);
487c3a558e7SSue Gleeson 	while (tgt->tp_state != SRPT_TGT_STATE_OFFLINE) {
488c3a558e7SSue Gleeson 		cv_wait(&tgt->tp_offline_complete, &tgt->tp_lock);
489c3a558e7SSue Gleeson 	}
490c3a558e7SSue Gleeson 	mutex_exit(&tgt->tp_lock);
491c3a558e7SSue Gleeson 
492c3a558e7SSue Gleeson 	SRPT_DPRINTF_L3("stp_destroy_port: IOC (0x%016llx) Target"
493c3a558e7SSue Gleeson 	    " SRP off-line complete", (u_longlong_t)guid);
494c3a558e7SSue Gleeson 
495c3a558e7SSue Gleeson 	/* loop waiting for all I/O to drain */
496c3a558e7SSue Gleeson 	for (;;) {
497c3a558e7SSue Gleeson 		status = stmf_deregister_local_port(tgt->tp_lport);
498c3a558e7SSue Gleeson 		if (status == STMF_BUSY) {
499c3a558e7SSue Gleeson 			delay(drv_usectohz(1000000));
500c3a558e7SSue Gleeson 		} else {
501c3a558e7SSue Gleeson 			break;
502c3a558e7SSue Gleeson 		}
503c3a558e7SSue Gleeson 	}
504c3a558e7SSue Gleeson 
505c3a558e7SSue Gleeson 	if (status == STMF_SUCCESS) {
506c3a558e7SSue Gleeson 		SRPT_DPRINTF_L3("stp_destroy_port, LPORT de-register"
507c3a558e7SSue Gleeson 		    " complete");
508c3a558e7SSue Gleeson 	} else {
509c3a558e7SSue Gleeson 		/*
510c3a558e7SSue Gleeson 		 * Something other than a BUSY error, this should not happen.
511c3a558e7SSue Gleeson 		 */
512c3a558e7SSue Gleeson 		SRPT_DPRINTF_L1(
513c3a558e7SSue Gleeson 		    "stp_destroy_port, de-register STMF error(0x%llx)",
514c3a558e7SSue Gleeson 		    (u_longlong_t)status);
5151bdd6c0eSSue Gleeson 	}
5161bdd6c0eSSue Gleeson 
5171bdd6c0eSSue Gleeson 	return (status);
5181bdd6c0eSSue Gleeson }
5191bdd6c0eSSue Gleeson 
5201bdd6c0eSSue Gleeson /*
5211bdd6c0eSSue Gleeson  * srpt_stp_xfer_data()
5221bdd6c0eSSue Gleeson  */
5231bdd6c0eSSue Gleeson /* ARGSUSED */
5241bdd6c0eSSue Gleeson static stmf_status_t
srpt_stp_xfer_data(struct scsi_task * task,struct stmf_data_buf * dbuf,uint32_t ioflags)5251bdd6c0eSSue Gleeson srpt_stp_xfer_data(struct scsi_task *task, struct stmf_data_buf *dbuf,
5261bdd6c0eSSue Gleeson 	uint32_t ioflags)
5271bdd6c0eSSue Gleeson {
5281bdd6c0eSSue Gleeson 	srpt_iu_t		*iu;
5291bdd6c0eSSue Gleeson 	srpt_channel_t		*ch;
5301bdd6c0eSSue Gleeson 	srpt_ds_dbuf_t		*db;
5311bdd6c0eSSue Gleeson 	ibt_send_wr_t		wr;
5321bdd6c0eSSue Gleeson 	ibt_wr_ds_t		ds;
5331bdd6c0eSSue Gleeson 	ibt_status_t		status;
5341bdd6c0eSSue Gleeson 	uint32_t		xfer_len;
5351bdd6c0eSSue Gleeson 	uint32_t		xferred_len;
5361bdd6c0eSSue Gleeson 	uint32_t		rdma_len;
5371bdd6c0eSSue Gleeson 	uint32_t		base_offset;
5381bdd6c0eSSue Gleeson 	uint32_t		desc_offset;
5391bdd6c0eSSue Gleeson 	srp_direct_desc_t	*desc;
5401bdd6c0eSSue Gleeson 
5411bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_xfer_data, invoked task (%p), dbuf (%p)",
5421bdd6c0eSSue Gleeson 	    (void *)task, (void *)dbuf);
5431bdd6c0eSSue Gleeson 	iu = task->task_port_private;
5441bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
5451bdd6c0eSSue Gleeson 	ASSERT(iu->iu_ch != NULL);
5461bdd6c0eSSue Gleeson 	/*
5471bdd6c0eSSue Gleeson 	 * We should use iu->iu_ch->ch_swqe_posted to throttle
5481bdd6c0eSSue Gleeson 	 * send wqe posting. This is very unlikely because we limit
5491bdd6c0eSSue Gleeson 	 * the maximum number of initiator descriptors per IU (impact
5501bdd6c0eSSue Gleeson 	 * of fragmentation of intiator buffer space) but it could occur
5511bdd6c0eSSue Gleeson 	 * if the back-end (STMF) were to use too many small buffers. In
5521bdd6c0eSSue Gleeson 	 * that case we would want to return STMF_BUSY.
5531bdd6c0eSSue Gleeson 	 */
5541bdd6c0eSSue Gleeson 
5551bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("stp_xfer_data, dbuf->db_flags (0x%x)",
5561bdd6c0eSSue Gleeson 	    dbuf->db_flags);
5571bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("stp_xfer_data, dbuf->db_data_size (%d)",
5581bdd6c0eSSue Gleeson 	    dbuf->db_data_size);
5591bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("stp_xfer_data, dbuf->db_relative_offset (%d)",
5601bdd6c0eSSue Gleeson 	    dbuf->db_relative_offset);
5611bdd6c0eSSue Gleeson 
5621bdd6c0eSSue Gleeson 	ASSERT((dbuf->db_flags & (DB_DIRECTION_TO_RPORT |
5631bdd6c0eSSue Gleeson 	    DB_DIRECTION_FROM_RPORT)) != (DB_DIRECTION_TO_RPORT |
5641bdd6c0eSSue Gleeson 	    DB_DIRECTION_FROM_RPORT));
5651bdd6c0eSSue Gleeson 
5661bdd6c0eSSue Gleeson 	db = dbuf->db_port_private;
5671bdd6c0eSSue Gleeson 
5681bdd6c0eSSue Gleeson 	/*
5691bdd6c0eSSue Gleeson 	 * Check to see if request will overflow the remote buffer; if so
5701bdd6c0eSSue Gleeson 	 * return a bad status and let STMF abort the task.
5711bdd6c0eSSue Gleeson 	 */
5721bdd6c0eSSue Gleeson 	if ((dbuf->db_relative_offset + dbuf->db_data_size) >
5731bdd6c0eSSue Gleeson 	    iu->iu_tot_xfer_len) {
5741bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_xfer_data, overflow of remote buffer");
5751bdd6c0eSSue Gleeson 		return (STMF_FAILURE);
5761bdd6c0eSSue Gleeson 	}
5771bdd6c0eSSue Gleeson 
5781bdd6c0eSSue Gleeson 	db->db_iu	= iu;
5791bdd6c0eSSue Gleeson 	wr.wr_trans  = IBT_RC_SRV;
5801bdd6c0eSSue Gleeson 	wr.wr_opcode = (dbuf->db_flags & DB_DIRECTION_TO_RPORT) ?
5811bdd6c0eSSue Gleeson 	    IBT_WRC_RDMAW : IBT_WRC_RDMAR;
5821bdd6c0eSSue Gleeson 	wr.wr_nds    = 1;
5831bdd6c0eSSue Gleeson 	wr.wr_sgl    = &ds;
5841bdd6c0eSSue Gleeson 
5851bdd6c0eSSue Gleeson 	/*
5861bdd6c0eSSue Gleeson 	 * We know that the data transfer is within the bounds described
5871bdd6c0eSSue Gleeson 	 * by our list of remote buffer descriptors.  Find the starting
5881bdd6c0eSSue Gleeson 	 * point based on the offset for the transfer, then perform the
5891bdd6c0eSSue Gleeson 	 * RDMA operations required of this transfer.
5901bdd6c0eSSue Gleeson 	 */
5911bdd6c0eSSue Gleeson 	base_offset = 0;
5921bdd6c0eSSue Gleeson 	desc = iu->iu_rdescs;
5931bdd6c0eSSue Gleeson 
5941bdd6c0eSSue Gleeson 	while ((base_offset + desc->dd_len) < dbuf->db_relative_offset) {
5951bdd6c0eSSue Gleeson 		base_offset += desc->dd_len;
5961bdd6c0eSSue Gleeson 		desc++;
5971bdd6c0eSSue Gleeson 	}
5981bdd6c0eSSue Gleeson 
5991bdd6c0eSSue Gleeson 	xfer_len    = dbuf->db_data_size;
6001bdd6c0eSSue Gleeson 	xferred_len = 0;
6011bdd6c0eSSue Gleeson 	desc_offset = dbuf->db_relative_offset - base_offset;
6021bdd6c0eSSue Gleeson 
6031bdd6c0eSSue Gleeson 	ch = iu->iu_ch;
6041bdd6c0eSSue Gleeson 
6051bdd6c0eSSue Gleeson 	/*
6061bdd6c0eSSue Gleeson 	 * If the channel is no longer connected then return an
6071bdd6c0eSSue Gleeson 	 * error and do not initiate I/O.  STMF should abort the
6081bdd6c0eSSue Gleeson 	 * task.
6091bdd6c0eSSue Gleeson 	 */
6101bdd6c0eSSue Gleeson 	rw_enter(&ch->ch_rwlock, RW_READER);
6111bdd6c0eSSue Gleeson 
6121bdd6c0eSSue Gleeson 	if (iu->iu_ch->ch_state == SRPT_CHANNEL_DISCONNECTING) {
6131bdd6c0eSSue Gleeson 		rw_exit(&iu->iu_ch->ch_rwlock);
6141bdd6c0eSSue Gleeson 		return (STMF_FAILURE);
6151bdd6c0eSSue Gleeson 	}
6161bdd6c0eSSue Gleeson 
6171bdd6c0eSSue Gleeson 	while (xfer_len > 0) {
6181bdd6c0eSSue Gleeson 		rdma_len = desc->dd_len - desc_offset;
6191bdd6c0eSSue Gleeson 
6201bdd6c0eSSue Gleeson 		/*
6211bdd6c0eSSue Gleeson 		 * We only generate completion entries on the last IB
6221bdd6c0eSSue Gleeson 		 * operation associated with any STMF buffer.
6231bdd6c0eSSue Gleeson 		 */
6241bdd6c0eSSue Gleeson 		if (rdma_len >= xfer_len) {
6251bdd6c0eSSue Gleeson 			rdma_len = xfer_len;
6261bdd6c0eSSue Gleeson 			wr.wr_flags  = IBT_WR_SEND_SIGNAL;
6271bdd6c0eSSue Gleeson 		} else {
6281bdd6c0eSSue Gleeson 			wr.wr_flags  = IBT_WR_NO_FLAGS;
6291bdd6c0eSSue Gleeson 		}
6301bdd6c0eSSue Gleeson 
6311bdd6c0eSSue Gleeson 		wr.wr.rc.rcwr.rdma.rdma_raddr = desc->dd_vaddr + desc_offset;
6321bdd6c0eSSue Gleeson 		wr.wr.rc.rcwr.rdma.rdma_rkey  = desc->dd_hdl;
6331bdd6c0eSSue Gleeson 		ds.ds_va  = db->db_sge.ds_va + xferred_len;
6341bdd6c0eSSue Gleeson 		ds.ds_key = db->db_sge.ds_key;
6351bdd6c0eSSue Gleeson 		ds.ds_len = rdma_len;
6361bdd6c0eSSue Gleeson 
6371bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L4("stp_xfer_data, post RDMA operation");
6381bdd6c0eSSue Gleeson 
6391bdd6c0eSSue Gleeson 		/*
6401bdd6c0eSSue Gleeson 		 * If this task is being aborted or has been aborted,
6411bdd6c0eSSue Gleeson 		 * do not post additional I/O.
6421bdd6c0eSSue Gleeson 		 */
6437830165bSCharles Ting 		DTRACE_SRP_8(xfer__start, srpt_channel_t, ch,
6447830165bSCharles Ting 		    ibt_wr_ds_t, &(db->db_sge), srpt_iu_t, iu,
6457830165bSCharles Ting 		    ibt_send_wr_t, &wr, uint32_t, rdma_len,
6467830165bSCharles Ting 		    uint32_t, xferred_len, uint32_t, desc_offset,
647191c289bSCharles Ting 		    uint32_t, wr.wr_opcode == IBT_WRC_RDMAR ? 0 : 1);
6481bdd6c0eSSue Gleeson 		mutex_enter(&iu->iu_lock);
6491bdd6c0eSSue Gleeson 		if ((iu->iu_flags & (SRPT_IU_SRP_ABORTING |
6501bdd6c0eSSue Gleeson 		    SRPT_IU_STMF_ABORTING | SRPT_IU_ABORTED)) != 0) {
6511bdd6c0eSSue Gleeson 			mutex_exit(&iu->iu_lock);
6521bdd6c0eSSue Gleeson 			rw_exit(&iu->iu_ch->ch_rwlock);
6531bdd6c0eSSue Gleeson 			return (STMF_SUCCESS);
6541bdd6c0eSSue Gleeson 		}
6551bdd6c0eSSue Gleeson 
6561bdd6c0eSSue Gleeson 		/*
6571bdd6c0eSSue Gleeson 		 * If a non-error CQE will be requested, add a reference to
6581bdd6c0eSSue Gleeson 		 * the IU and initialize the work request appropriately.
6591bdd6c0eSSue Gleeson 		 */
6601bdd6c0eSSue Gleeson 		if ((wr.wr_flags & IBT_WR_SEND_SIGNAL) != 0) {
6611bdd6c0eSSue Gleeson 			wr.wr_id = srpt_ch_alloc_swqe_wrid(ch,
6621bdd6c0eSSue Gleeson 			    SRPT_SWQE_TYPE_DATA, (void *)dbuf);
6631bdd6c0eSSue Gleeson 			if (wr.wr_id == 0) {
6641bdd6c0eSSue Gleeson 				rw_exit(&iu->iu_ch->ch_rwlock);
6651bdd6c0eSSue Gleeson 				mutex_exit(&iu->iu_lock);
6661bdd6c0eSSue Gleeson 				return (STMF_BUSY);
6671bdd6c0eSSue Gleeson 			}
6681bdd6c0eSSue Gleeson 			atomic_inc_32(&iu->iu_sq_posted_cnt);
6691bdd6c0eSSue Gleeson 		} else {
6701bdd6c0eSSue Gleeson 			wr.wr_id = 0;
6711bdd6c0eSSue Gleeson 		}
6721bdd6c0eSSue Gleeson 
6731bdd6c0eSSue Gleeson 		status = ibt_post_send(iu->iu_ch->ch_chan_hdl, &wr, 1, NULL);
6741bdd6c0eSSue Gleeson 		mutex_exit(&iu->iu_lock);
6751bdd6c0eSSue Gleeson 
6761bdd6c0eSSue Gleeson 		if (status != IBT_SUCCESS) {
6771bdd6c0eSSue Gleeson 			/*
6781bdd6c0eSSue Gleeson 			 * Could not post to IB transport, report to STMF and
6791bdd6c0eSSue Gleeson 			 * and let it initiate an abort of the task.
6801bdd6c0eSSue Gleeson 			 */
6811bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_xfer_data, post RDMA"
6821bdd6c0eSSue Gleeson 			    " error (%d)", status);
6831bdd6c0eSSue Gleeson 
6841bdd6c0eSSue Gleeson 			if ((wr.wr_flags & IBT_WR_SEND_SIGNAL) != 0) {
6851bdd6c0eSSue Gleeson 				srpt_ch_free_swqe_wrid(ch, wr.wr_id);
6861bdd6c0eSSue Gleeson 				atomic_dec_32(&iu->iu_sq_posted_cnt);
6871bdd6c0eSSue Gleeson 			}
6881bdd6c0eSSue Gleeson 			rw_exit(&iu->iu_ch->ch_rwlock);
6891bdd6c0eSSue Gleeson 			return (STMF_FAILURE);
6901bdd6c0eSSue Gleeson 		}
6911bdd6c0eSSue Gleeson 		xferred_len += rdma_len;
6921bdd6c0eSSue Gleeson 		xfer_len    -= rdma_len;
6931bdd6c0eSSue Gleeson 		desc_offset  = 0;
6941bdd6c0eSSue Gleeson 		desc++;
6951bdd6c0eSSue Gleeson 	}
6961bdd6c0eSSue Gleeson 
6971bdd6c0eSSue Gleeson 	rw_exit(&ch->ch_rwlock);
6981bdd6c0eSSue Gleeson 	return (STMF_SUCCESS);
6991bdd6c0eSSue Gleeson }
7001bdd6c0eSSue Gleeson 
7011bdd6c0eSSue Gleeson /*
7021bdd6c0eSSue Gleeson  * srpt_stp_send_mgmt_response() - Return SRP task managment response IU
7031bdd6c0eSSue Gleeson  */
7041bdd6c0eSSue Gleeson ibt_status_t
srpt_stp_send_mgmt_response(srpt_iu_t * iu,uint8_t srp_rsp,uint_t fence)7051bdd6c0eSSue Gleeson srpt_stp_send_mgmt_response(srpt_iu_t *iu, uint8_t srp_rsp,
7061bdd6c0eSSue Gleeson 	uint_t fence)
7071bdd6c0eSSue Gleeson {
7081bdd6c0eSSue Gleeson 	srp_rsp_t	*rsp;
7091bdd6c0eSSue Gleeson 	srp_rsp_data_t	*data;
7101bdd6c0eSSue Gleeson 	uint32_t	rsp_length;
7111bdd6c0eSSue Gleeson 	ibt_status_t	status;
7121bdd6c0eSSue Gleeson 	uint8_t		*bufp;
7131bdd6c0eSSue Gleeson 
7141bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&iu->iu_lock));
7151bdd6c0eSSue Gleeson 	rsp = iu->iu_buf;
7161bdd6c0eSSue Gleeson 	bufp = (uint8_t *)iu->iu_buf + SRP_RSP_SIZE;
7171bdd6c0eSSue Gleeson 	bzero(rsp, SRP_RSP_SIZE + sizeof (srp_rsp_data_t));
7181bdd6c0eSSue Gleeson 	rsp->rsp_type = SRP_IU_RSP;
7191bdd6c0eSSue Gleeson 
7201bdd6c0eSSue Gleeson 	/*
7211bdd6c0eSSue Gleeson 	 * Report ULP credits we have added since last response sent
7221bdd6c0eSSue Gleeson 	 * over this channel.
7231bdd6c0eSSue Gleeson 	 */
7241bdd6c0eSSue Gleeson 	rsp->rsp_req_limit_delta =
7251bdd6c0eSSue Gleeson 	    h2b32(atomic_swap_32(&iu->iu_ch->ch_req_lim_delta, 0));
7261bdd6c0eSSue Gleeson 	rsp->rsp_tag = iu->iu_tag;
7271bdd6c0eSSue Gleeson 
7281bdd6c0eSSue Gleeson 	/* srp_rsp_t is padded out, so use explicit size here */
7291bdd6c0eSSue Gleeson 	rsp_length = SRP_RSP_SIZE;
7301bdd6c0eSSue Gleeson 	if (srp_rsp != SRP_TM_SUCCESS) {
7311bdd6c0eSSue Gleeson 		rsp->rsp_flags |= SRP_RSP_VALID;
7321bdd6c0eSSue Gleeson 		data = (srp_rsp_data_t *)bufp;
7331bdd6c0eSSue Gleeson 		data->rd_rsp_status = srp_rsp;
7341bdd6c0eSSue Gleeson 		rsp->rsp_data_len = h2b32(sizeof (srp_rsp_data_t));
7351bdd6c0eSSue Gleeson 		rsp_length += sizeof (srp_rsp_data_t);
7361bdd6c0eSSue Gleeson 	}
7371bdd6c0eSSue Gleeson 
7381bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("stp_send_mgmt_response, sending on ch(%p),"
7391bdd6c0eSSue Gleeson 	    " iu(%p), mgmt status(%d)", (void *)iu->iu_ch,
7401bdd6c0eSSue Gleeson 	    (void *)iu, srp_rsp);
7411bdd6c0eSSue Gleeson 
742191c289bSCharles Ting 	DTRACE_SRP_4(task__response, srpt_channel_t, iu->iu_ch,
743191c289bSCharles Ting 	    srp_rsp_t, iu->iu_buf, scsi_task_t, iu->iu_stmf_task,
744191c289bSCharles Ting 	    int8_t, srp_rsp);
745191c289bSCharles Ting 
7461bdd6c0eSSue Gleeson 	status = srpt_ch_post_send(iu->iu_ch, iu, rsp_length, fence);
7471bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
7481bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_send_mgmt_response, post "
7491bdd6c0eSSue Gleeson 		    "response err(%d)", status);
7501bdd6c0eSSue Gleeson 	}
7511bdd6c0eSSue Gleeson 	return (status);
7521bdd6c0eSSue Gleeson }
7531bdd6c0eSSue Gleeson 
7541bdd6c0eSSue Gleeson /*
7551bdd6c0eSSue Gleeson  * srpt_stp_send_response() - Send SRP command response IU
7561bdd6c0eSSue Gleeson  */
7571bdd6c0eSSue Gleeson ibt_status_t
srpt_stp_send_response(srpt_iu_t * iu,uint8_t scsi_status,uint8_t flags,uint32_t resid,uint16_t sense_length,uint8_t * sense_data,uint_t fence)7581bdd6c0eSSue Gleeson srpt_stp_send_response(srpt_iu_t *iu, uint8_t scsi_status,
7591bdd6c0eSSue Gleeson 	uint8_t flags, uint32_t resid, uint16_t sense_length,
7601bdd6c0eSSue Gleeson 	uint8_t *sense_data, uint_t fence)
7611bdd6c0eSSue Gleeson {
7621bdd6c0eSSue Gleeson 	srp_rsp_t	*rsp;
7631bdd6c0eSSue Gleeson 	uint32_t	rsp_length;
7641bdd6c0eSSue Gleeson 	uint8_t		*bufp;
7651bdd6c0eSSue Gleeson 	ibt_status_t	status;
7661bdd6c0eSSue Gleeson 
7671bdd6c0eSSue Gleeson 	ASSERT(mutex_owned(&iu->iu_lock));
7681bdd6c0eSSue Gleeson 	rsp = iu->iu_buf;
7691bdd6c0eSSue Gleeson 	bufp = (uint8_t *)iu->iu_buf + SRP_RSP_SIZE;
7701bdd6c0eSSue Gleeson 	bzero(rsp, SRP_RSP_SIZE);
7711bdd6c0eSSue Gleeson 	rsp->rsp_type = SRP_IU_RSP;
7721bdd6c0eSSue Gleeson 
7731bdd6c0eSSue Gleeson 	/*
7741bdd6c0eSSue Gleeson 	 * Report ULP credits we have added since last response sent
7751bdd6c0eSSue Gleeson 	 * over this channel.
7761bdd6c0eSSue Gleeson 	 */
7771bdd6c0eSSue Gleeson 	rsp->rsp_req_limit_delta =
7781bdd6c0eSSue Gleeson 	    h2b32(atomic_swap_32(&iu->iu_ch->ch_req_lim_delta, 0));
7791bdd6c0eSSue Gleeson 	rsp->rsp_tag = iu->iu_tag;
7801bdd6c0eSSue Gleeson 	rsp->rsp_status = scsi_status;
7811bdd6c0eSSue Gleeson 
7821bdd6c0eSSue Gleeson 	rsp_length = SRP_RSP_SIZE;
7831bdd6c0eSSue Gleeson 
7841bdd6c0eSSue Gleeson 	if (resid != 0) {
7851bdd6c0eSSue Gleeson 		rsp->rsp_flags |= flags;
7861bdd6c0eSSue Gleeson 
7871bdd6c0eSSue Gleeson 		if ((flags & SRP_RSP_DO_OVER) ||
7881bdd6c0eSSue Gleeson 		    (flags & SRP_RSP_DO_UNDER)) {
7891bdd6c0eSSue Gleeson 			rsp->rsp_do_resid_cnt = h2b32(resid);
7901bdd6c0eSSue Gleeson 		} else if ((flags & SRP_RSP_DI_OVER) ||
7911bdd6c0eSSue Gleeson 		    (flags & SRP_RSP_DI_UNDER)) {
7921bdd6c0eSSue Gleeson 			rsp->rsp_di_resid_cnt = h2b32(resid);
7931bdd6c0eSSue Gleeson 		}
7941bdd6c0eSSue Gleeson 	}
7951bdd6c0eSSue Gleeson 
7961bdd6c0eSSue Gleeson 	if (sense_length != 0) {
7971bdd6c0eSSue Gleeson 		rsp->rsp_flags |= SRP_RSP_SNS_VALID;
7981bdd6c0eSSue Gleeson 		if (SRP_RSP_SIZE + sense_length >
7991bdd6c0eSSue Gleeson 		    iu->iu_ch->ch_ti_iu_len) {
8001bdd6c0eSSue Gleeson 			sense_length = iu->iu_ch->ch_ti_iu_len -
8011bdd6c0eSSue Gleeson 			    SRP_RSP_SIZE;
8021bdd6c0eSSue Gleeson 		}
8031bdd6c0eSSue Gleeson 		bcopy(sense_data, bufp, sense_length);
8041bdd6c0eSSue Gleeson 		rsp->rsp_sense_data_len = h2b32(sense_length);
8051bdd6c0eSSue Gleeson 		rsp_length += sense_length;
8061bdd6c0eSSue Gleeson 	}
8071bdd6c0eSSue Gleeson 
8081bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L4("stp_send_reponse, sending on ch(%p),"
8091bdd6c0eSSue Gleeson 	    " iu(%p), length(%d)", (void *)iu->iu_ch,
8101bdd6c0eSSue Gleeson 	    (void *)iu, rsp_length);
8111bdd6c0eSSue Gleeson 
812191c289bSCharles Ting 	DTRACE_SRP_4(task__response, srpt_channel_t, iu->iu_ch,
813191c289bSCharles Ting 	    srp_rsp_t, iu->iu_buf, scsi_task_t, iu->iu_stmf_task,
814191c289bSCharles Ting 	    uint8_t, scsi_status);
815191c289bSCharles Ting 
8161bdd6c0eSSue Gleeson 	status = srpt_ch_post_send(iu->iu_ch, iu, rsp_length, fence);
8171bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
8181bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_send_response, post response err(%d)",
8191bdd6c0eSSue Gleeson 		    status);
8201bdd6c0eSSue Gleeson 	}
8211bdd6c0eSSue Gleeson 	return (status);
8221bdd6c0eSSue Gleeson }
8231bdd6c0eSSue Gleeson 
8241bdd6c0eSSue Gleeson /*
8251bdd6c0eSSue Gleeson  * srpt_stp_send_status()
8261bdd6c0eSSue Gleeson  */
8271bdd6c0eSSue Gleeson /* ARGSUSED */
8281bdd6c0eSSue Gleeson stmf_status_t
srpt_stp_send_status(struct scsi_task * task,uint32_t ioflags)8291bdd6c0eSSue Gleeson srpt_stp_send_status(struct scsi_task *task, uint32_t ioflags)
8301bdd6c0eSSue Gleeson {
8311bdd6c0eSSue Gleeson 	srpt_iu_t	*iu;
8321bdd6c0eSSue Gleeson 	ibt_status_t	status;
8331bdd6c0eSSue Gleeson 
8341bdd6c0eSSue Gleeson 	ASSERT(task != NULL);
8351bdd6c0eSSue Gleeson 	iu = task->task_port_private;
8361bdd6c0eSSue Gleeson 
8371bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
8386527ba51SSue Gleeson 
8396527ba51SSue Gleeson 	mutex_enter(&iu->iu_lock);
8406527ba51SSue Gleeson 
8411bdd6c0eSSue Gleeson 	ASSERT(iu->iu_ch != NULL);
8421bdd6c0eSSue Gleeson 
8431bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_send_status, invoked task (%p)"
8441bdd6c0eSSue Gleeson 	    ", task_completion_status (%d)"
8451bdd6c0eSSue Gleeson 	    ", task_resid (%d)"
8461bdd6c0eSSue Gleeson 	    ", task_status_ctrl (%d)"
8471bdd6c0eSSue Gleeson 	    ", task_scsi_status (%d)"
8481bdd6c0eSSue Gleeson 	    ", task_sense_length (%d)"
8491bdd6c0eSSue Gleeson 	    ", task_sense_data (%p)",
8501bdd6c0eSSue Gleeson 	    (void *)task,
8511bdd6c0eSSue Gleeson 	    (int)task->task_completion_status,
8521bdd6c0eSSue Gleeson 	    task->task_resid,
8531bdd6c0eSSue Gleeson 	    task->task_status_ctrl,
8541bdd6c0eSSue Gleeson 	    task->task_scsi_status,
8551bdd6c0eSSue Gleeson 	    task->task_sense_length,
8561bdd6c0eSSue Gleeson 	    (void *)task->task_sense_data);
8571bdd6c0eSSue Gleeson 
858191c289bSCharles Ting 	DTRACE_SRP_4(scsi__response, srpt_channel_t, iu->iu_ch,
859191c289bSCharles Ting 	    srp_rsp_t, iu->iu_buf, scsi_task_t, task,
860191c289bSCharles Ting 	    int8_t, task->task_scsi_status);
861191c289bSCharles Ting 
8626527ba51SSue Gleeson 	if ((iu->iu_flags & (SRPT_IU_STMF_ABORTING |
8636527ba51SSue Gleeson 	    SRPT_IU_SRP_ABORTING | SRPT_IU_ABORTED)) != 0) {
8646527ba51SSue Gleeson 		mutex_exit(&iu->iu_lock);
8656527ba51SSue Gleeson 		return (STMF_FAILURE);
8666527ba51SSue Gleeson 	}
867191c289bSCharles Ting 
8681bdd6c0eSSue Gleeson 	/*
8691bdd6c0eSSue Gleeson 	 * Indicate future aborts can not be initiated (although
8701bdd6c0eSSue Gleeson 	 * we will handle any that have been requested since the
8711bdd6c0eSSue Gleeson 	 * last I/O completed and before we are sending status).
8721bdd6c0eSSue Gleeson 	 */
8731bdd6c0eSSue Gleeson 	iu->iu_flags |= SRPT_IU_RESP_SENT;
8741bdd6c0eSSue Gleeson 
8751bdd6c0eSSue Gleeson 	/*
8761bdd6c0eSSue Gleeson 	 * Send SRP command response or SRP task mgmt response.
8771bdd6c0eSSue Gleeson 	 */
8781bdd6c0eSSue Gleeson 	if (task->task_mgmt_function == 0) {
8791bdd6c0eSSue Gleeson 		uint8_t		rsp_flags = 0;
8801bdd6c0eSSue Gleeson 		uint32_t	resbytes = 0;
8811bdd6c0eSSue Gleeson 
8821bdd6c0eSSue Gleeson 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
8831bdd6c0eSSue Gleeson 			resbytes = task->task_resid;
8841bdd6c0eSSue Gleeson 
8851bdd6c0eSSue Gleeson 			if (task->task_flags & TF_READ_DATA) {
8861bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L3(
8871bdd6c0eSSue Gleeson 				    "stp_send_status, data out overrun");
8881bdd6c0eSSue Gleeson 				rsp_flags |= SRP_RSP_DO_OVER;
8891bdd6c0eSSue Gleeson 			} else if (task->task_flags & TF_WRITE_DATA) {
8901bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L3(
8911bdd6c0eSSue Gleeson 				    "stp_send_status, data in overrun");
8921bdd6c0eSSue Gleeson 				rsp_flags |= SRP_RSP_DI_OVER;
8931bdd6c0eSSue Gleeson 			}
8941bdd6c0eSSue Gleeson 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
8951bdd6c0eSSue Gleeson 			resbytes = task->task_resid;
8961bdd6c0eSSue Gleeson 
8971bdd6c0eSSue Gleeson 			if (task->task_flags & TF_READ_DATA) {
8981bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L3(
8991bdd6c0eSSue Gleeson 				    "stp_send_status, data out underrun");
9001bdd6c0eSSue Gleeson 				rsp_flags |= SRP_RSP_DO_UNDER;
9011bdd6c0eSSue Gleeson 			} else if (task->task_flags & TF_WRITE_DATA) {
9021bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L3(
9031bdd6c0eSSue Gleeson 				    "stp_send_status, data in underrun");
9041bdd6c0eSSue Gleeson 				rsp_flags |= SRP_RSP_DI_UNDER;
9051bdd6c0eSSue Gleeson 			}
9061bdd6c0eSSue Gleeson 		}
9071bdd6c0eSSue Gleeson 
9081bdd6c0eSSue Gleeson 		status = srpt_stp_send_response(iu,
9091bdd6c0eSSue Gleeson 		    task->task_scsi_status, rsp_flags, resbytes,
9101bdd6c0eSSue Gleeson 		    task->task_sense_length, task->task_sense_data, 0);
9111bdd6c0eSSue Gleeson 	} else {
9121bdd6c0eSSue Gleeson 		status = srpt_stp_send_mgmt_response(iu,
9131bdd6c0eSSue Gleeson 		    (task->task_scsi_status ?
9141bdd6c0eSSue Gleeson 		    SRP_TM_FAILED : SRP_TM_SUCCESS),
9151bdd6c0eSSue Gleeson 		    SRPT_FENCE_SEND);
9161bdd6c0eSSue Gleeson 	}
9171bdd6c0eSSue Gleeson 
9181bdd6c0eSSue Gleeson 	/*
9191bdd6c0eSSue Gleeson 	 * If we have an error posting the response return bad status
9201bdd6c0eSSue Gleeson 	 * to STMF and let it initiate an abort for the task.
9211bdd6c0eSSue Gleeson 	 */
9221bdd6c0eSSue Gleeson 	if (status != IBT_SUCCESS) {
9231bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_send_status, post response err(%d)",
9241bdd6c0eSSue Gleeson 		    status);
9256527ba51SSue Gleeson 
9266527ba51SSue Gleeson 		/* clear the response sent flag since it never went out */
9276527ba51SSue Gleeson 		iu->iu_flags &= ~SRPT_IU_RESP_SENT;
9286527ba51SSue Gleeson 
9291bdd6c0eSSue Gleeson 		mutex_exit(&iu->iu_lock);
9301bdd6c0eSSue Gleeson 		return (STMF_FAILURE);
9311bdd6c0eSSue Gleeson 	}
9321bdd6c0eSSue Gleeson 	mutex_exit(&iu->iu_lock);
9331bdd6c0eSSue Gleeson 	return (STMF_SUCCESS);
9341bdd6c0eSSue Gleeson }
9351bdd6c0eSSue Gleeson 
9361bdd6c0eSSue Gleeson /*
9371bdd6c0eSSue Gleeson  * srpt_stp_task_free() - STMF call-back.
9381bdd6c0eSSue Gleeson  */
9391bdd6c0eSSue Gleeson static void
srpt_stp_task_free(struct scsi_task * task)9401bdd6c0eSSue Gleeson srpt_stp_task_free(struct scsi_task *task)
9411bdd6c0eSSue Gleeson {
9421bdd6c0eSSue Gleeson 	srpt_iu_t	*iu;
9431bdd6c0eSSue Gleeson 	srpt_channel_t	*ch;
9441bdd6c0eSSue Gleeson 
9451bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_task_free, invoked task (%p)",
9461bdd6c0eSSue Gleeson 	    (void *)task);
9471bdd6c0eSSue Gleeson 
9481bdd6c0eSSue Gleeson 	iu = task->task_port_private;
9491bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
9501bdd6c0eSSue Gleeson 
9511bdd6c0eSSue Gleeson 	mutex_enter(&iu->iu_lock);
9521bdd6c0eSSue Gleeson 	ch = iu->iu_ch;
9531bdd6c0eSSue Gleeson 	mutex_exit(&iu->iu_lock);
9541bdd6c0eSSue Gleeson 
9551bdd6c0eSSue Gleeson 	ASSERT(ch != NULL);
9561bdd6c0eSSue Gleeson 	ASSERT(ch->ch_session != NULL);
9571bdd6c0eSSue Gleeson 
9581bdd6c0eSSue Gleeson 	/*
9591bdd6c0eSSue Gleeson 	 * Do not hold IU lock while task is being removed from
9601bdd6c0eSSue Gleeson 	 * the session list - possible deadlock if cleaning up
9611bdd6c0eSSue Gleeson 	 * channel when this is called.
9621bdd6c0eSSue Gleeson 	 */
9631bdd6c0eSSue Gleeson 	srpt_stp_remove_task(ch->ch_session, iu);
9641bdd6c0eSSue Gleeson 
9651bdd6c0eSSue Gleeson 	mutex_enter(&iu->iu_lock);
9661bdd6c0eSSue Gleeson 	iu->iu_stmf_task = NULL;
9671bdd6c0eSSue Gleeson 
9681bdd6c0eSSue Gleeson 	srpt_ioc_repost_recv_iu(iu->iu_ioc, iu);
9691bdd6c0eSSue Gleeson 
9701bdd6c0eSSue Gleeson 	mutex_exit(&iu->iu_lock);
9711bdd6c0eSSue Gleeson 
9721bdd6c0eSSue Gleeson 	srpt_ch_release_ref(ch, 0);
9731bdd6c0eSSue Gleeson }
9741bdd6c0eSSue Gleeson 
9751bdd6c0eSSue Gleeson /*
9761bdd6c0eSSue Gleeson  * srpt_stp_abort() - STMF call-back.
9771bdd6c0eSSue Gleeson  */
9781bdd6c0eSSue Gleeson /* ARGSUSED */
9791bdd6c0eSSue Gleeson static stmf_status_t
srpt_stp_abort(struct stmf_local_port * lport,int abort_cmd,void * arg,uint32_t flags)9801bdd6c0eSSue Gleeson srpt_stp_abort(struct stmf_local_port *lport, int abort_cmd,
9811bdd6c0eSSue Gleeson 	void *arg, uint32_t flags)
9821bdd6c0eSSue Gleeson {
9831bdd6c0eSSue Gleeson 	struct scsi_task	*task;
9841bdd6c0eSSue Gleeson 	srpt_iu_t		*iu;
9851bdd6c0eSSue Gleeson 	stmf_status_t		status;
9861bdd6c0eSSue Gleeson 
9871bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_abort, invoked lport (%p), arg (%p)",
9881bdd6c0eSSue Gleeson 	    (void *)lport, (void *)arg);
9891bdd6c0eSSue Gleeson 
9901bdd6c0eSSue Gleeson 	task = (struct scsi_task *)arg;
9911bdd6c0eSSue Gleeson 	ASSERT(task != NULL);
9921bdd6c0eSSue Gleeson 
9931bdd6c0eSSue Gleeson 	iu = (srpt_iu_t *)task->task_port_private;
9941bdd6c0eSSue Gleeson 	ASSERT(iu != NULL);
9951bdd6c0eSSue Gleeson 
9961bdd6c0eSSue Gleeson 	mutex_enter(&iu->iu_lock);
9971bdd6c0eSSue Gleeson 
9981bdd6c0eSSue Gleeson 	/*
9991bdd6c0eSSue Gleeson 	 * If no I/O is outstanding then immediately transition to
10006527ba51SSue Gleeson 	 * aborted state.  If any I/O is in progress OR we've sent the
10016527ba51SSue Gleeson 	 * completion response, then indicate that an STMF abort has been
10026527ba51SSue Gleeson 	 * requested and ask STMF to call us back later to complete the abort.
10031bdd6c0eSSue Gleeson 	 */
10046527ba51SSue Gleeson 	if ((iu->iu_flags & SRPT_IU_RESP_SENT) ||
10056527ba51SSue Gleeson 	    (iu->iu_sq_posted_cnt > 0)) {
10066527ba51SSue Gleeson 		SRPT_DPRINTF_L3("stp_abort, deferring abort request. "
10076527ba51SSue Gleeson 		    "%d outstanding I/O for IU %p",
10086527ba51SSue Gleeson 		    iu->iu_sq_posted_cnt, (void *)iu);
10096527ba51SSue Gleeson 		iu->iu_flags |= SRPT_IU_STMF_ABORTING;
10106527ba51SSue Gleeson 		status = STMF_BUSY;
10116527ba51SSue Gleeson 	} else {
10121bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_abort, no outstanding I/O for %p",
10131bdd6c0eSSue Gleeson 		    (void *)iu);
10141bdd6c0eSSue Gleeson 		iu->iu_flags |= SRPT_IU_ABORTED;
10151bdd6c0eSSue Gleeson 		/* Synchronous abort - STMF will call task_free */
10161bdd6c0eSSue Gleeson 		status = STMF_ABORT_SUCCESS;
10171bdd6c0eSSue Gleeson 	}
10181bdd6c0eSSue Gleeson 
10192d361592SSue Gleeson 	mutex_exit(&iu->iu_lock);
10201bdd6c0eSSue Gleeson 	return (status);
10211bdd6c0eSSue Gleeson }
10221bdd6c0eSSue Gleeson 
10231bdd6c0eSSue Gleeson /*
10241bdd6c0eSSue Gleeson  * srpt_stp_task_poll() - STMF call-back
10251bdd6c0eSSue Gleeson  */
10261bdd6c0eSSue Gleeson static void
srpt_stp_task_poll(struct scsi_task * task)10271bdd6c0eSSue Gleeson srpt_stp_task_poll(struct scsi_task *task)
10281bdd6c0eSSue Gleeson {
10291bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_task_poll, invoked, task (%p)",
10301bdd6c0eSSue Gleeson 	    (void *)task);
10311bdd6c0eSSue Gleeson }
10321bdd6c0eSSue Gleeson 
10331bdd6c0eSSue Gleeson /*
10341bdd6c0eSSue Gleeson  * srpt_stp_ctl() - STMF call-back
10351bdd6c0eSSue Gleeson  */
10361bdd6c0eSSue Gleeson static void
srpt_stp_ctl(struct stmf_local_port * lport,int cmd,void * arg)10371bdd6c0eSSue Gleeson srpt_stp_ctl(struct stmf_local_port *lport, int cmd, void *arg)
10381bdd6c0eSSue Gleeson {
10391bdd6c0eSSue Gleeson 	stmf_state_change_info_t	*sc_info = arg;
10401bdd6c0eSSue Gleeson 	stmf_change_status_t		cstatus;
10411bdd6c0eSSue Gleeson 	stmf_status_t			status;
10421bdd6c0eSSue Gleeson 	srpt_target_port_t		*tgt;
10433baa0db4SSue Gleeson 	char				*why;
10441bdd6c0eSSue Gleeson 
10451bdd6c0eSSue Gleeson 	ASSERT(sc_info != NULL);
10461bdd6c0eSSue Gleeson 	ASSERT(lport != NULL);
10471bdd6c0eSSue Gleeson 
10481bdd6c0eSSue Gleeson 	tgt = lport->lport_port_private;
10491bdd6c0eSSue Gleeson 	ASSERT(tgt->tp_ioc != NULL);
10501bdd6c0eSSue Gleeson 
10513baa0db4SSue Gleeson 	why = sc_info->st_additional_info;
10523baa0db4SSue Gleeson 	if (why == NULL) {
10533baa0db4SSue Gleeson 		why = "<null>";
10543baa0db4SSue Gleeson 	}
10553baa0db4SSue Gleeson 
10563baa0db4SSue Gleeson 	SRPT_DPRINTF_L2("stp_ctl, invoked for LPORT (0x%016llx), cmd (%d), "
10573baa0db4SSue Gleeson 	    "info (%s)", (u_longlong_t)tgt->tp_ibt_svc_id, cmd, why);
10581bdd6c0eSSue Gleeson 
10591bdd6c0eSSue Gleeson 	cstatus.st_completion_status = STMF_SUCCESS;
10601bdd6c0eSSue Gleeson 	cstatus.st_additional_info = NULL;
10611bdd6c0eSSue Gleeson 
10621bdd6c0eSSue Gleeson 	switch (cmd) {
10631bdd6c0eSSue Gleeson 	case STMF_CMD_LPORT_ONLINE:
10641bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_ctl, LPORT_ONLINE command,"
10651bdd6c0eSSue Gleeson 		    " st_rflags(0x%llx)", (u_longlong_t)sc_info->st_rflags);
10661bdd6c0eSSue Gleeson 		/*
10671bdd6c0eSSue Gleeson 		 * If the SCSI Target Port is not enabled by the driver,
10681bdd6c0eSSue Gleeson 		 * don't start and instead return busy.  This is a
10691bdd6c0eSSue Gleeson 		 * creation/destruction transitional state and the will
10701bdd6c0eSSue Gleeson 		 * either go away or become enabled.
10711bdd6c0eSSue Gleeson 		 */
10721bdd6c0eSSue Gleeson 		mutex_enter(&tgt->tp_lock);
10733baa0db4SSue Gleeson 
10743baa0db4SSue Gleeson 		tgt->tp_requested_state = SRPT_TGT_STATE_ONLINE;
10753baa0db4SSue Gleeson 
10761bdd6c0eSSue Gleeson 		if (tgt->tp_drv_disabled != 0) {
10771bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("stp_ctl, set LPORT_ONLINE failed - "
10781bdd6c0eSSue Gleeson 			    "LPORT (0x%016llx) BUSY",
10791bdd6c0eSSue Gleeson 			    (u_longlong_t)tgt->tp_ibt_svc_id);
10801bdd6c0eSSue Gleeson 			cstatus.st_completion_status = STMF_BUSY;
10813baa0db4SSue Gleeson 		} else if ((tgt->tp_state == SRPT_TGT_STATE_ONLINE) ||
10823baa0db4SSue Gleeson 		    (tgt->tp_state == SRPT_TGT_STATE_ONLINING)) {
10831bdd6c0eSSue Gleeson 			cstatus.st_completion_status = STMF_ALREADY;
10841bdd6c0eSSue Gleeson 		} else if (tgt->tp_state != SRPT_TGT_STATE_OFFLINE) {
10851bdd6c0eSSue Gleeson 			cstatus.st_completion_status = STMF_INVALID_ARG;
10861bdd6c0eSSue Gleeson 		} else {
10871bdd6c0eSSue Gleeson 			tgt->tp_state = SRPT_TGT_STATE_ONLINING;
10881bdd6c0eSSue Gleeson 			status = srpt_stp_start_srp(tgt);
10893baa0db4SSue Gleeson 			if (status != IBT_SUCCESS) {
10901bdd6c0eSSue Gleeson 				tgt->tp_state = SRPT_TGT_STATE_OFFLINE;
10911bdd6c0eSSue Gleeson 				cstatus.st_completion_status = STMF_INVALID_ARG;
10923baa0db4SSue Gleeson 				if (tgt->tp_num_active_ports == 0) {
10933baa0db4SSue Gleeson 					SRPT_DPRINTF_L1(
10943baa0db4SSue Gleeson 					    "stp_ctl, no ports active "
10953baa0db4SSue Gleeson 					    "for HCA 0x%016llx. Target will "
10963baa0db4SSue Gleeson 					    "not be placed online.",
10973baa0db4SSue Gleeson 					    (u_longlong_t)tgt->tp_ibt_svc_id);
10983baa0db4SSue Gleeson 				}
10991bdd6c0eSSue Gleeson 			}
11001bdd6c0eSSue Gleeson 		}
11011bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_lock);
11021bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_ctl, (0x%016llx) LPORT_ONLINE command"
11031bdd6c0eSSue Gleeson 		    " status (0x%llx)", (u_longlong_t)tgt->tp_ibt_svc_id,
11041bdd6c0eSSue Gleeson 		    (u_longlong_t)cstatus.st_completion_status);
11051bdd6c0eSSue Gleeson 		status = stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport,
11061bdd6c0eSSue Gleeson 		    &cstatus);
11071bdd6c0eSSue Gleeson 		if (status != STMF_SUCCESS) {
11081bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("stp_ctl, ONLINE_COMPLETE returned"
11091bdd6c0eSSue Gleeson 			    " error(0x%llx)", (u_longlong_t)status);
11101bdd6c0eSSue Gleeson 		}
11111bdd6c0eSSue Gleeson 		break;
11121bdd6c0eSSue Gleeson 
11131bdd6c0eSSue Gleeson 	case STMF_CMD_LPORT_OFFLINE:
11143baa0db4SSue Gleeson 		SRPT_DPRINTF_L2("stp_ctl, LPORT_OFFLINE command,"
11153baa0db4SSue Gleeson 		    " st_rflags(0x%llx)", (u_longlong_t)sc_info->st_rflags);
11161bdd6c0eSSue Gleeson 		mutex_enter(&tgt->tp_lock);
11173baa0db4SSue Gleeson 
11183baa0db4SSue Gleeson 		/*
11193baa0db4SSue Gleeson 		 * Only keep persistent state if explicitly requested by user
11203baa0db4SSue Gleeson 		 * action, such as stmfadm offline-target or
11213baa0db4SSue Gleeson 		 * svcadm disable stmf.
11223baa0db4SSue Gleeson 		 * If not requested by the user, this was likely triggered by
11233baa0db4SSue Gleeson 		 * not having any HCA ports active.
11243baa0db4SSue Gleeson 		 */
11253baa0db4SSue Gleeson 		if (sc_info->st_rflags & STMF_RFLAG_USER_REQUEST) {
11263baa0db4SSue Gleeson 			tgt->tp_requested_state = SRPT_TGT_STATE_OFFLINE;
11273baa0db4SSue Gleeson 		}
11283baa0db4SSue Gleeson 
11293baa0db4SSue Gleeson 		if ((tgt->tp_state == SRPT_TGT_STATE_OFFLINE) ||
11303baa0db4SSue Gleeson 		    (tgt->tp_state == SRPT_TGT_STATE_OFFLINING)) {
11311bdd6c0eSSue Gleeson 			cstatus.st_completion_status = STMF_ALREADY;
11321bdd6c0eSSue Gleeson 		} else if (tgt->tp_state != SRPT_TGT_STATE_ONLINE) {
11331bdd6c0eSSue Gleeson 			cstatus.st_completion_status = STMF_INVALID_ARG;
11341bdd6c0eSSue Gleeson 		} else {
11351bdd6c0eSSue Gleeson 			tgt->tp_state = SRPT_TGT_STATE_OFFLINING;
11361bdd6c0eSSue Gleeson 			srpt_stp_stop_srp(tgt);
11371bdd6c0eSSue Gleeson 		}
11381bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_lock);
11391bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L3("stp_ctl, notify STMF OFFLINE complete"
11401bdd6c0eSSue Gleeson 		    " (0x%016llx)", (u_longlong_t)tgt->tp_ibt_svc_id);
11411bdd6c0eSSue Gleeson 		status = stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
11421bdd6c0eSSue Gleeson 		    lport, &cstatus);
11431bdd6c0eSSue Gleeson 		if (status != STMF_SUCCESS) {
11441bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L1("stp_ctl, OFFLINE_COMPLETE returned"
11451bdd6c0eSSue Gleeson 			    " error(0x%llx)", (u_longlong_t)status);
11461bdd6c0eSSue Gleeson 		}
11471bdd6c0eSSue Gleeson 		break;
11481bdd6c0eSSue Gleeson 
11491bdd6c0eSSue Gleeson 	case STMF_ACK_LPORT_ONLINE_COMPLETE:
11501bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_ctl, LPORT_ONLINE_COMPLETE ACK from"
11511bdd6c0eSSue Gleeson 		    " STMF");
11521bdd6c0eSSue Gleeson 		mutex_enter(&tgt->tp_lock);
11531bdd6c0eSSue Gleeson 		if (tgt->tp_state == SRPT_TGT_STATE_ONLINING) {
11541bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_ctl, LPORT is ONLINE");
11551bdd6c0eSSue Gleeson 			tgt->tp_state = SRPT_TGT_STATE_ONLINE;
11561bdd6c0eSSue Gleeson 		} else {
11571bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_ctl, LPORT not on-lining");
11581bdd6c0eSSue Gleeson 		}
11591bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_lock);
11601bdd6c0eSSue Gleeson 		break;
11611bdd6c0eSSue Gleeson 
11621bdd6c0eSSue Gleeson 	case STMF_ACK_LPORT_OFFLINE_COMPLETE:
11631bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_ctl, LPORT_OFFLINE_COMPLETE ACK from"
11641bdd6c0eSSue Gleeson 		    " STMF");
11651bdd6c0eSSue Gleeson 		mutex_enter(&tgt->tp_lock);
11661bdd6c0eSSue Gleeson 		if (tgt->tp_state == SRPT_TGT_STATE_OFFLINING) {
11671bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_ctl, LPORT is OFFLINE");
11681bdd6c0eSSue Gleeson 			tgt->tp_state = SRPT_TGT_STATE_OFFLINE;
11691bdd6c0eSSue Gleeson 			cv_broadcast(&tgt->tp_offline_complete);
11701bdd6c0eSSue Gleeson 		} else {
11711bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_ctl, LPORT not off-lining");
11721bdd6c0eSSue Gleeson 		}
11731bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_lock);
11741bdd6c0eSSue Gleeson 		break;
11751bdd6c0eSSue Gleeson 
11761bdd6c0eSSue Gleeson 	default:
11771bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_ctl, cmd (%d) not handled",
11781bdd6c0eSSue Gleeson 		    cmd);
11791bdd6c0eSSue Gleeson 		break;
11801bdd6c0eSSue Gleeson 	}
11811bdd6c0eSSue Gleeson }
11821bdd6c0eSSue Gleeson 
11831bdd6c0eSSue Gleeson /*
11841bdd6c0eSSue Gleeson  * srpt_stp_info() - STMF call-back
11851bdd6c0eSSue Gleeson  */
11861bdd6c0eSSue Gleeson /* ARGSUSED */
11871bdd6c0eSSue Gleeson static stmf_status_t
srpt_stp_info(uint32_t cmd,struct stmf_local_port * lport,void * arg,uint8_t * buf,uint32_t * bufsizep)11881bdd6c0eSSue Gleeson srpt_stp_info(uint32_t cmd, struct stmf_local_port *lport,
11891bdd6c0eSSue Gleeson 	void *arg, uint8_t *buf, uint32_t *bufsizep)
11901bdd6c0eSSue Gleeson {
11911bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_info, invoked");
11921bdd6c0eSSue Gleeson 	return (STMF_SUCCESS);
11931bdd6c0eSSue Gleeson }
11941bdd6c0eSSue Gleeson 
11951bdd6c0eSSue Gleeson /*
11961bdd6c0eSSue Gleeson  * srpt_stp_event_handler() - STMF call-back
11971bdd6c0eSSue Gleeson  */
11981bdd6c0eSSue Gleeson /* ARGSUSED */
11991bdd6c0eSSue Gleeson static void
srpt_stp_event_handler(struct stmf_local_port * lport,int eventid,void * arg,uint32_t flags)12001bdd6c0eSSue Gleeson srpt_stp_event_handler(struct stmf_local_port *lport, int eventid,
12011bdd6c0eSSue Gleeson 	void *arg, uint32_t flags)
12021bdd6c0eSSue Gleeson {
12031bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_event_handler, invoked");
12041bdd6c0eSSue Gleeson }
12051bdd6c0eSSue Gleeson 
12061bdd6c0eSSue Gleeson /*
12071bdd6c0eSSue Gleeson  * srpt_stp_alloc_scsi_devid_desc()
12081bdd6c0eSSue Gleeson  *
12091bdd6c0eSSue Gleeson  * Allocate and initialize a SCSI device ID descriptor for
12101bdd6c0eSSue Gleeson  * the SRP protocol.  Names are eui.GUID format.
12111bdd6c0eSSue Gleeson  *
12121bdd6c0eSSue Gleeson  * Both extension and guid are passed in host order.
12131bdd6c0eSSue Gleeson  */
12141bdd6c0eSSue Gleeson static scsi_devid_desc_t *
srpt_stp_alloc_scsi_devid_desc(uint64_t guid)12151bdd6c0eSSue Gleeson srpt_stp_alloc_scsi_devid_desc(uint64_t guid)
12161bdd6c0eSSue Gleeson {
12171bdd6c0eSSue Gleeson 	scsi_devid_desc_t	*sdd;
12181bdd6c0eSSue Gleeson 
12191bdd6c0eSSue Gleeson 	sdd = kmem_zalloc(sizeof (*sdd) + SRPT_EUI_ID_LEN + 1, KM_SLEEP);
12201bdd6c0eSSue Gleeson 	sdd->protocol_id = PROTOCOL_SRP;
12211bdd6c0eSSue Gleeson 	sdd->piv = 1;
12221bdd6c0eSSue Gleeson 	sdd->code_set = CODE_SET_ASCII;
12231bdd6c0eSSue Gleeson 	sdd->association = ID_IS_TARGET_PORT;
12241bdd6c0eSSue Gleeson 	sdd->ident_length = SRPT_EUI_ID_LEN;
12251bdd6c0eSSue Gleeson 	(void) sprintf((char *)sdd->ident, "eui.%016llX", (u_longlong_t)guid);
12261bdd6c0eSSue Gleeson 	return (sdd);
12271bdd6c0eSSue Gleeson }
12281bdd6c0eSSue Gleeson 
12291bdd6c0eSSue Gleeson /*
12301bdd6c0eSSue Gleeson  * srpt_stp_free_scsi_devid_desc()
12311bdd6c0eSSue Gleeson  *
12321bdd6c0eSSue Gleeson  * Free a SRPT SCSI device ID descriptor previously allocated via
12331bdd6c0eSSue Gleeson  * srpt_stp_alloc_scsi_devid_desc().
12341bdd6c0eSSue Gleeson  */
12351bdd6c0eSSue Gleeson static void
srpt_stp_free_scsi_devid_desc(scsi_devid_desc_t * sdd)12361bdd6c0eSSue Gleeson srpt_stp_free_scsi_devid_desc(scsi_devid_desc_t *sdd)
12371bdd6c0eSSue Gleeson {
12381bdd6c0eSSue Gleeson 	kmem_free(sdd, sizeof (*sdd) + SRPT_EUI_ID_LEN + 1);
12391bdd6c0eSSue Gleeson }
12401bdd6c0eSSue Gleeson 
12411bdd6c0eSSue Gleeson /*
12421bdd6c0eSSue Gleeson  * srpt_stp_alloc_session()
12431bdd6c0eSSue Gleeson  */
12441bdd6c0eSSue Gleeson srpt_session_t *
srpt_stp_alloc_session(srpt_target_port_t * tgt,uint8_t * i_id,uint8_t * t_id,uint8_t port,char * local_gid,char * remote_gid)12451bdd6c0eSSue Gleeson srpt_stp_alloc_session(srpt_target_port_t *tgt,
1246191c289bSCharles Ting 	uint8_t *i_id, uint8_t *t_id, uint8_t port,
1247191c289bSCharles Ting 	char *local_gid, char *remote_gid)
12481bdd6c0eSSue Gleeson {
12491bdd6c0eSSue Gleeson 	stmf_status_t		status;
12501bdd6c0eSSue Gleeson 	srpt_session_t		*ss;
12511bdd6c0eSSue Gleeson 	stmf_scsi_session_t	*stmf_ss;
12521bdd6c0eSSue Gleeson 	uint64_t		i_guid;
1253*716c1805SNattuvetty Bhavyan 	scsi_srp_transport_id_t *srptpd;
12541bdd6c0eSSue Gleeson 
12551bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
12561bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_alloc_session, invoked");
12571bdd6c0eSSue Gleeson 
12581bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_sess_list_lock);
12591bdd6c0eSSue Gleeson 
12601bdd6c0eSSue Gleeson 	i_guid = BE_IN64(&i_id[8]);
12611bdd6c0eSSue Gleeson 
12621bdd6c0eSSue Gleeson 	stmf_ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION,
12631bdd6c0eSSue Gleeson 	    sizeof (srpt_session_t), 0);
12641bdd6c0eSSue Gleeson 	if (stmf_ss == NULL) {
12651bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_alloc_session, stmf_alloc"
12661bdd6c0eSSue Gleeson 		    " returned NULL");
12671bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_sess_list_lock);
12681bdd6c0eSSue Gleeson 		return (NULL);
12691bdd6c0eSSue Gleeson 	}
12701bdd6c0eSSue Gleeson 	ss = stmf_ss->ss_port_private;
12711bdd6c0eSSue Gleeson 	ASSERT(ss != NULL);
12721bdd6c0eSSue Gleeson 
12731bdd6c0eSSue Gleeson 	rw_init(&ss->ss_rwlock, NULL, RW_DRIVER, NULL);
12741bdd6c0eSSue Gleeson 	list_create(&ss->ss_task_list, sizeof (srpt_iu_t),
12751bdd6c0eSSue Gleeson 	    offsetof(srpt_iu_t, iu_ss_task_node));
12761bdd6c0eSSue Gleeson 
12771bdd6c0eSSue Gleeson 	stmf_ss->ss_rport_id = srpt_stp_alloc_scsi_devid_desc(i_guid);
1278*716c1805SNattuvetty Bhavyan 	/* Setup remote port transport id */
1279*716c1805SNattuvetty Bhavyan 	stmf_ss->ss_rport = stmf_remote_port_alloc(
1280*716c1805SNattuvetty Bhavyan 	    sizeof (scsi_srp_transport_id_t));
1281*716c1805SNattuvetty Bhavyan 	stmf_ss->ss_rport->rport_tptid->protocol_id = PROTOCOL_SRP;
1282*716c1805SNattuvetty Bhavyan 	stmf_ss->ss_rport->rport_tptid->format_code = 0;
1283*716c1805SNattuvetty Bhavyan 	srptpd = (scsi_srp_transport_id_t *)stmf_ss->ss_rport->rport_tptid;
1284*716c1805SNattuvetty Bhavyan 	bcopy(i_id, srptpd->srp_name, SRP_PORT_ID_LEN);
1285*716c1805SNattuvetty Bhavyan 
12861bdd6c0eSSue Gleeson 	stmf_ss->ss_lport    = tgt->tp_lport;
12871bdd6c0eSSue Gleeson 
12881bdd6c0eSSue Gleeson 	ss->ss_ss	= stmf_ss;
12891bdd6c0eSSue Gleeson 	ss->ss_hw_port	= port;
12901bdd6c0eSSue Gleeson 	ss->ss_tgt	= tgt;
12911bdd6c0eSSue Gleeson 	bcopy(i_id, ss->ss_i_id, SRP_PORT_ID_LEN);
12921bdd6c0eSSue Gleeson 	bcopy(t_id, ss->ss_t_id, SRP_PORT_ID_LEN);
12931bdd6c0eSSue Gleeson 
12941bdd6c0eSSue Gleeson 	/*
12951bdd6c0eSSue Gleeson 	 * Set the alias to include the initiator extension, this will enable
12961bdd6c0eSSue Gleeson 	 * the administrator to identify multiple unique sessions originating
12971bdd6c0eSSue Gleeson 	 * from the same initiator.
12981bdd6c0eSSue Gleeson 	 */
1299191c289bSCharles Ting 	(void) strlcpy(ss->ss_i_gid, remote_gid, SRPT_ALIAS_LEN);
1300191c289bSCharles Ting 	(void) strlcpy(ss->ss_t_gid, local_gid, SRPT_ALIAS_LEN);
1301191c289bSCharles Ting 	EUI_STR(ss->ss_i_name, BE_IN64(&ss->ss_i_id[8]));
1302191c289bSCharles Ting 	EUI_STR(ss->ss_t_name, BE_IN64(&ss->ss_t_id[0]));
1303191c289bSCharles Ting 	ALIAS_STR(ss->ss_i_alias, BE_IN64(&ss->ss_i_id[0]),
1304191c289bSCharles Ting 	    BE_IN64(&ss->ss_i_id[8]));
1305191c289bSCharles Ting 	ALIAS_STR(ss->ss_t_alias, BE_IN64(&ss->ss_t_id[0]),
1306191c289bSCharles Ting 	    BE_IN64(&ss->ss_t_id[8]));
1307191c289bSCharles Ting 	stmf_ss->ss_rport_alias = ss->ss_i_alias;
13081bdd6c0eSSue Gleeson 
13091bdd6c0eSSue Gleeson 	status = stmf_register_scsi_session(tgt->tp_lport, stmf_ss);
13101bdd6c0eSSue Gleeson 	if (status != STMF_SUCCESS) {
13111bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_alloc_session, STMF register session"
13121bdd6c0eSSue Gleeson 		    " err(0x%llx)", (u_longlong_t)status);
13131bdd6c0eSSue Gleeson 		list_destroy(&ss->ss_task_list);
13141bdd6c0eSSue Gleeson 		rw_destroy(&ss->ss_rwlock);
1315*716c1805SNattuvetty Bhavyan 		srpt_stp_free_scsi_devid_desc(stmf_ss->ss_rport_id);
1316*716c1805SNattuvetty Bhavyan 		stmf_remote_port_free(stmf_ss->ss_rport);
13171bdd6c0eSSue Gleeson 		stmf_free(stmf_ss);
13181bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_sess_list_lock);
13191bdd6c0eSSue Gleeson 		return (NULL);
13201bdd6c0eSSue Gleeson 	}
13211bdd6c0eSSue Gleeson 
13221bdd6c0eSSue Gleeson 	list_insert_tail(&tgt->tp_sess_list, ss);
13231bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_sess_list_lock);
13241bdd6c0eSSue Gleeson 	return (ss);
13251bdd6c0eSSue Gleeson }
13261bdd6c0eSSue Gleeson 
13271bdd6c0eSSue Gleeson /*
13281bdd6c0eSSue Gleeson  * srpt_stp_free_session()
13291bdd6c0eSSue Gleeson  */
13301bdd6c0eSSue Gleeson void
srpt_stp_free_session(srpt_session_t * session)13311bdd6c0eSSue Gleeson srpt_stp_free_session(srpt_session_t *session)
13321bdd6c0eSSue Gleeson {
13331bdd6c0eSSue Gleeson 	stmf_scsi_session_t	*stmf_ss;
13341bdd6c0eSSue Gleeson 	srpt_target_port_t	*tgt;
13351bdd6c0eSSue Gleeson 
13361bdd6c0eSSue Gleeson 	ASSERT(session != NULL);
13371bdd6c0eSSue Gleeson 
13381bdd6c0eSSue Gleeson 	tgt = session->ss_tgt;
13391bdd6c0eSSue Gleeson 
13401bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
13411bdd6c0eSSue Gleeson 
13421bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L3("stp_free_session, invoked");
13431bdd6c0eSSue Gleeson 
13441bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_sess_list_lock);
13451bdd6c0eSSue Gleeson 
13461bdd6c0eSSue Gleeson 	stmf_ss = session->ss_ss;
13471bdd6c0eSSue Gleeson 
13481bdd6c0eSSue Gleeson 	list_destroy(&session->ss_task_list);
13491bdd6c0eSSue Gleeson 	rw_destroy(&session->ss_rwlock);
13501bdd6c0eSSue Gleeson 
13511bdd6c0eSSue Gleeson 	stmf_deregister_scsi_session(tgt->tp_lport, stmf_ss);
13521bdd6c0eSSue Gleeson 	srpt_stp_free_scsi_devid_desc(stmf_ss->ss_rport_id);
1353*716c1805SNattuvetty Bhavyan 	stmf_remote_port_free(stmf_ss->ss_rport);
13541bdd6c0eSSue Gleeson 	list_remove(&tgt->tp_sess_list, session);
13551bdd6c0eSSue Gleeson 	cv_signal(&tgt->tp_sess_complete);
13561bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_sess_list_lock);
13571bdd6c0eSSue Gleeson 	stmf_free(stmf_ss);
13581bdd6c0eSSue Gleeson }
13591bdd6c0eSSue Gleeson 
13601bdd6c0eSSue Gleeson /*
13611bdd6c0eSSue Gleeson  * srpt_stp_login() - SRP SCSI Target port login
13621bdd6c0eSSue Gleeson  */
13631bdd6c0eSSue Gleeson srpt_channel_t *
srpt_stp_login(srpt_target_port_t * tgt,srp_login_req_t * login,srp_login_rsp_t * login_rsp,srp_login_rej_t * login_rej,uint8_t login_port,char * local_gid,char * remote_gid)13641bdd6c0eSSue Gleeson srpt_stp_login(srpt_target_port_t *tgt, srp_login_req_t *login,
13651bdd6c0eSSue Gleeson 	srp_login_rsp_t *login_rsp, srp_login_rej_t *login_rej,
1366191c289bSCharles Ting 	uint8_t login_port, char *local_gid, char *remote_gid)
13671bdd6c0eSSue Gleeson {
13681bdd6c0eSSue Gleeson 	uint32_t	reason;
13691bdd6c0eSSue Gleeson 	uint32_t	req_it_ui_len;
13701bdd6c0eSSue Gleeson 	uint8_t		rsp_flags;
13711bdd6c0eSSue Gleeson 	srpt_ioc_t	*ioc;
13721bdd6c0eSSue Gleeson 	srpt_channel_t	*ch = NULL;
13731bdd6c0eSSue Gleeson 	srpt_channel_t	*next_ch = NULL;
13741bdd6c0eSSue Gleeson 	srpt_session_t	*session = NULL;
1375191c289bSCharles Ting 	srpt_session_t	sess;
13761bdd6c0eSSue Gleeson 
13771bdd6c0eSSue Gleeson 	ASSERT(tgt != NULL);
13781bdd6c0eSSue Gleeson 	ASSERT(login != NULL);
13791bdd6c0eSSue Gleeson 	ASSERT(login_rsp != NULL);
13801bdd6c0eSSue Gleeson 	ASSERT(login_rej != NULL);
13811bdd6c0eSSue Gleeson 
1382191c289bSCharles Ting 	/* Store the string representation of connection info */
1383191c289bSCharles Ting 	/* for Dtrace probes */
1384191c289bSCharles Ting 	bzero(&sess, sizeof (srpt_session_t));
1385191c289bSCharles Ting 	(void) strlcpy(sess.ss_i_gid, remote_gid, SRPT_ALIAS_LEN);
1386191c289bSCharles Ting 	(void) strlcpy(sess.ss_t_gid, local_gid, SRPT_ALIAS_LEN);
1387191c289bSCharles Ting 	EUI_STR(sess.ss_i_name,
1388191c289bSCharles Ting 	    BE_IN64(&login->lreq_initiator_port_id[8]));
1389191c289bSCharles Ting 	EUI_STR(sess.ss_t_name,
1390191c289bSCharles Ting 	    BE_IN64(&login->lreq_target_port_id[0]));
1391191c289bSCharles Ting 	ALIAS_STR(sess.ss_i_alias,
1392191c289bSCharles Ting 	    BE_IN64(&login->lreq_initiator_port_id[0]),
1393191c289bSCharles Ting 	    BE_IN64(&login->lreq_initiator_port_id[8]));
1394191c289bSCharles Ting 	ALIAS_STR(sess.ss_t_alias,
1395191c289bSCharles Ting 	    BE_IN64(&login->lreq_target_port_id[0]),
1396191c289bSCharles Ting 	    BE_IN64(&login->lreq_target_port_id[8]));
1397191c289bSCharles Ting 
1398191c289bSCharles Ting 	DTRACE_SRP_2(login__command, srpt_session_t, &sess,
1399191c289bSCharles Ting 	    srp_login_req_t, login);
1400191c289bSCharles Ting 
14011bdd6c0eSSue Gleeson 	/*
14021bdd6c0eSSue Gleeson 	 * The target lock taken here serializes logins to this target
14031bdd6c0eSSue Gleeson 	 * and prevents an STMF target port from starting a control
14041bdd6c0eSSue Gleeson 	 * operation to transition the target state while a login is
14051bdd6c0eSSue Gleeson 	 * being processed.
14061bdd6c0eSSue Gleeson 	 */
1407191c289bSCharles Ting 	bzero(login_rsp, sizeof (srp_login_rsp_t));
1408191c289bSCharles Ting 	bzero(login_rej, sizeof (srp_login_rej_t));
14091bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_lock);
14101bdd6c0eSSue Gleeson 	ioc = tgt->tp_ioc;
14111bdd6c0eSSue Gleeson 	if (ioc == NULL) {
14121bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L1("stp_login, NULL I/O Controller");
14131bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_UNABLE_TO_ASSOCIATE_I_T_NEXUS;
14141bdd6c0eSSue Gleeson 		goto reject_login;
14151bdd6c0eSSue Gleeson 	}
14161bdd6c0eSSue Gleeson 
14171bdd6c0eSSue Gleeson 	/*
14181bdd6c0eSSue Gleeson 	 * Validate that the SRP Target ID in the login request specifies
14191bdd6c0eSSue Gleeson 	 * this I/O Controller SCSI Target Port.
14201bdd6c0eSSue Gleeson 	 */
14211bdd6c0eSSue Gleeson 	if (memcmp(login->lreq_target_port_id, tgt->tp_srp_port_id,
14221bdd6c0eSSue Gleeson 	    SRP_PORT_ID_LEN) != 0) {
14231bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, SRP CM SVC target ID mismatch."
14241bdd6c0eSSue Gleeson 		    " Incoming TgtID 0x%016llx:0x%016llx",
14251bdd6c0eSSue Gleeson 		    (u_longlong_t)BE_IN64(&login->lreq_target_port_id[0]),
14261bdd6c0eSSue Gleeson 		    (u_longlong_t)BE_IN64(&login->lreq_target_port_id[8]));
14271bdd6c0eSSue Gleeson 
14281bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_UNABLE_TO_ASSOCIATE_I_T_NEXUS;
14291bdd6c0eSSue Gleeson 		goto reject_login;
14301bdd6c0eSSue Gleeson 	}
14311bdd6c0eSSue Gleeson 
14321bdd6c0eSSue Gleeson 	if (tgt->tp_state != SRPT_TGT_STATE_ONLINE) {
14331bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, SRP Login target not on-line");
14341bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_UNABLE_TO_ASSOCIATE_I_T_NEXUS;
14351bdd6c0eSSue Gleeson 		goto reject_login;
14361bdd6c0eSSue Gleeson 	}
14371bdd6c0eSSue Gleeson 
14381bdd6c0eSSue Gleeson 	/*
14391bdd6c0eSSue Gleeson 	 * Initiator requested IU size must be as large as the specification
14401bdd6c0eSSue Gleeson 	 * minimum and no greater than what we chose to support.
14411bdd6c0eSSue Gleeson 	 */
14421bdd6c0eSSue Gleeson 	req_it_ui_len = b2h32(login->lreq_req_it_iu_len);
14431bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_login, requested iu size = %d", req_it_ui_len);
1444989ca640SSue Gleeson 	if (req_it_ui_len > srpt_iu_size) {
14451bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, SRP Login IU size (%d) too large",
14461bdd6c0eSSue Gleeson 		    req_it_ui_len);
14471bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE;
14481bdd6c0eSSue Gleeson 		goto reject_login;
14491bdd6c0eSSue Gleeson 	}
14501bdd6c0eSSue Gleeson 	if (req_it_ui_len < SRP_MIN_IU_SIZE) {
14511bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, SRP Login IU size (%d) too small",
14521bdd6c0eSSue Gleeson 		    req_it_ui_len);
14531bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_NO_REASON;
14541bdd6c0eSSue Gleeson 		goto reject_login;
14551bdd6c0eSSue Gleeson 	}
14561bdd6c0eSSue Gleeson 
14571bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_login, login req InitID 0x%016llx:0x%016llx",
14581bdd6c0eSSue Gleeson 	    (u_longlong_t)BE_IN64(&login->lreq_initiator_port_id[0]),
14591bdd6c0eSSue Gleeson 	    (u_longlong_t)BE_IN64(&login->lreq_initiator_port_id[8]));
14601bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_login, login req TgtID 0x%016llx:0x%016llx",
14611bdd6c0eSSue Gleeson 	    (u_longlong_t)BE_IN64(&login->lreq_target_port_id[0]),
14621bdd6c0eSSue Gleeson 	    (u_longlong_t)BE_IN64(&login->lreq_target_port_id[8]));
14631bdd6c0eSSue Gleeson 
14641bdd6c0eSSue Gleeson 	/*
14651bdd6c0eSSue Gleeson 	 * Processing is based on either single channel or multi-channel
14661bdd6c0eSSue Gleeson 	 * operation.  In single channel, all current logins for this
14671bdd6c0eSSue Gleeson 	 * same I_T_Nexus should be logged out.  In multi-channel
14681bdd6c0eSSue Gleeson 	 * mode we would add an additional channel to an existing
14691bdd6c0eSSue Gleeson 	 * I_T_Nexus if one currently exists (i.e. reference the
14701bdd6c0eSSue Gleeson 	 * same SCSI session).
14711bdd6c0eSSue Gleeson 	 */
14721bdd6c0eSSue Gleeson 	rsp_flags = SRP_MULTI_CH_RESULT_NO_EXISTING;
14731bdd6c0eSSue Gleeson 
14741bdd6c0eSSue Gleeson 	switch (login->lreq_req_flags & SRP_LOGIN_MULTI_CH_MASK) {
14751bdd6c0eSSue Gleeson 
14761bdd6c0eSSue Gleeson 	case SRP_LOGIN_MULTI_CH_SINGLE:
14771bdd6c0eSSue Gleeson 		/*
14781bdd6c0eSSue Gleeson 		 * Only a single channel may be associated with a I_T_Nexus.
14791bdd6c0eSSue Gleeson 		 * Disconnect any channel with the same SRP Initiator and
14801bdd6c0eSSue Gleeson 		 * SRP target IDs.
14811bdd6c0eSSue Gleeson 		 */
14821bdd6c0eSSue Gleeson 		mutex_enter(&tgt->tp_ch_list_lock);
14831bdd6c0eSSue Gleeson 		ch = list_head(&tgt->tp_ch_list);
14841bdd6c0eSSue Gleeson 		while (ch != NULL) {
14851bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L3("stp_login, compare session,"
14861bdd6c0eSSue Gleeson 			    " ch_state(%d)", ch->ch_state);
14871bdd6c0eSSue Gleeson 			next_ch = list_next(&tgt->tp_ch_list, ch);
14881bdd6c0eSSue Gleeson 
14891bdd6c0eSSue Gleeson 			if (ch->ch_state != SRPT_CHANNEL_CONNECTING &&
14901bdd6c0eSSue Gleeson 			    ch->ch_state != SRPT_CHANNEL_CONNECTED) {
14911bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L3("stp_login, compare session,"
14921bdd6c0eSSue Gleeson 				    " channel not active");
14931bdd6c0eSSue Gleeson 				ch = next_ch;
14941bdd6c0eSSue Gleeson 				continue;
14951bdd6c0eSSue Gleeson 			}
14961bdd6c0eSSue Gleeson 
14971bdd6c0eSSue Gleeson 			ASSERT(ch->ch_session != NULL);
14981bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L3("stp_login, compare session"
14991bdd6c0eSSue Gleeson 			    " I_ID 0x%016llx:0x%016llx",
15001bdd6c0eSSue Gleeson 			    (u_longlong_t)b2h64(*((uint64_t *)(void *)
15011bdd6c0eSSue Gleeson 			    &ch->ch_session->ss_i_id[0])),
15021bdd6c0eSSue Gleeson 			    (u_longlong_t)b2h64(*((uint64_t *)(void *)
15031bdd6c0eSSue Gleeson 			    &ch->ch_session->ss_i_id[8])));
15041bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L3("stp_login, compare session"
15051bdd6c0eSSue Gleeson 			    " T_ID 0x%016llx:0x%016llx",
15061bdd6c0eSSue Gleeson 			    (u_longlong_t)b2h64(*((uint64_t *)(void *)
15071bdd6c0eSSue Gleeson 			    &ch->ch_session->ss_t_id[0])),
15081bdd6c0eSSue Gleeson 			    (u_longlong_t)b2h64(*((uint64_t *)(void *)
15091bdd6c0eSSue Gleeson 			    &ch->ch_session->ss_t_id[8])));
15101bdd6c0eSSue Gleeson 			if ((bcmp(login->lreq_initiator_port_id,
15111bdd6c0eSSue Gleeson 			    ch->ch_session->ss_i_id,
15121bdd6c0eSSue Gleeson 			    SRP_PORT_ID_LEN) == 0) &&
15131bdd6c0eSSue Gleeson 			    (bcmp(login->lreq_target_port_id,
15141bdd6c0eSSue Gleeson 			    ch->ch_session->ss_t_id,
15151bdd6c0eSSue Gleeson 			    SRP_PORT_ID_LEN) == 0)) {
15161bdd6c0eSSue Gleeson 				/*
15171bdd6c0eSSue Gleeson 				 * if a session is in the process of connecting,
15181bdd6c0eSSue Gleeson 				 * reject subsequent equivalent requests.
15191bdd6c0eSSue Gleeson 				 */
15201bdd6c0eSSue Gleeson 				if (ch->ch_state == SRPT_CHANNEL_CONNECTING) {
15211bdd6c0eSSue Gleeson 					reason = SRP_LOGIN_REJ_INIT_CH_LIMIT;
15221bdd6c0eSSue Gleeson 					mutex_exit(&tgt->tp_ch_list_lock);
15231bdd6c0eSSue Gleeson 					goto reject_login;
15241bdd6c0eSSue Gleeson 				}
15251bdd6c0eSSue Gleeson 
15261bdd6c0eSSue Gleeson 				SRPT_DPRINTF_L2("stp_login, terminate"
15271bdd6c0eSSue Gleeson 				    " existing login");
15281bdd6c0eSSue Gleeson 				rsp_flags =
15291bdd6c0eSSue Gleeson 				    SRP_MULTI_CH_RESULT_TERM_EXISTING;
15301bdd6c0eSSue Gleeson 				srpt_ch_disconnect(ch);
15311bdd6c0eSSue Gleeson 			}
15321bdd6c0eSSue Gleeson 
15331bdd6c0eSSue Gleeson 			ch = next_ch;
15341bdd6c0eSSue Gleeson 		}
15351bdd6c0eSSue Gleeson 		mutex_exit(&tgt->tp_ch_list_lock);
15361bdd6c0eSSue Gleeson 
15371bdd6c0eSSue Gleeson 		/* Create the new session for this SRP login */
15381bdd6c0eSSue Gleeson 		session = srpt_stp_alloc_session(tgt,
15391bdd6c0eSSue Gleeson 		    login->lreq_initiator_port_id,
1540191c289bSCharles Ting 		    login->lreq_target_port_id, login_port,
1541191c289bSCharles Ting 		    local_gid, remote_gid);
15421bdd6c0eSSue Gleeson 		if (session == NULL) {
15431bdd6c0eSSue Gleeson 			SRPT_DPRINTF_L2("stp_login, session allocation"
15441bdd6c0eSSue Gleeson 			    " failed");
15451bdd6c0eSSue Gleeson 			reason = SRP_LOGIN_REJ_UNABLE_TO_ASSOCIATE_I_T_NEXUS;
15461bdd6c0eSSue Gleeson 			goto reject_login;
15471bdd6c0eSSue Gleeson 		}
15481bdd6c0eSSue Gleeson 		break;
15491bdd6c0eSSue Gleeson 
15501bdd6c0eSSue Gleeson 	case SRP_LOGIN_MULTI_CH_MULTIPLE:
15511bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, multichannel not supported yet");
15521bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_MULTI_CH_NOT_SUPPORTED;
15531bdd6c0eSSue Gleeson 		goto reject_login;
15541bdd6c0eSSue Gleeson 		/* break via goto */
15551bdd6c0eSSue Gleeson 
15561bdd6c0eSSue Gleeson 	default:
15571bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, invalid multichannel field (%d)",
15581bdd6c0eSSue Gleeson 		    login->lreq_req_flags & SRP_LOGIN_MULTI_CH_MASK);
15591bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_NO_REASON;
15601bdd6c0eSSue Gleeson 		goto reject_login;
15611bdd6c0eSSue Gleeson 		/* break via goto */
15621bdd6c0eSSue Gleeson 	}
15631bdd6c0eSSue Gleeson 
15641bdd6c0eSSue Gleeson 	/*
15651bdd6c0eSSue Gleeson 	 * Create new RDMA channel for this SRP login request.
15661bdd6c0eSSue Gleeson 	 * The channel is returned with a single reference which
15671bdd6c0eSSue Gleeson 	 * represents the reference held by the CM.
15681bdd6c0eSSue Gleeson 	 */
15691bdd6c0eSSue Gleeson 	ch = srpt_ch_alloc(tgt, login_port);
15701bdd6c0eSSue Gleeson 	if (ch == NULL) {
15711bdd6c0eSSue Gleeson 		SRPT_DPRINTF_L2("stp_login, unable to alloc RDMA channel");
15721bdd6c0eSSue Gleeson 		reason = SRP_LOGIN_REJ_INSUFFICIENT_CH_RESOURCES;
15731bdd6c0eSSue Gleeson 		srpt_stp_free_session(session);
15741bdd6c0eSSue Gleeson 		goto reject_login;
15751bdd6c0eSSue Gleeson 	}
15761bdd6c0eSSue Gleeson 	ch->ch_session = session;
15771bdd6c0eSSue Gleeson 	ch->ch_ti_iu_len = b2h32(login->lreq_req_it_iu_len);
15781bdd6c0eSSue Gleeson 
15791bdd6c0eSSue Gleeson 	/*
15801bdd6c0eSSue Gleeson 	 * Add another reference to the channel which represents
15811bdd6c0eSSue Gleeson 	 * a reference placed by the target port and add it to
15821bdd6c0eSSue Gleeson 	 * the store of channels logged in for this target port.
15831bdd6c0eSSue Gleeson 	 */
15841bdd6c0eSSue Gleeson 	srpt_ch_add_ref(ch);
15851bdd6c0eSSue Gleeson 	mutex_enter(&tgt->tp_ch_list_lock);
15861bdd6c0eSSue Gleeson 	list_insert_tail(&tgt->tp_ch_list, ch);
15871bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_ch_list_lock);
15881bdd6c0eSSue Gleeson 
15891bdd6c0eSSue Gleeson 	srpt_format_login_rsp(login, login_rsp, rsp_flags);
15901bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_lock);
15911bdd6c0eSSue Gleeson 	SRPT_DPRINTF_L2("stp_login, login successful");
15921bdd6c0eSSue Gleeson 
1593191c289bSCharles Ting 	DTRACE_SRP_3(login__response, srpt_session_t, &sess,
1594191c289bSCharles Ting 	    srp_login_rsp_t, login_rsp, srp_login_rej_t, login_rej)
1595191c289bSCharles Ting 
15961bdd6c0eSSue Gleeson 	return (ch);
15971bdd6c0eSSue Gleeson 
15981bdd6c0eSSue Gleeson reject_login:
15991bdd6c0eSSue Gleeson 	srpt_format_login_rej(login, login_rej, reason);
16001bdd6c0eSSue Gleeson 	mutex_exit(&tgt->tp_lock);
1601191c289bSCharles Ting 
1602191c289bSCharles Ting 	DTRACE_SRP_3(login__response, srpt_session_t, &sess,
1603191c289bSCharles Ting 	    srp_login_rsp_t, login_rsp, srp_login_rej_t, login_rej);
1604191c289bSCharles Ting 
16051bdd6c0eSSue Gleeson 	return (NULL);
16061bdd6c0eSSue Gleeson }
16071bdd6c0eSSue Gleeson 
16081bdd6c0eSSue Gleeson /*
16091bdd6c0eSSue Gleeson  * srpt_stp_logout() - SRP logout
16101bdd6c0eSSue Gleeson  *
16111bdd6c0eSSue Gleeson  * Logout is not normally initiated in-band, but is so, just
16121bdd6c0eSSue Gleeson  * initiate a disconnect.
16131bdd6c0eSSue Gleeson  */
16141bdd6c0eSSue Gleeson void
srpt_stp_logout(srpt_channel_t * ch)16151bdd6c0eSSue Gleeson srpt_stp_logout(srpt_channel_t *ch)
16161bdd6c0eSSue Gleeson {
1617191c289bSCharles Ting 	DTRACE_SRP_1(logout__command, srpt_channel_t, ch);
1618191c289bSCharles Ting 	SRPT_DPRINTF_L2("stp_logout, invoked for ch (%p)", (void *)ch);
16191bdd6c0eSSue Gleeson 	srpt_ch_disconnect(ch);
16201bdd6c0eSSue Gleeson }
16211bdd6c0eSSue Gleeson 
16221bdd6c0eSSue Gleeson /*
16231bdd6c0eSSue Gleeson  * srpt_format_login_rej() - Format login reject IU
16241bdd6c0eSSue Gleeson  */
16251bdd6c0eSSue Gleeson static void
srpt_format_login_rej(srp_login_req_t * req,srp_login_rej_t * rej,uint32_t reason)16261bdd6c0eSSue Gleeson srpt_format_login_rej(srp_login_req_t *req, srp_login_rej_t *rej,
16271bdd6c0eSSue Gleeson 	uint32_t reason)
16281bdd6c0eSSue Gleeson {
16291bdd6c0eSSue Gleeson 	rej->lrej_type   = SRP_IU_LOGIN_REJ;
16301bdd6c0eSSue Gleeson 	rej->lrej_reason = h2b32(reason);
16311bdd6c0eSSue Gleeson 	rej->lrej_tag    = req->lreq_tag;
16321bdd6c0eSSue Gleeson 	rej->lrej_sup_buf_format =
16331bdd6c0eSSue Gleeson 	    h2b16(SRP_DIRECT_BUFR_DESC | SRP_INDIRECT_BUFR_DESC);
16341bdd6c0eSSue Gleeson }
16351bdd6c0eSSue Gleeson 
16361bdd6c0eSSue Gleeson /*
16371bdd6c0eSSue Gleeson  * srpt_format_login_rsp() - Format login response IU
16381bdd6c0eSSue Gleeson  */
16391bdd6c0eSSue Gleeson static void
srpt_format_login_rsp(srp_login_req_t * req,srp_login_rsp_t * rsp,uint8_t flags)16401bdd6c0eSSue Gleeson srpt_format_login_rsp(srp_login_req_t *req, srp_login_rsp_t *rsp,
16411bdd6c0eSSue Gleeson 	uint8_t flags)
16421bdd6c0eSSue Gleeson {
16431bdd6c0eSSue Gleeson 	rsp->lrsp_type   = SRP_IU_LOGIN_RSP;
16441bdd6c0eSSue Gleeson 	rsp->lrsp_req_limit_delta = h2b32((uint32_t)srpt_send_msg_depth);
16451bdd6c0eSSue Gleeson 	rsp->lrsp_tag    = req->lreq_tag;
16461bdd6c0eSSue Gleeson 
16471bdd6c0eSSue Gleeson 	rsp->lrsp_max_it_iu_len = req->lreq_req_it_iu_len;
16481bdd6c0eSSue Gleeson 	/* by def. > min T_IU_LEN */
16491bdd6c0eSSue Gleeson 	rsp->lrsp_max_ti_iu_len = req->lreq_req_it_iu_len;
16501bdd6c0eSSue Gleeson 
16511bdd6c0eSSue Gleeson 	rsp->lrsp_sup_buf_format =
16521bdd6c0eSSue Gleeson 	    h2b16(SRP_DIRECT_BUFR_DESC | SRP_INDIRECT_BUFR_DESC);
16531bdd6c0eSSue Gleeson 	rsp->lrsp_rsp_flags = flags;
16541bdd6c0eSSue Gleeson }
16551bdd6c0eSSue Gleeson 
16561bdd6c0eSSue Gleeson /*
16571bdd6c0eSSue Gleeson  * srpt_stp_add_task()
16581bdd6c0eSSue Gleeson  */
16591bdd6c0eSSue Gleeson void
srpt_stp_add_task(srpt_session_t * session,srpt_iu_t * iu)16601bdd6c0eSSue Gleeson srpt_stp_add_task(srpt_session_t *session, srpt_iu_t *iu)
16611bdd6c0eSSue Gleeson {
16621bdd6c0eSSue Gleeson 	rw_enter(&session->ss_rwlock, RW_WRITER);
16631bdd6c0eSSue Gleeson 	list_insert_tail(&session->ss_task_list, iu);
16641bdd6c0eSSue Gleeson 	rw_exit(&session->ss_rwlock);
16651bdd6c0eSSue Gleeson }
16661bdd6c0eSSue Gleeson 
16671bdd6c0eSSue Gleeson /*
16681bdd6c0eSSue Gleeson  * srpt_stp_remove_task()
16691bdd6c0eSSue Gleeson  */
16701bdd6c0eSSue Gleeson void
srpt_stp_remove_task(srpt_session_t * session,srpt_iu_t * iu)16711bdd6c0eSSue Gleeson srpt_stp_remove_task(srpt_session_t *session, srpt_iu_t *iu)
16721bdd6c0eSSue Gleeson {
16731bdd6c0eSSue Gleeson 	rw_enter(&session->ss_rwlock, RW_WRITER);
16741bdd6c0eSSue Gleeson 
16751bdd6c0eSSue Gleeson 	ASSERT(!list_is_empty(&session->ss_task_list));
16761bdd6c0eSSue Gleeson 
16771bdd6c0eSSue Gleeson 	list_remove(&session->ss_task_list, iu);
16781bdd6c0eSSue Gleeson 	rw_exit(&session->ss_rwlock);
16791bdd6c0eSSue Gleeson }
1680