17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
227836SJohn.Forte@Sun.COM * Copyright 2000 by Cisco Systems, Inc. All rights reserved.
23*12161SJack.Meng@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247836SJohn.Forte@Sun.COM *
257836SJohn.Forte@Sun.COM * iSCSI Pseudo HBA Driver
267836SJohn.Forte@Sun.COM */
277836SJohn.Forte@Sun.COM
287836SJohn.Forte@Sun.COM #include <sys/socket.h> /* networking stuff */
297836SJohn.Forte@Sun.COM #include <sys/t_kuser.h> /* networking stuff */
307836SJohn.Forte@Sun.COM #include <sys/tihdr.h> /* networking stuff */
317836SJohn.Forte@Sun.COM #include <sys/strsubr.h> /* networking stuff */
327836SJohn.Forte@Sun.COM #include <netinet/tcp.h> /* TCP_NODELAY */
337836SJohn.Forte@Sun.COM #include <sys/socketvar.h> /* _ALLOC_SLEEP */
347836SJohn.Forte@Sun.COM #include <sys/strsun.h> /* DB_TYPE() */
359780SBing.Zhao@Sun.COM #include <sys/scsi/generic/sense.h>
367836SJohn.Forte@Sun.COM
377836SJohn.Forte@Sun.COM #include "iscsi.h" /* iscsi driver */
388656SPeter.Dunlap@Sun.COM #include <sys/iscsi_protocol.h> /* iscsi protocol */
397836SJohn.Forte@Sun.COM
409162SPeter.Dunlap@Sun.COM #define ISCSI_INI_TASK_TTT 0xffffffff
4110156SZhang.Yi@Sun.COM #define ISCSI_CONN_TIEMOUT_DETECT 20
429162SPeter.Dunlap@Sun.COM
439162SPeter.Dunlap@Sun.COM boolean_t iscsi_io_logging = B_FALSE;
449162SPeter.Dunlap@Sun.COM
459162SPeter.Dunlap@Sun.COM #define ISCSI_CHECK_SCSI_READ(ICHK_CMD, ICHK_HDR, ICHK_LEN, ICHK_TYPE) \
469162SPeter.Dunlap@Sun.COM if (idm_pattern_checking) { \
479162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt = (ICHK_CMD)->cmd_un.scsi.pkt; \
489162SPeter.Dunlap@Sun.COM if (((ICHK_HDR)->response == 0) && \
499162SPeter.Dunlap@Sun.COM ((ICHK_HDR)->cmd_status == 0) && \
509162SPeter.Dunlap@Sun.COM ((pkt->pkt_cdbp[0] == SCMD_READ_G1) || \
519162SPeter.Dunlap@Sun.COM (pkt->pkt_cdbp[0] == SCMD_READ_G4) || \
529162SPeter.Dunlap@Sun.COM (pkt->pkt_cdbp[0] == SCMD_READ) || \
539162SPeter.Dunlap@Sun.COM (pkt->pkt_cdbp[0] == SCMD_READ_G5))) { \
549162SPeter.Dunlap@Sun.COM idm_buf_t *idb = (ICHK_CMD)->cmd_un.scsi.ibp_ibuf; \
559162SPeter.Dunlap@Sun.COM IDM_BUFPAT_CHECK(idb, ICHK_LEN, ICHK_TYPE); \
569162SPeter.Dunlap@Sun.COM } \
579162SPeter.Dunlap@Sun.COM }
589162SPeter.Dunlap@Sun.COM
5911271SMilos.Muzik@Sun.COM /* Size of structure scsi_arq_status without sense data. */
6011271SMilos.Muzik@Sun.COM #define ISCSI_ARQ_STATUS_NOSENSE_LEN (sizeof (struct scsi_arq_status) - \
6111271SMilos.Muzik@Sun.COM sizeof (struct scsi_extended_sense))
6211271SMilos.Muzik@Sun.COM
637836SJohn.Forte@Sun.COM /* generic io helpers */
647836SJohn.Forte@Sun.COM static uint32_t n2h24(uchar_t *ptr);
657836SJohn.Forte@Sun.COM static int iscsi_sna_lt(uint32_t n1, uint32_t n2);
669162SPeter.Dunlap@Sun.COM void iscsi_update_flow_control(iscsi_sess_t *isp,
677836SJohn.Forte@Sun.COM uint32_t max, uint32_t exp);
689162SPeter.Dunlap@Sun.COM static iscsi_status_t iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp,
699162SPeter.Dunlap@Sun.COM idm_conn_t *ic, iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp);
709162SPeter.Dunlap@Sun.COM static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp,
719162SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp);
729162SPeter.Dunlap@Sun.COM static void iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
739162SPeter.Dunlap@Sun.COM idm_status_t status);
749162SPeter.Dunlap@Sun.COM static void iscsi_drop_conn_cleanup(iscsi_conn_t *icp);
7510156SZhang.Yi@Sun.COM static boolean_t iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp);
769162SPeter.Dunlap@Sun.COM /* callbacks from idm */
779162SPeter.Dunlap@Sun.COM static idm_pdu_cb_t iscsi_tx_done;
787836SJohn.Forte@Sun.COM
797836SJohn.Forte@Sun.COM /* receivers */
809162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu);
819162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_data_rsp(idm_conn_t *ic,
829162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
839162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu);
849162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_reject_rsp(idm_conn_t *ic,
859162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
869162SPeter.Dunlap@Sun.COM
879162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic,
887836SJohn.Forte@Sun.COM iscsi_hdr_t *old_ihp);
899162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic,
909162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
919162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_logout_rsp(idm_conn_t *ic,
929162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
939162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_async_rsp(idm_conn_t *ic,
949162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
959162SPeter.Dunlap@Sun.COM static idm_status_t iscsi_rx_process_text_rsp(idm_conn_t *ic,
969162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu);
977836SJohn.Forte@Sun.COM
987836SJohn.Forte@Sun.COM /* senders */
997836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1007836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1017836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1027836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1037836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1047836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp);
1057836SJohn.Forte@Sun.COM
1067836SJohn.Forte@Sun.COM
1077836SJohn.Forte@Sun.COM /* helpers */
1089162SPeter.Dunlap@Sun.COM static void iscsi_logout_start(void *arg);
1097836SJohn.Forte@Sun.COM static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt);
1107836SJohn.Forte@Sun.COM static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt);
1117836SJohn.Forte@Sun.COM
1127836SJohn.Forte@Sun.COM static void iscsi_timeout_checks(iscsi_sess_t *isp);
1137836SJohn.Forte@Sun.COM static void iscsi_nop_checks(iscsi_sess_t *isp);
114*12161SJack.Meng@Sun.COM static boolean_t iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp);
1159780SBing.Zhao@Sun.COM static void iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
1169780SBing.Zhao@Sun.COM iscsi_conn_t *icp);
1177836SJohn.Forte@Sun.COM
1187836SJohn.Forte@Sun.COM /*
1197836SJohn.Forte@Sun.COM * This file contains the main guts of the iSCSI protocol layer.
1207836SJohn.Forte@Sun.COM * It's broken into 5 sections; Basic helper functions, RX IO path,
1217836SJohn.Forte@Sun.COM * TX IO path, Completion (IC) IO path, and watchdog (WD) routines.
1227836SJohn.Forte@Sun.COM *
1237836SJohn.Forte@Sun.COM * The IO flow model is similiar to the below diagram. The
1247836SJohn.Forte@Sun.COM * iscsi session, connection and command state machines are used
1257836SJohn.Forte@Sun.COM * to drive IO through this flow diagram. Reference those files
1267836SJohn.Forte@Sun.COM * to get a detailed description of their respective state models
1277836SJohn.Forte@Sun.COM * prior to their xxx_state_machine_function().
1287836SJohn.Forte@Sun.COM *
1297836SJohn.Forte@Sun.COM * tran_start() -> CMD_E1 TX_THREAD RX_THREAD
1307836SJohn.Forte@Sun.COM * | T T
1317836SJohn.Forte@Sun.COM * V T T
1327836SJohn.Forte@Sun.COM * PENDING_Q --CMD_E2--> ACTIVE_Q - --CMD_E3--+
1337836SJohn.Forte@Sun.COM * T \ C T |
1347836SJohn.Forte@Sun.COM * T \M T |
1357836SJohn.Forte@Sun.COM * D T |
1367836SJohn.Forte@Sun.COM * WD_THREAD TT|TT T |
1377836SJohn.Forte@Sun.COM * /E T |
1387836SJohn.Forte@Sun.COM * / 6 T |
1397836SJohn.Forte@Sun.COM * ABORTING_Q<- --CMD_E3--+
1407836SJohn.Forte@Sun.COM * T |
1417836SJohn.Forte@Sun.COM * T T |
1427836SJohn.Forte@Sun.COM * T |
1437836SJohn.Forte@Sun.COM * callback() <--CMD_E#-- COMPLETION_Q <------------+
1447836SJohn.Forte@Sun.COM * T
1457836SJohn.Forte@Sun.COM * T
1467836SJohn.Forte@Sun.COM * IC_THREAD
1477836SJohn.Forte@Sun.COM *
1487836SJohn.Forte@Sun.COM * External and internal command are ran thru this same state
1497836SJohn.Forte@Sun.COM * machine. All commands enter the state machine by receiving an
1507836SJohn.Forte@Sun.COM * ISCSI_CMD_EVENT_E1. This event places the command into the
1517836SJohn.Forte@Sun.COM * PENDING_Q. Next when resources are available the TX_THREAD
1527836SJohn.Forte@Sun.COM * issues a E2 event on the command. This sends the command
1537836SJohn.Forte@Sun.COM * to the TCP stack and places the command on the ACTIVE_Q. While
1547836SJohn.Forte@Sun.COM * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the
1557836SJohn.Forte@Sun.COM * WD_THREAD to ensure the pkt_time has not elapsed. If elapsed the
1567836SJohn.Forte@Sun.COM * command is issued an E6(timeout) event which moves either (if pending)
1577836SJohn.Forte@Sun.COM * completed the command or (if active) moves the command to the
1587836SJohn.Forte@Sun.COM * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command
1597836SJohn.Forte@Sun.COM * to cancel the IO request. If the original command is completed
1607836SJohn.Forte@Sun.COM * or the TASK MANAGEMENT command completes the command is moved
1617836SJohn.Forte@Sun.COM * to the COMPLETION_Q via a E3 event. The IC_THREAD then processes
1627836SJohn.Forte@Sun.COM * the COMPLETION_Q and issues the scsi_pkt callback. This
1637836SJohn.Forte@Sun.COM * callback can not be processed directly from the RX_THREAD
1647836SJohn.Forte@Sun.COM * because the callback might call back into the iscsi driver
1657836SJohn.Forte@Sun.COM * causing a deadlock condition.
1667836SJohn.Forte@Sun.COM *
1677836SJohn.Forte@Sun.COM * For more details on the complete CMD state machine reference
1687836SJohn.Forte@Sun.COM * the state machine diagram in iscsi_cmd.c. The connection state
1697836SJohn.Forte@Sun.COM * machine is driven via IO events in this file. Then session
1707836SJohn.Forte@Sun.COM * events are driven by the connection events. For complete
1717836SJohn.Forte@Sun.COM * details on these state machines reference iscsi_sess.c and
1727836SJohn.Forte@Sun.COM * iscsi_conn.c
1737836SJohn.Forte@Sun.COM */
1747836SJohn.Forte@Sun.COM
1757836SJohn.Forte@Sun.COM
1767836SJohn.Forte@Sun.COM /*
1777836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
1787836SJohn.Forte@Sun.COM * | io helper routines |
1797836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
1807836SJohn.Forte@Sun.COM */
1817836SJohn.Forte@Sun.COM
1827836SJohn.Forte@Sun.COM /*
1837836SJohn.Forte@Sun.COM * n2h24 - native to host 24 bit integer translation.
1847836SJohn.Forte@Sun.COM */
1857836SJohn.Forte@Sun.COM static uint32_t
n2h24(uchar_t * ptr)1867836SJohn.Forte@Sun.COM n2h24(uchar_t *ptr)
1877836SJohn.Forte@Sun.COM {
1887836SJohn.Forte@Sun.COM uint32_t idx;
1897836SJohn.Forte@Sun.COM bcopy(ptr, &idx, 3);
1907836SJohn.Forte@Sun.COM return (ntohl(idx) >> 8);
1917836SJohn.Forte@Sun.COM }
1927836SJohn.Forte@Sun.COM
1937836SJohn.Forte@Sun.COM /*
1947836SJohn.Forte@Sun.COM * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982
1957836SJohn.Forte@Sun.COM */
1967836SJohn.Forte@Sun.COM static int
iscsi_sna_lt(uint32_t n1,uint32_t n2)1977836SJohn.Forte@Sun.COM iscsi_sna_lt(uint32_t n1, uint32_t n2)
1987836SJohn.Forte@Sun.COM {
1997836SJohn.Forte@Sun.COM return ((n1 != n2) &&
2007836SJohn.Forte@Sun.COM (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
2017836SJohn.Forte@Sun.COM ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
2027836SJohn.Forte@Sun.COM }
2037836SJohn.Forte@Sun.COM
2047836SJohn.Forte@Sun.COM /*
2057836SJohn.Forte@Sun.COM * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal,
2067836SJohn.Forte@Sun.COM * RFC1982
2077836SJohn.Forte@Sun.COM */
2087836SJohn.Forte@Sun.COM int
iscsi_sna_lte(uint32_t n1,uint32_t n2)2097836SJohn.Forte@Sun.COM iscsi_sna_lte(uint32_t n1, uint32_t n2)
2107836SJohn.Forte@Sun.COM {
2117836SJohn.Forte@Sun.COM return ((n1 == n2) ||
2127836SJohn.Forte@Sun.COM (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) ||
2137836SJohn.Forte@Sun.COM ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK))));
2147836SJohn.Forte@Sun.COM }
2157836SJohn.Forte@Sun.COM
2167836SJohn.Forte@Sun.COM /*
2177836SJohn.Forte@Sun.COM * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI
2187836SJohn.Forte@Sun.COM * flow control information for a session
2197836SJohn.Forte@Sun.COM */
2209162SPeter.Dunlap@Sun.COM void
iscsi_update_flow_control(iscsi_sess_t * isp,uint32_t max,uint32_t exp)2217836SJohn.Forte@Sun.COM iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp)
2227836SJohn.Forte@Sun.COM {
2237836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
2247836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
2257836SJohn.Forte@Sun.COM
2267836SJohn.Forte@Sun.COM if (!iscsi_sna_lt(max, (exp - 1))) {
2277836SJohn.Forte@Sun.COM
2287836SJohn.Forte@Sun.COM if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) {
2297836SJohn.Forte@Sun.COM isp->sess_expcmdsn = exp;
2307836SJohn.Forte@Sun.COM }
2317836SJohn.Forte@Sun.COM
2327836SJohn.Forte@Sun.COM if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) {
2337836SJohn.Forte@Sun.COM isp->sess_maxcmdsn = max;
2347836SJohn.Forte@Sun.COM if (iscsi_sna_lte(isp->sess_cmdsn,
2357836SJohn.Forte@Sun.COM isp->sess_maxcmdsn)) {
2367836SJohn.Forte@Sun.COM /*
2377836SJohn.Forte@Sun.COM * the window is open again - schedule
2387836SJohn.Forte@Sun.COM * to send any held tasks soon
2397836SJohn.Forte@Sun.COM */
2407836SJohn.Forte@Sun.COM iscsi_sess_redrive_io(isp);
2417836SJohn.Forte@Sun.COM }
2427836SJohn.Forte@Sun.COM }
2437836SJohn.Forte@Sun.COM }
2447836SJohn.Forte@Sun.COM }
2457836SJohn.Forte@Sun.COM
2467836SJohn.Forte@Sun.COM
2477836SJohn.Forte@Sun.COM /*
2487836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
2497836SJohn.Forte@Sun.COM * | io receive and processing routines |
2507836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
2517836SJohn.Forte@Sun.COM */
2527836SJohn.Forte@Sun.COM
2537836SJohn.Forte@Sun.COM /*
2549162SPeter.Dunlap@Sun.COM * iscsi_rx_scsi_rsp - called from idm
2559162SPeter.Dunlap@Sun.COM * For each opcode type fan out the processing.
2567836SJohn.Forte@Sun.COM */
2577836SJohn.Forte@Sun.COM void
iscsi_rx_scsi_rsp(idm_conn_t * ic,idm_pdu_t * pdu)2589162SPeter.Dunlap@Sun.COM iscsi_rx_scsi_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
2597836SJohn.Forte@Sun.COM {
2609162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp;
2619162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp;
2629162SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp;
2639162SPeter.Dunlap@Sun.COM idm_status_t status;
2649162SPeter.Dunlap@Sun.COM
2659162SPeter.Dunlap@Sun.COM ASSERT(ic != NULL);
2669162SPeter.Dunlap@Sun.COM ASSERT(pdu != NULL);
2679162SPeter.Dunlap@Sun.COM icp = ic->ic_handle;
2687836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
2699162SPeter.Dunlap@Sun.COM ihp = (iscsi_hdr_t *)pdu->isp_hdr;
2707836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
2719162SPeter.Dunlap@Sun.COM isp = icp->conn_sess;
2727836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
2737836SJohn.Forte@Sun.COM
2749162SPeter.Dunlap@Sun.COM /* reset the session timer when we receive the response */
2759162SPeter.Dunlap@Sun.COM isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
2767836SJohn.Forte@Sun.COM
2777836SJohn.Forte@Sun.COM /* fan out the hdr processing */
2787836SJohn.Forte@Sun.COM switch (ihp->opcode & ISCSI_OPCODE_MASK) {
2797836SJohn.Forte@Sun.COM case ISCSI_OP_SCSI_DATA_RSP:
2809162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_data_rsp(ic, pdu);
2817836SJohn.Forte@Sun.COM break;
2827836SJohn.Forte@Sun.COM case ISCSI_OP_SCSI_RSP:
2839162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_cmd_rsp(ic, pdu);
2849162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
2857836SJohn.Forte@Sun.COM break;
2867836SJohn.Forte@Sun.COM default:
2877836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
2889162SPeter.Dunlap@Sun.COM "received pdu with unsupported opcode 0x%02x",
2897836SJohn.Forte@Sun.COM icp->conn_oid, ihp->opcode);
2909162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
2919162SPeter.Dunlap@Sun.COM }
2929162SPeter.Dunlap@Sun.COM iscsi_process_rsp_status(isp, icp, status);
2939162SPeter.Dunlap@Sun.COM }
2949162SPeter.Dunlap@Sun.COM
2959162SPeter.Dunlap@Sun.COM void
iscsi_task_cleanup(int opcode,iscsi_cmd_t * icmdp)2969162SPeter.Dunlap@Sun.COM iscsi_task_cleanup(int opcode, iscsi_cmd_t *icmdp)
2979162SPeter.Dunlap@Sun.COM {
2989162SPeter.Dunlap@Sun.COM struct buf *bp;
2999162SPeter.Dunlap@Sun.COM idm_buf_t *ibp, *obp;
3009162SPeter.Dunlap@Sun.COM idm_task_t *itp;
3019162SPeter.Dunlap@Sun.COM
3029162SPeter.Dunlap@Sun.COM itp = icmdp->cmd_itp;
3039162SPeter.Dunlap@Sun.COM ASSERT(itp != NULL);
3049162SPeter.Dunlap@Sun.COM ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
3059162SPeter.Dunlap@Sun.COM (opcode == ISCSI_OP_SCSI_RSP));
3069162SPeter.Dunlap@Sun.COM
3079162SPeter.Dunlap@Sun.COM bp = icmdp->cmd_un.scsi.bp;
3089162SPeter.Dunlap@Sun.COM ibp = icmdp->cmd_un.scsi.ibp_ibuf;
3099162SPeter.Dunlap@Sun.COM obp = icmdp->cmd_un.scsi.ibp_obuf;
3109162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: task_cleanup: itp: %p opcode: %d "
3119162SPeter.Dunlap@Sun.COM "icmdp: %p bp: %p ibp: %p", (void *)itp, opcode,
3129162SPeter.Dunlap@Sun.COM (void *)icmdp, (void *)bp, (void *)ibp);
3139162SPeter.Dunlap@Sun.COM if (bp && bp->b_bcount) {
3149162SPeter.Dunlap@Sun.COM if (ibp != NULL && bp->b_flags & B_READ) {
3159162SPeter.Dunlap@Sun.COM idm_buf_unbind_in(itp, ibp);
3169162SPeter.Dunlap@Sun.COM idm_buf_free(ibp);
3179162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_ibuf = NULL;
3189162SPeter.Dunlap@Sun.COM } else if (obp != NULL && !(bp->b_flags & B_READ)) {
3199162SPeter.Dunlap@Sun.COM idm_buf_unbind_out(itp, obp);
3209162SPeter.Dunlap@Sun.COM idm_buf_free(obp);
3219162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_obuf = NULL;
3229162SPeter.Dunlap@Sun.COM }
3239162SPeter.Dunlap@Sun.COM }
3249162SPeter.Dunlap@Sun.COM
3259162SPeter.Dunlap@Sun.COM idm_task_done(itp);
3269162SPeter.Dunlap@Sun.COM }
3279162SPeter.Dunlap@Sun.COM
3289162SPeter.Dunlap@Sun.COM idm_status_t
iscsi_rx_chk(iscsi_conn_t * icp,iscsi_sess_t * isp,iscsi_scsi_rsp_hdr_t * irhp,iscsi_cmd_t ** icmdp)3299162SPeter.Dunlap@Sun.COM iscsi_rx_chk(iscsi_conn_t *icp, iscsi_sess_t *isp,
3309162SPeter.Dunlap@Sun.COM iscsi_scsi_rsp_hdr_t *irhp, iscsi_cmd_t **icmdp)
3319162SPeter.Dunlap@Sun.COM {
3329162SPeter.Dunlap@Sun.COM iscsi_status_t rval;
3339162SPeter.Dunlap@Sun.COM
3349162SPeter.Dunlap@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
3359162SPeter.Dunlap@Sun.COM
3369162SPeter.Dunlap@Sun.COM if (icp->conn_expstatsn == ntohl(irhp->statsn)) {
3379162SPeter.Dunlap@Sun.COM icp->conn_expstatsn++;
3389162SPeter.Dunlap@Sun.COM } else {
3399162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
3409162SPeter.Dunlap@Sun.COM "received status out of order itt:0x%x statsn:0x%x "
3419162SPeter.Dunlap@Sun.COM "expstatsn:0x%x", icp->conn_oid, irhp->opcode,
3429162SPeter.Dunlap@Sun.COM irhp->itt, ntohl(irhp->statsn), icp->conn_expstatsn);
3439162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
3449162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
3459162SPeter.Dunlap@Sun.COM }
3469162SPeter.Dunlap@Sun.COM
3479162SPeter.Dunlap@Sun.COM /* get icmdp so we can cleanup on error */
3489162SPeter.Dunlap@Sun.COM if ((irhp->opcode == ISCSI_OP_SCSI_DATA_RSP) ||
3499162SPeter.Dunlap@Sun.COM (irhp->opcode == ISCSI_OP_SCSI_RSP)) {
3509162SPeter.Dunlap@Sun.COM rval = iscsi_rx_process_scsi_itt_to_icmdp(isp, icp->conn_ic,
3519162SPeter.Dunlap@Sun.COM irhp, icmdp);
3529162SPeter.Dunlap@Sun.COM } else {
3539162SPeter.Dunlap@Sun.COM rval = iscsi_rx_process_itt_to_icmdp(isp,
3549162SPeter.Dunlap@Sun.COM (iscsi_hdr_t *)irhp, icmdp);
3559162SPeter.Dunlap@Sun.COM }
3569162SPeter.Dunlap@Sun.COM
3579162SPeter.Dunlap@Sun.COM if (!ISCSI_SUCCESS(rval)) {
3589162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
3599162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
3609162SPeter.Dunlap@Sun.COM }
3619162SPeter.Dunlap@Sun.COM
3629162SPeter.Dunlap@Sun.COM /* update expcmdsn and maxcmdsn */
3639162SPeter.Dunlap@Sun.COM iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn),
3649162SPeter.Dunlap@Sun.COM ntohl(irhp->expcmdsn));
3659162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
3669162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
3679162SPeter.Dunlap@Sun.COM }
3689162SPeter.Dunlap@Sun.COM
3699162SPeter.Dunlap@Sun.COM static void
iscsi_cmd_rsp_chk(iscsi_cmd_t * icmdp,iscsi_scsi_rsp_hdr_t * issrhp)3709162SPeter.Dunlap@Sun.COM iscsi_cmd_rsp_chk(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp)
3719162SPeter.Dunlap@Sun.COM {
3729162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt;
3739162SPeter.Dunlap@Sun.COM size_t data_transferred;
3749162SPeter.Dunlap@Sun.COM
3759162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
3769162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
3779162SPeter.Dunlap@Sun.COM data_transferred = icmdp->cmd_un.scsi.data_transferred;
3789162SPeter.Dunlap@Sun.COM /* Check the residual count */
3799162SPeter.Dunlap@Sun.COM if ((icmdp->cmd_un.scsi.bp) &&
3809162SPeter.Dunlap@Sun.COM (data_transferred != icmdp->cmd_un.scsi.bp->b_bcount)) {
3819162SPeter.Dunlap@Sun.COM /*
3829162SPeter.Dunlap@Sun.COM * We didn't xfer the expected amount of data -
3839162SPeter.Dunlap@Sun.COM * the residual_count in the header is only
3849162SPeter.Dunlap@Sun.COM * valid if the underflow flag is set.
3859162SPeter.Dunlap@Sun.COM */
3869162SPeter.Dunlap@Sun.COM if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
3879162SPeter.Dunlap@Sun.COM pkt->pkt_resid = ntohl(issrhp->residual_count);
3889162SPeter.Dunlap@Sun.COM } else {
3899162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.bp->b_bcount >
3909162SPeter.Dunlap@Sun.COM data_transferred) {
3919162SPeter.Dunlap@Sun.COM /*
3929162SPeter.Dunlap@Sun.COM * Some data fell on the floor
3939162SPeter.Dunlap@Sun.COM * somehow - probably a CRC error
3949162SPeter.Dunlap@Sun.COM */
3959162SPeter.Dunlap@Sun.COM pkt->pkt_resid =
3969162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.bp->b_bcount -
3979162SPeter.Dunlap@Sun.COM data_transferred;
3989162SPeter.Dunlap@Sun.COM }
3999162SPeter.Dunlap@Sun.COM }
4009162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
4019162SPeter.Dunlap@Sun.COM "DEBUG: iscsi_rx_cmd_rsp_chk: itt: %u"
4029162SPeter.Dunlap@Sun.COM "data_trans != b_count data_transferred: %lu "
4039162SPeter.Dunlap@Sun.COM "b_count: %lu cmd_status: %d flags: %d resid: %lu",
4049162SPeter.Dunlap@Sun.COM issrhp->itt, data_transferred,
4059162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.bp->b_bcount,
4069162SPeter.Dunlap@Sun.COM issrhp->cmd_status & STATUS_MASK,
4079162SPeter.Dunlap@Sun.COM issrhp->flags, pkt->pkt_resid);
4089162SPeter.Dunlap@Sun.COM }
4099162SPeter.Dunlap@Sun.COM /* set flags that tell SCSA that the command is complete */
4109162SPeter.Dunlap@Sun.COM if (icmdp->cmd_crc_error_seen == B_FALSE) {
4119162SPeter.Dunlap@Sun.COM /* Set successful completion */
4129162SPeter.Dunlap@Sun.COM pkt->pkt_reason = CMD_CMPLT;
4139162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.bp) {
4149162SPeter.Dunlap@Sun.COM pkt->pkt_state |= (STATE_XFERRED_DATA |
4159162SPeter.Dunlap@Sun.COM STATE_GOT_STATUS);
4169162SPeter.Dunlap@Sun.COM } else {
4179162SPeter.Dunlap@Sun.COM pkt->pkt_state |= STATE_GOT_STATUS;
4189162SPeter.Dunlap@Sun.COM }
4199162SPeter.Dunlap@Sun.COM } else {
4209162SPeter.Dunlap@Sun.COM /*
4219162SPeter.Dunlap@Sun.COM * Some of the data was found to have an incorrect
4229162SPeter.Dunlap@Sun.COM * error at the protocol error.
4239162SPeter.Dunlap@Sun.COM */
4249162SPeter.Dunlap@Sun.COM pkt->pkt_reason = CMD_PER_FAIL;
4259162SPeter.Dunlap@Sun.COM pkt->pkt_statistics |= STAT_PERR;
4269162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.bp) {
4279162SPeter.Dunlap@Sun.COM pkt->pkt_resid =
4289162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.bp->b_bcount;
4299162SPeter.Dunlap@Sun.COM } else {
4309162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
4319162SPeter.Dunlap@Sun.COM }
4327836SJohn.Forte@Sun.COM }
4337836SJohn.Forte@Sun.COM }
4347836SJohn.Forte@Sun.COM
4359780SBing.Zhao@Sun.COM static boolean_t
iscsi_cmd_rsp_cmd_status(iscsi_cmd_t * icmdp,iscsi_scsi_rsp_hdr_t * issrhp,uint8_t * data)4369162SPeter.Dunlap@Sun.COM iscsi_cmd_rsp_cmd_status(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp,
4379162SPeter.Dunlap@Sun.COM uint8_t *data)
4389162SPeter.Dunlap@Sun.COM {
43911271SMilos.Muzik@Sun.COM int32_t dlength;
44011271SMilos.Muzik@Sun.COM struct scsi_arq_status *arqstat;
44111271SMilos.Muzik@Sun.COM size_t senselen;
44211271SMilos.Muzik@Sun.COM int32_t statuslen;
44311271SMilos.Muzik@Sun.COM int32_t sensebuf_len;
4449162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt;
44511271SMilos.Muzik@Sun.COM boolean_t affect = B_FALSE;
44611271SMilos.Muzik@Sun.COM int32_t senselen_to_copy;
4479162SPeter.Dunlap@Sun.COM
4489162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
4499162SPeter.Dunlap@Sun.COM dlength = n2h24(issrhp->dlength);
4509162SPeter.Dunlap@Sun.COM
4519162SPeter.Dunlap@Sun.COM /*
4529162SPeter.Dunlap@Sun.COM * Process iSCSI Cmd Response Status
4539162SPeter.Dunlap@Sun.COM * RFC 3720 Sectionn 10.4.2.
4549162SPeter.Dunlap@Sun.COM */
4559162SPeter.Dunlap@Sun.COM switch (issrhp->cmd_status & STATUS_MASK) {
4569162SPeter.Dunlap@Sun.COM case STATUS_GOOD:
4579162SPeter.Dunlap@Sun.COM /* pass SCSI status up stack */
4589162SPeter.Dunlap@Sun.COM if (pkt->pkt_scbp) {
4599162SPeter.Dunlap@Sun.COM pkt->pkt_scbp[0] = issrhp->cmd_status;
4609162SPeter.Dunlap@Sun.COM }
4619162SPeter.Dunlap@Sun.COM break;
4629162SPeter.Dunlap@Sun.COM case STATUS_CHECK:
4639162SPeter.Dunlap@Sun.COM /*
4649162SPeter.Dunlap@Sun.COM * Verify we received a sense buffer and
4659162SPeter.Dunlap@Sun.COM * that there is the correct amount of
4669162SPeter.Dunlap@Sun.COM * request sense space to copy it to.
4679162SPeter.Dunlap@Sun.COM */
4689162SPeter.Dunlap@Sun.COM if ((dlength > 1) &&
4699162SPeter.Dunlap@Sun.COM (pkt->pkt_scbp != NULL) &&
4709162SPeter.Dunlap@Sun.COM (icmdp->cmd_un.scsi.statuslen >=
4719162SPeter.Dunlap@Sun.COM sizeof (struct scsi_arq_status))) {
4729162SPeter.Dunlap@Sun.COM /*
4739162SPeter.Dunlap@Sun.COM * If a bad command status is received we
4749162SPeter.Dunlap@Sun.COM * need to reset the pkt_resid to zero.
4759162SPeter.Dunlap@Sun.COM * The target driver compares its value
4769162SPeter.Dunlap@Sun.COM * before checking other error flags.
4779162SPeter.Dunlap@Sun.COM * (ex. check conditions)
4789162SPeter.Dunlap@Sun.COM */
4799162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
4809162SPeter.Dunlap@Sun.COM
4819162SPeter.Dunlap@Sun.COM /* get sense length from first 2 bytes */
4829162SPeter.Dunlap@Sun.COM senselen = ((data[0] << 8) | data[1]) &
4839162SPeter.Dunlap@Sun.COM (size_t)0xFFFF;
4849162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
4859162SPeter.Dunlap@Sun.COM "DEBUG: iscsi_rx_cmd_rsp_cmd_status status_check: "
4869162SPeter.Dunlap@Sun.COM "dlen: %d scbp: %p statuslen: %d arq: %d senselen:"
4879162SPeter.Dunlap@Sun.COM " %lu", dlength, (void *)pkt->pkt_scbp,
4889162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.statuslen,
4899162SPeter.Dunlap@Sun.COM (int)sizeof (struct scsi_arq_status),
4909162SPeter.Dunlap@Sun.COM senselen);
4919162SPeter.Dunlap@Sun.COM
4929162SPeter.Dunlap@Sun.COM /* Sanity-check on the sense length */
4939162SPeter.Dunlap@Sun.COM if ((senselen + 2) > dlength) {
4949162SPeter.Dunlap@Sun.COM senselen = dlength - 2;
4959162SPeter.Dunlap@Sun.COM }
4969162SPeter.Dunlap@Sun.COM
4979162SPeter.Dunlap@Sun.COM /*
4989162SPeter.Dunlap@Sun.COM * If there was a Data Digest error then
4999162SPeter.Dunlap@Sun.COM * the sense data cannot be trusted.
5009162SPeter.Dunlap@Sun.COM */
5019162SPeter.Dunlap@Sun.COM if (icmdp->cmd_crc_error_seen) {
5029162SPeter.Dunlap@Sun.COM senselen = 0;
5039162SPeter.Dunlap@Sun.COM }
5049162SPeter.Dunlap@Sun.COM
5059162SPeter.Dunlap@Sun.COM /* automatic request sense */
5069162SPeter.Dunlap@Sun.COM arqstat =
5079162SPeter.Dunlap@Sun.COM (struct scsi_arq_status *)pkt->pkt_scbp;
5089162SPeter.Dunlap@Sun.COM
5099162SPeter.Dunlap@Sun.COM /* pass SCSI status up stack */
5109162SPeter.Dunlap@Sun.COM *((uchar_t *)&arqstat->sts_status) =
5119162SPeter.Dunlap@Sun.COM issrhp->cmd_status;
5129162SPeter.Dunlap@Sun.COM
5139162SPeter.Dunlap@Sun.COM /*
5149162SPeter.Dunlap@Sun.COM * Set the status for the automatic
5159162SPeter.Dunlap@Sun.COM * request sense command
5169162SPeter.Dunlap@Sun.COM */
5179162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_state = (STATE_GOT_BUS |
5189162SPeter.Dunlap@Sun.COM STATE_GOT_TARGET | STATE_SENT_CMD |
5199162SPeter.Dunlap@Sun.COM STATE_XFERRED_DATA | STATE_GOT_STATUS |
5209162SPeter.Dunlap@Sun.COM STATE_ARQ_DONE);
5219162SPeter.Dunlap@Sun.COM
5229162SPeter.Dunlap@Sun.COM *((uchar_t *)&arqstat->sts_rqpkt_status) =
5239162SPeter.Dunlap@Sun.COM STATUS_GOOD;
5249162SPeter.Dunlap@Sun.COM
5259162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_reason = CMD_CMPLT;
5269162SPeter.Dunlap@Sun.COM statuslen = icmdp->cmd_un.scsi.statuslen;
5279162SPeter.Dunlap@Sun.COM
5289162SPeter.Dunlap@Sun.COM if (senselen == 0) {
5299162SPeter.Dunlap@Sun.COM /* auto request sense failed */
5309162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_status.sts_chk = 1;
5319162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_resid = statuslen;
5329162SPeter.Dunlap@Sun.COM } else if (senselen < statuslen) {
5339162SPeter.Dunlap@Sun.COM /* auto request sense short */
5349162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_resid = statuslen - senselen;
5359162SPeter.Dunlap@Sun.COM } else {
5369162SPeter.Dunlap@Sun.COM /* auto request sense complete */
5379162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_resid = 0;
5389162SPeter.Dunlap@Sun.COM }
5399162SPeter.Dunlap@Sun.COM arqstat->sts_rqpkt_statistics = 0;
5409162SPeter.Dunlap@Sun.COM pkt->pkt_state |= STATE_ARQ_DONE;
5419162SPeter.Dunlap@Sun.COM
5429162SPeter.Dunlap@Sun.COM if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_XARQ) {
5439162SPeter.Dunlap@Sun.COM pkt->pkt_state |= STATE_XARQ_DONE;
5449162SPeter.Dunlap@Sun.COM }
5459162SPeter.Dunlap@Sun.COM
54611271SMilos.Muzik@Sun.COM /*
54711271SMilos.Muzik@Sun.COM * Calculate size of space reserved for sense data in
54811271SMilos.Muzik@Sun.COM * pkt->pkt_scbp.
54911271SMilos.Muzik@Sun.COM */
55011271SMilos.Muzik@Sun.COM sensebuf_len = statuslen - ISCSI_ARQ_STATUS_NOSENSE_LEN;
5519620SJack.Meng@Sun.COM
5529162SPeter.Dunlap@Sun.COM /* copy auto request sense */
55311271SMilos.Muzik@Sun.COM senselen_to_copy = min(senselen, sensebuf_len);
55411271SMilos.Muzik@Sun.COM if (senselen_to_copy > 0) {
5559162SPeter.Dunlap@Sun.COM bcopy(&data[2], (uchar_t *)&arqstat->
55611271SMilos.Muzik@Sun.COM sts_sensedata, senselen_to_copy);
5579780SBing.Zhao@Sun.COM
5589780SBing.Zhao@Sun.COM affect = iscsi_decode_sense(
559*12161SJack.Meng@Sun.COM (uint8_t *)&arqstat->sts_sensedata, icmdp);
5609162SPeter.Dunlap@Sun.COM }
56111271SMilos.Muzik@Sun.COM arqstat->sts_rqpkt_resid = sensebuf_len -
56211271SMilos.Muzik@Sun.COM senselen_to_copy;
56311271SMilos.Muzik@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_cmd_rsp_cmd_status:"
56411271SMilos.Muzik@Sun.COM " sts_rqpkt_resid: %d pkt_scblen: %d senselen: %lu"
56511271SMilos.Muzik@Sun.COM " sensebuf_len: %d senselen_to_copy: %d affect: %d",
56611271SMilos.Muzik@Sun.COM arqstat->sts_rqpkt_resid, pkt->pkt_scblen, senselen,
56711271SMilos.Muzik@Sun.COM sensebuf_len, senselen_to_copy, affect);
5689162SPeter.Dunlap@Sun.COM break;
5699162SPeter.Dunlap@Sun.COM }
5709162SPeter.Dunlap@Sun.COM /* FALLTHRU */
5719162SPeter.Dunlap@Sun.COM case STATUS_BUSY:
5729162SPeter.Dunlap@Sun.COM case STATUS_RESERVATION_CONFLICT:
5739162SPeter.Dunlap@Sun.COM case STATUS_QFULL:
5749162SPeter.Dunlap@Sun.COM case STATUS_ACA_ACTIVE:
5759162SPeter.Dunlap@Sun.COM default:
5769162SPeter.Dunlap@Sun.COM /*
5779162SPeter.Dunlap@Sun.COM * If a bad command status is received we need to
5789162SPeter.Dunlap@Sun.COM * reset the pkt_resid to zero. The target driver
5799162SPeter.Dunlap@Sun.COM * compares its value before checking other error
5809162SPeter.Dunlap@Sun.COM * flags. (ex. check conditions)
5819162SPeter.Dunlap@Sun.COM */
5829162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
5839162SPeter.Dunlap@Sun.COM "DEBUG: iscsi_rx_cmd_rsp_cmd_status: status: "
5849162SPeter.Dunlap@Sun.COM "%d cmd_status: %d dlen: %u scbp: %p statuslen: %d "
5859162SPeter.Dunlap@Sun.COM "arg_len: %d", issrhp->cmd_status & STATUS_MASK,
5869162SPeter.Dunlap@Sun.COM issrhp->cmd_status, dlength, (void *)pkt->pkt_scbp,
5879162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.statuslen,
5889162SPeter.Dunlap@Sun.COM (int)sizeof (struct scsi_arq_status));
5899162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
5909162SPeter.Dunlap@Sun.COM /* pass SCSI status up stack */
5919162SPeter.Dunlap@Sun.COM if (pkt->pkt_scbp) {
5929162SPeter.Dunlap@Sun.COM pkt->pkt_scbp[0] = issrhp->cmd_status;
5939162SPeter.Dunlap@Sun.COM }
5949162SPeter.Dunlap@Sun.COM }
5959780SBing.Zhao@Sun.COM
5969780SBing.Zhao@Sun.COM return (affect);
5979162SPeter.Dunlap@Sun.COM }
5987836SJohn.Forte@Sun.COM
5997836SJohn.Forte@Sun.COM /*
6009162SPeter.Dunlap@Sun.COM * iscsi_rx_process_login_pdup - Process login response PDU. This function
6019162SPeter.Dunlap@Sun.COM * copies the data into the connection context so that the login code can
6029162SPeter.Dunlap@Sun.COM * interpret it.
6039162SPeter.Dunlap@Sun.COM */
6049162SPeter.Dunlap@Sun.COM
6059162SPeter.Dunlap@Sun.COM idm_status_t
iscsi_rx_process_login_pdu(idm_conn_t * ic,idm_pdu_t * pdu)6069162SPeter.Dunlap@Sun.COM iscsi_rx_process_login_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
6079162SPeter.Dunlap@Sun.COM {
6089162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp;
6099162SPeter.Dunlap@Sun.COM
6109162SPeter.Dunlap@Sun.COM icp = ic->ic_handle;
6119162SPeter.Dunlap@Sun.COM
6129162SPeter.Dunlap@Sun.COM /*
6139162SPeter.Dunlap@Sun.COM * Copy header and data into connection structure so iscsi_login()
6149162SPeter.Dunlap@Sun.COM * can process it.
6159162SPeter.Dunlap@Sun.COM */
6169162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_login_mutex);
6179162SPeter.Dunlap@Sun.COM /*
6189162SPeter.Dunlap@Sun.COM * If conn_login_state != LOGIN_TX then we are not ready to handle
6199162SPeter.Dunlap@Sun.COM * this login response and we should just drop it.
6209162SPeter.Dunlap@Sun.COM */
6219162SPeter.Dunlap@Sun.COM if (icp->conn_login_state == LOGIN_TX) {
6229162SPeter.Dunlap@Sun.COM icp->conn_login_datalen = pdu->isp_datalen;
6239162SPeter.Dunlap@Sun.COM bcopy(pdu->isp_hdr, &icp->conn_login_resp_hdr,
6249162SPeter.Dunlap@Sun.COM sizeof (iscsi_hdr_t));
6259162SPeter.Dunlap@Sun.COM /*
6269162SPeter.Dunlap@Sun.COM * Login code is sloppy with it's NULL handling so make sure
6279162SPeter.Dunlap@Sun.COM * we don't leave any stale data in there.
6289162SPeter.Dunlap@Sun.COM */
6299162SPeter.Dunlap@Sun.COM bzero(icp->conn_login_data, icp->conn_login_max_data_length);
6309162SPeter.Dunlap@Sun.COM bcopy(pdu->isp_data, icp->conn_login_data,
6319162SPeter.Dunlap@Sun.COM MIN(pdu->isp_datalen, icp->conn_login_max_data_length));
6329162SPeter.Dunlap@Sun.COM iscsi_login_update_state_locked(icp, LOGIN_RX);
6339162SPeter.Dunlap@Sun.COM }
6349162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_login_mutex);
6359162SPeter.Dunlap@Sun.COM
6369162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
6379162SPeter.Dunlap@Sun.COM }
6389162SPeter.Dunlap@Sun.COM
6399162SPeter.Dunlap@Sun.COM /*
6409162SPeter.Dunlap@Sun.COM * iscsi_rx_process_cmd_rsp - Process received scsi command response. This
6419162SPeter.Dunlap@Sun.COM * will contain sense data if the command was not successful. This data needs
6429162SPeter.Dunlap@Sun.COM * to be copied into the scsi_pkt. Otherwise we just complete the IO.
6439162SPeter.Dunlap@Sun.COM */
6449162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_cmd_rsp(idm_conn_t * ic,idm_pdu_t * pdu)6459162SPeter.Dunlap@Sun.COM iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
6469162SPeter.Dunlap@Sun.COM {
6479162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
6489162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = icp->conn_sess;
6499162SPeter.Dunlap@Sun.COM iscsi_scsi_rsp_hdr_t *issrhp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
6509162SPeter.Dunlap@Sun.COM uint8_t *data = pdu->isp_data;
6519162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp = NULL;
6529162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt = NULL;
6539162SPeter.Dunlap@Sun.COM idm_status_t rval;
6549162SPeter.Dunlap@Sun.COM struct buf *bp;
6559780SBing.Zhao@Sun.COM boolean_t flush = B_FALSE;
6569780SBing.Zhao@Sun.COM uint32_t cmd_sn = 0;
6579780SBing.Zhao@Sun.COM uint16_t lun_num = 0;
6589162SPeter.Dunlap@Sun.COM
6599162SPeter.Dunlap@Sun.COM /* make sure we get status in order */
6609162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
6619162SPeter.Dunlap@Sun.COM
6629162SPeter.Dunlap@Sun.COM if ((rval = iscsi_rx_chk(icp, isp, issrhp,
6639162SPeter.Dunlap@Sun.COM &icmdp)) != IDM_STATUS_SUCCESS) {
6649162SPeter.Dunlap@Sun.COM if (icmdp != NULL) {
6659162SPeter.Dunlap@Sun.COM iscsi_task_cleanup(issrhp->opcode, icmdp);
6669162SPeter.Dunlap@Sun.COM }
6679162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
6689162SPeter.Dunlap@Sun.COM return (rval);
6699162SPeter.Dunlap@Sun.COM }
6709162SPeter.Dunlap@Sun.COM
6719162SPeter.Dunlap@Sun.COM /*
6729162SPeter.Dunlap@Sun.COM * If we are in "idm aborting" state then we shouldn't continue
6739162SPeter.Dunlap@Sun.COM * to process this command. By definition this command is no longer
6749162SPeter.Dunlap@Sun.COM * on the active queue so we shouldn't try to remove it either.
6759162SPeter.Dunlap@Sun.COM */
6769162SPeter.Dunlap@Sun.COM mutex_enter(&icmdp->cmd_mutex);
6779162SPeter.Dunlap@Sun.COM if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
6789162SPeter.Dunlap@Sun.COM mutex_exit(&icmdp->cmd_mutex);
6799162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
6809162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
6819162SPeter.Dunlap@Sun.COM }
6829162SPeter.Dunlap@Sun.COM mutex_exit(&icmdp->cmd_mutex);
6839162SPeter.Dunlap@Sun.COM
6849162SPeter.Dunlap@Sun.COM /* Get the IDM buffer and bytes transferred */
6859162SPeter.Dunlap@Sun.COM bp = icmdp->cmd_un.scsi.bp;
6869162SPeter.Dunlap@Sun.COM if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
6879162SPeter.Dunlap@Sun.COM /* Transport tracks bytes transferred so use those counts */
6889162SPeter.Dunlap@Sun.COM if (bp && (bp->b_flags & B_READ)) {
6899162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred +=
6909162SPeter.Dunlap@Sun.COM icmdp->cmd_itp->idt_rx_bytes;
6919162SPeter.Dunlap@Sun.COM } else {
6929162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred +=
6939162SPeter.Dunlap@Sun.COM icmdp->cmd_itp->idt_tx_bytes;
6949162SPeter.Dunlap@Sun.COM }
6959162SPeter.Dunlap@Sun.COM } else {
6969162SPeter.Dunlap@Sun.COM /*
6979162SPeter.Dunlap@Sun.COM * Some transports cannot track the bytes transferred on
6989162SPeter.Dunlap@Sun.COM * the initiator side (like iSER) so we have to use the
6999162SPeter.Dunlap@Sun.COM * status info. If the response field indicates that
7009162SPeter.Dunlap@Sun.COM * the command actually completed then we will assume
7019162SPeter.Dunlap@Sun.COM * the data_transferred value represents the entire buffer
7029162SPeter.Dunlap@Sun.COM * unless the resid field says otherwise. This is a bit
7039162SPeter.Dunlap@Sun.COM * unintuitive but it's really impossible to know what
7049162SPeter.Dunlap@Sun.COM * has been transferred without detailed consideration
7059162SPeter.Dunlap@Sun.COM * of the SCSI status and sense key and that is outside
7069162SPeter.Dunlap@Sun.COM * the scope of the transport. Instead the target/class driver
7079162SPeter.Dunlap@Sun.COM * can consider these values along with the resid and figure
7089162SPeter.Dunlap@Sun.COM * it out. The data_transferred concept is just belt and
7099162SPeter.Dunlap@Sun.COM * suspenders anyway -- RFC 3720 actually explicitly rejects
7109162SPeter.Dunlap@Sun.COM * scoreboarding ("Initiators SHOULD NOT keep track of the
7119162SPeter.Dunlap@Sun.COM * data transferred to or from the target (scoreboarding)")
7129162SPeter.Dunlap@Sun.COM * perhaps for this very reason.
7139162SPeter.Dunlap@Sun.COM */
7149162SPeter.Dunlap@Sun.COM if (issrhp->response != 0) {
7159162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred = 0;
7169162SPeter.Dunlap@Sun.COM } else {
7179162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred =
7189162SPeter.Dunlap@Sun.COM (bp == NULL) ? 0 : bp->b_bcount;
7199162SPeter.Dunlap@Sun.COM if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
7209162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred -=
7219162SPeter.Dunlap@Sun.COM ntohl(issrhp->residual_count);
7229162SPeter.Dunlap@Sun.COM }
7239162SPeter.Dunlap@Sun.COM }
7249162SPeter.Dunlap@Sun.COM }
7259162SPeter.Dunlap@Sun.COM
7269162SPeter.Dunlap@Sun.COM ISCSI_CHECK_SCSI_READ(icmdp, issrhp,
7279162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred,
7289162SPeter.Dunlap@Sun.COM BP_CHECK_THOROUGH);
7299162SPeter.Dunlap@Sun.COM
7309162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu: %p itt:"
7319162SPeter.Dunlap@Sun.COM " %x expcmdsn: %x sess_cmd: %x sess_expcmdsn: %x data_transfered:"
7329162SPeter.Dunlap@Sun.COM " %lu ibp: %p obp: %p", (void *)ic, (void *)pdu, issrhp->itt,
7339162SPeter.Dunlap@Sun.COM issrhp->expcmdsn, isp->sess_cmdsn, isp->sess_expcmdsn,
7349162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred,
7359162SPeter.Dunlap@Sun.COM (void *)icmdp->cmd_un.scsi.ibp_ibuf,
7369162SPeter.Dunlap@Sun.COM (void *)icmdp->cmd_un.scsi.ibp_obuf);
7379162SPeter.Dunlap@Sun.COM
7389162SPeter.Dunlap@Sun.COM iscsi_task_cleanup(issrhp->opcode, icmdp);
7399162SPeter.Dunlap@Sun.COM
7409162SPeter.Dunlap@Sun.COM if (issrhp->response) {
7419162SPeter.Dunlap@Sun.COM /* The target failed the command. */
7429162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu:"
7439162SPeter.Dunlap@Sun.COM " %p response: %d bcount: %lu", (void *)ic, (void *)pdu,
7449162SPeter.Dunlap@Sun.COM issrhp->response, icmdp->cmd_un.scsi.bp->b_bcount);
7459162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
7469162SPeter.Dunlap@Sun.COM pkt->pkt_reason = CMD_TRAN_ERR;
7479162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.bp) {
7489162SPeter.Dunlap@Sun.COM pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount;
7499162SPeter.Dunlap@Sun.COM } else {
7509162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
7519162SPeter.Dunlap@Sun.COM }
7529162SPeter.Dunlap@Sun.COM } else {
7539162SPeter.Dunlap@Sun.COM /* success */
7549162SPeter.Dunlap@Sun.COM iscsi_cmd_rsp_chk(icmdp, issrhp);
7559780SBing.Zhao@Sun.COM flush = iscsi_cmd_rsp_cmd_status(icmdp, issrhp, data);
75611272SMilos.Muzik@Sun.COM
75711272SMilos.Muzik@Sun.COM ASSERT(icmdp->cmd_lun == NULL || icmdp->cmd_lun->lun_num ==
75811272SMilos.Muzik@Sun.COM (icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK));
75911272SMilos.Muzik@Sun.COM
7609780SBing.Zhao@Sun.COM if (flush == B_TRUE) {
7619780SBing.Zhao@Sun.COM cmd_sn = icmdp->cmd_sn;
76211272SMilos.Muzik@Sun.COM lun_num = icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK;
7639780SBing.Zhao@Sun.COM }
7649162SPeter.Dunlap@Sun.COM }
7659162SPeter.Dunlap@Sun.COM
7669162SPeter.Dunlap@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
7679780SBing.Zhao@Sun.COM if (flush == B_TRUE) {
7689780SBing.Zhao@Sun.COM iscsi_flush_cmd_after_reset(cmd_sn, lun_num, icp);
7699780SBing.Zhao@Sun.COM }
7709162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
7719162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
7729162SPeter.Dunlap@Sun.COM }
7739162SPeter.Dunlap@Sun.COM
7749162SPeter.Dunlap@Sun.COM static void
iscsi_data_rsp_pkt(iscsi_cmd_t * icmdp,iscsi_data_rsp_hdr_t * idrhp)7759162SPeter.Dunlap@Sun.COM iscsi_data_rsp_pkt(iscsi_cmd_t *icmdp, iscsi_data_rsp_hdr_t *idrhp)
7769162SPeter.Dunlap@Sun.COM {
7779162SPeter.Dunlap@Sun.COM struct buf *bp = NULL;
7789162SPeter.Dunlap@Sun.COM size_t data_transferred;
7799162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt;
7809162SPeter.Dunlap@Sun.COM
7819162SPeter.Dunlap@Sun.COM bp = icmdp->cmd_un.scsi.bp;
7829162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
7839162SPeter.Dunlap@Sun.COM data_transferred = icmdp->cmd_un.scsi.data_transferred;
7849162SPeter.Dunlap@Sun.COM /*
7859162SPeter.Dunlap@Sun.COM * The command* must be completed now, since we won't get a command
7869162SPeter.Dunlap@Sun.COM * response PDU. The cmd_status and residual_count are
7879162SPeter.Dunlap@Sun.COM * not meaningful unless status_present is set.
7889162SPeter.Dunlap@Sun.COM */
7899162SPeter.Dunlap@Sun.COM pkt->pkt_resid = 0;
7909162SPeter.Dunlap@Sun.COM /* Check the residual count */
7919162SPeter.Dunlap@Sun.COM if (bp && (data_transferred != bp->b_bcount)) {
7929162SPeter.Dunlap@Sun.COM /*
7939162SPeter.Dunlap@Sun.COM * We didn't xfer the expected amount of data -
7949162SPeter.Dunlap@Sun.COM * the residual_count in the header is only valid
7959162SPeter.Dunlap@Sun.COM * if the underflow flag is set.
7969162SPeter.Dunlap@Sun.COM */
7979162SPeter.Dunlap@Sun.COM if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
7989162SPeter.Dunlap@Sun.COM pkt->pkt_resid = ntohl(idrhp->residual_count);
7999162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
8009162SPeter.Dunlap@Sun.COM "underflow: itt: %d "
8019162SPeter.Dunlap@Sun.COM "transferred: %lu count: %lu", idrhp->itt,
8029162SPeter.Dunlap@Sun.COM data_transferred, bp->b_bcount);
8039162SPeter.Dunlap@Sun.COM } else {
8049162SPeter.Dunlap@Sun.COM if (bp->b_bcount > data_transferred) {
8059162SPeter.Dunlap@Sun.COM /* Some data fell on the floor somehw */
8069162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: "
8079162SPeter.Dunlap@Sun.COM "iscsi_data_rsp_pkt: data fell: itt: %d "
8089162SPeter.Dunlap@Sun.COM "transferred: %lu count: %lu", idrhp->itt,
8099162SPeter.Dunlap@Sun.COM data_transferred, bp->b_bcount);
8109162SPeter.Dunlap@Sun.COM pkt->pkt_resid =
8119162SPeter.Dunlap@Sun.COM bp->b_bcount - data_transferred;
8129162SPeter.Dunlap@Sun.COM }
8139162SPeter.Dunlap@Sun.COM }
8149162SPeter.Dunlap@Sun.COM }
8159162SPeter.Dunlap@Sun.COM
8169162SPeter.Dunlap@Sun.COM pkt->pkt_reason = CMD_CMPLT;
8179162SPeter.Dunlap@Sun.COM pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS);
8189162SPeter.Dunlap@Sun.COM
8199162SPeter.Dunlap@Sun.COM if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) &&
8209162SPeter.Dunlap@Sun.COM (icmdp->cmd_un.scsi.statuslen >=
8219162SPeter.Dunlap@Sun.COM sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) {
8229162SPeter.Dunlap@Sun.COM
8239162SPeter.Dunlap@Sun.COM /*
8249162SPeter.Dunlap@Sun.COM * Not supposed to get exception status here!
8259162SPeter.Dunlap@Sun.COM * We have no request sense data so just do the
8269162SPeter.Dunlap@Sun.COM * best we can
8279162SPeter.Dunlap@Sun.COM */
8289162SPeter.Dunlap@Sun.COM struct scsi_arq_status *arqstat =
8299162SPeter.Dunlap@Sun.COM (struct scsi_arq_status *)pkt->pkt_scbp;
8309162SPeter.Dunlap@Sun.COM
8319162SPeter.Dunlap@Sun.COM
8329162SPeter.Dunlap@Sun.COM bzero(arqstat, sizeof (struct scsi_arq_status));
8339162SPeter.Dunlap@Sun.COM
8349162SPeter.Dunlap@Sun.COM *((uchar_t *)&arqstat->sts_status) =
8359162SPeter.Dunlap@Sun.COM idrhp->cmd_status;
8369162SPeter.Dunlap@Sun.COM
83711271SMilos.Muzik@Sun.COM /* sense residual is set to whole size of sense buffer */
83811271SMilos.Muzik@Sun.COM arqstat->sts_rqpkt_resid = icmdp->cmd_un.scsi.statuslen -
83911271SMilos.Muzik@Sun.COM ISCSI_ARQ_STATUS_NOSENSE_LEN;
8409162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: "
8419162SPeter.Dunlap@Sun.COM "exception status: itt: %d resid: %d",
8429162SPeter.Dunlap@Sun.COM idrhp->itt, arqstat->sts_rqpkt_resid);
8439162SPeter.Dunlap@Sun.COM
8449162SPeter.Dunlap@Sun.COM } else if (pkt->pkt_scbp) {
8459162SPeter.Dunlap@Sun.COM /* just pass along the status we got */
8469162SPeter.Dunlap@Sun.COM pkt->pkt_scbp[0] = idrhp->cmd_status;
8479162SPeter.Dunlap@Sun.COM }
8489162SPeter.Dunlap@Sun.COM }
8499162SPeter.Dunlap@Sun.COM
8509162SPeter.Dunlap@Sun.COM /*
8519162SPeter.Dunlap@Sun.COM * iscsi_rx_process_data_rsp -
8529162SPeter.Dunlap@Sun.COM * This currently processes the final data sequence denoted by the data response
8537836SJohn.Forte@Sun.COM * PDU Status bit being set. We will not receive the SCSI response.
8547836SJohn.Forte@Sun.COM * This bit denotes that the PDU is the successful completion of the
8559162SPeter.Dunlap@Sun.COM * command.
8567836SJohn.Forte@Sun.COM */
8579162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_data_rsp(idm_conn_t * ic,idm_pdu_t * pdu)8589162SPeter.Dunlap@Sun.COM iscsi_rx_process_data_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
8597836SJohn.Forte@Sun.COM {
8609162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = NULL;
8619162SPeter.Dunlap@Sun.COM iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)pdu->isp_hdr;
8629162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp = NULL;
8639162SPeter.Dunlap@Sun.COM struct buf *bp = NULL;
8649162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
8659162SPeter.Dunlap@Sun.COM idm_buf_t *ibp;
8669162SPeter.Dunlap@Sun.COM idm_status_t rval;
8679162SPeter.Dunlap@Sun.COM
8689162SPeter.Dunlap@Sun.COM
8699162SPeter.Dunlap@Sun.COM /* should only call this when the data rsp contains final rsp */
8709162SPeter.Dunlap@Sun.COM ASSERT(idrhp->flags & ISCSI_FLAG_DATA_STATUS);
8717836SJohn.Forte@Sun.COM isp = icp->conn_sess;
8729162SPeter.Dunlap@Sun.COM
8739162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
8749162SPeter.Dunlap@Sun.COM if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)idrhp,
8759162SPeter.Dunlap@Sun.COM &icmdp)) != IDM_STATUS_SUCCESS) {
8769162SPeter.Dunlap@Sun.COM if (icmdp != NULL) {
8779162SPeter.Dunlap@Sun.COM iscsi_task_cleanup(idrhp->opcode, icmdp);
8787836SJohn.Forte@Sun.COM }
8799162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
8809162SPeter.Dunlap@Sun.COM return (rval);
8817836SJohn.Forte@Sun.COM }
8827836SJohn.Forte@Sun.COM
8839162SPeter.Dunlap@Sun.COM /*
8849162SPeter.Dunlap@Sun.COM * If we are in "idm aborting" state then we shouldn't continue
8859162SPeter.Dunlap@Sun.COM * to process this command. By definition this command is no longer
8869162SPeter.Dunlap@Sun.COM * on the active queue so we shouldn't try to remove it either.
8879162SPeter.Dunlap@Sun.COM */
8889162SPeter.Dunlap@Sun.COM mutex_enter(&icmdp->cmd_mutex);
8899162SPeter.Dunlap@Sun.COM if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) {
8909162SPeter.Dunlap@Sun.COM mutex_exit(&icmdp->cmd_mutex);
8917836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
8929162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
8937836SJohn.Forte@Sun.COM }
8949162SPeter.Dunlap@Sun.COM mutex_exit(&icmdp->cmd_mutex);
8959162SPeter.Dunlap@Sun.COM
8967836SJohn.Forte@Sun.COM /*
8977836SJohn.Forte@Sun.COM * Holding the pending/active queue locks across the
8987836SJohn.Forte@Sun.COM * iscsi_rx_data call later in this function may cause
8997836SJohn.Forte@Sun.COM * deadlock during fault injections. Instead remove
9007836SJohn.Forte@Sun.COM * the cmd from the active queue and release the locks.
9017836SJohn.Forte@Sun.COM * Then before returning or completing the command
9027836SJohn.Forte@Sun.COM * return the cmd to the active queue and reacquire
9037836SJohn.Forte@Sun.COM * the locks.
9047836SJohn.Forte@Sun.COM */
9057836SJohn.Forte@Sun.COM iscsi_dequeue_active_cmd(icp, icmdp);
9067836SJohn.Forte@Sun.COM
9077836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
9087836SJohn.Forte@Sun.COM
9097836SJohn.Forte@Sun.COM /* shorthand some values */
9107836SJohn.Forte@Sun.COM bp = icmdp->cmd_un.scsi.bp;
9117836SJohn.Forte@Sun.COM
9127836SJohn.Forte@Sun.COM /*
9137836SJohn.Forte@Sun.COM * some poorly behaved targets have been observed
9147836SJohn.Forte@Sun.COM * sending data-in pdu's during a write operation
9157836SJohn.Forte@Sun.COM */
9167836SJohn.Forte@Sun.COM if (bp != NULL) {
9177836SJohn.Forte@Sun.COM if (!(bp->b_flags & B_READ)) {
9187836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
9197836SJohn.Forte@Sun.COM "iscsi connection(%u) protocol error - "
9207836SJohn.Forte@Sun.COM "received data response during write operation "
9217836SJohn.Forte@Sun.COM "itt:0x%x",
9227836SJohn.Forte@Sun.COM icp->conn_oid, idrhp->itt);
9237836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
9247836SJohn.Forte@Sun.COM iscsi_enqueue_active_cmd(icp, icmdp);
9257836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
9269162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
9277836SJohn.Forte@Sun.COM }
9287836SJohn.Forte@Sun.COM }
9297836SJohn.Forte@Sun.COM
9309162SPeter.Dunlap@Sun.COM ibp = icmdp->cmd_un.scsi.ibp_ibuf;
9319162SPeter.Dunlap@Sun.COM if (ibp == NULL) {
9329162SPeter.Dunlap@Sun.COM /*
9339162SPeter.Dunlap@Sun.COM * After the check of bp above we *should* have a corresponding
9349162SPeter.Dunlap@Sun.COM * idm_buf_t (ibp). It's possible that the original call
9359162SPeter.Dunlap@Sun.COM * to idm_buf_alloc failed due to a pending connection state
9369162SPeter.Dunlap@Sun.COM * transition in which case this value can be NULL. It's
9379162SPeter.Dunlap@Sun.COM * highly unlikely that the connection would be shutting down
9389162SPeter.Dunlap@Sun.COM * *and* we manage to process a data response and get to this
9399162SPeter.Dunlap@Sun.COM * point in the code but just in case we should check for it.
9409162SPeter.Dunlap@Sun.COM * This isn't really a protocol error -- we are almost certainly
9419162SPeter.Dunlap@Sun.COM * closing the connection anyway so just return a generic error.
9429162SPeter.Dunlap@Sun.COM */
9437836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
9447836SJohn.Forte@Sun.COM iscsi_enqueue_active_cmd(icp, icmdp);
9457836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
9469162SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL);
9477836SJohn.Forte@Sun.COM }
9487836SJohn.Forte@Sun.COM
9499162SPeter.Dunlap@Sun.COM if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) {
9509162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred =
9519162SPeter.Dunlap@Sun.COM icmdp->cmd_itp->idt_rx_bytes;
9527836SJohn.Forte@Sun.COM } else {
9539162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred = bp->b_bcount;
9549162SPeter.Dunlap@Sun.COM if (idrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
9559162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred -=
9569162SPeter.Dunlap@Sun.COM ntohl(idrhp->residual_count);
9579162SPeter.Dunlap@Sun.COM }
9587836SJohn.Forte@Sun.COM }
9597836SJohn.Forte@Sun.COM
9609162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_data_rsp: icp: %p pdu: %p "
9619162SPeter.Dunlap@Sun.COM "itt: %d ibp: %p icmdp: %p xfer_len: %lu transferred: %lu dlen: %u",
9629162SPeter.Dunlap@Sun.COM (void *)icp, (void *)pdu, idrhp->itt, (void *)bp, (void *)icmdp,
9639162SPeter.Dunlap@Sun.COM (ibp == NULL) ? 0 : ibp->idb_xfer_len,
9649162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred,
9659162SPeter.Dunlap@Sun.COM n2h24(idrhp->dlength));
9669162SPeter.Dunlap@Sun.COM
9679162SPeter.Dunlap@Sun.COM iscsi_task_cleanup(idrhp->opcode, icmdp);
9689162SPeter.Dunlap@Sun.COM
9699162SPeter.Dunlap@Sun.COM iscsi_data_rsp_pkt(icmdp, idrhp);
9709162SPeter.Dunlap@Sun.COM
9717836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
9729162SPeter.Dunlap@Sun.COM iscsi_enqueue_active_cmd(icp, icmdp);
9737836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
9747836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
9757836SJohn.Forte@Sun.COM
9769162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
9777836SJohn.Forte@Sun.COM }
9787836SJohn.Forte@Sun.COM
9797836SJohn.Forte@Sun.COM /*
9807836SJohn.Forte@Sun.COM * iscsi_rx_process_nop - Process a received nop. If nop is in response
9817836SJohn.Forte@Sun.COM * to a ping we sent update stats. If initiated by the target we need
9827836SJohn.Forte@Sun.COM * to response back to the target with a nop. Schedule the response.
9837836SJohn.Forte@Sun.COM */
9847836SJohn.Forte@Sun.COM /* ARGSUSED */
9859162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_nop(idm_conn_t * ic,idm_pdu_t * pdu)9869162SPeter.Dunlap@Sun.COM iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu)
9877836SJohn.Forte@Sun.COM {
9887836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
9899162SPeter.Dunlap@Sun.COM iscsi_nop_in_hdr_t *inihp = (iscsi_nop_in_hdr_t *)pdu->isp_hdr;
9907836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
9919162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
9929162SPeter.Dunlap@Sun.COM
9939162SPeter.Dunlap@Sun.COM if (icp->conn_expstatsn != ntohl(inihp->statsn)) {
9949162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
9959162SPeter.Dunlap@Sun.COM "received status out of order itt:0x%x statsn:0x%x "
9969162SPeter.Dunlap@Sun.COM "expstatsn:0x%x", icp->conn_oid, inihp->opcode, inihp->itt,
9979162SPeter.Dunlap@Sun.COM ntohl(inihp->statsn), icp->conn_expstatsn);
9989162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
9999162SPeter.Dunlap@Sun.COM }
10007836SJohn.Forte@Sun.COM isp = icp->conn_sess;
10017836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
10027836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
10037836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
10047836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
10057836SJohn.Forte@Sun.COM if (inihp->itt != ISCSI_RSVD_TASK_TAG) {
10067836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
10079162SPeter.Dunlap@Sun.COM isp, (iscsi_hdr_t *)inihp, &icmdp))) {
10089162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
10099162SPeter.Dunlap@Sun.COM "- can not find cmd for itt:0x%x",
10109162SPeter.Dunlap@Sun.COM icp->conn_oid, inihp->itt);
10117836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
10127836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
10137836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
10149162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
10157836SJohn.Forte@Sun.COM }
10167836SJohn.Forte@Sun.COM }
10177836SJohn.Forte@Sun.COM
10187836SJohn.Forte@Sun.COM /* update expcmdsn and maxcmdsn */
10197836SJohn.Forte@Sun.COM iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn),
10207836SJohn.Forte@Sun.COM ntohl(inihp->expcmdsn));
10217836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
10227836SJohn.Forte@Sun.COM
10237836SJohn.Forte@Sun.COM if ((inihp->itt != ISCSI_RSVD_TASK_TAG) &&
10247836SJohn.Forte@Sun.COM (inihp->ttt == ISCSI_RSVD_TASK_TAG)) {
10257836SJohn.Forte@Sun.COM /* This is the only type of nop that incs. the expstatsn */
10267836SJohn.Forte@Sun.COM icp->conn_expstatsn++;
10277836SJohn.Forte@Sun.COM
10287836SJohn.Forte@Sun.COM /*
10297836SJohn.Forte@Sun.COM * This is a targets response to our nop
10307836SJohn.Forte@Sun.COM */
10317836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
10327836SJohn.Forte@Sun.COM } else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) {
10337836SJohn.Forte@Sun.COM /*
10347836SJohn.Forte@Sun.COM * Target requested a nop. Send one.
10357836SJohn.Forte@Sun.COM */
10367836SJohn.Forte@Sun.COM iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt);
10377836SJohn.Forte@Sun.COM } else {
10387836SJohn.Forte@Sun.COM /*
10397836SJohn.Forte@Sun.COM * This is a target-initiated ping that doesn't expect
10407836SJohn.Forte@Sun.COM * a response; nothing to do except update our flow control
10417836SJohn.Forte@Sun.COM * (which we do in all cases above).
10427836SJohn.Forte@Sun.COM */
10437836SJohn.Forte@Sun.COM /* EMPTY */
10447836SJohn.Forte@Sun.COM }
10457836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
10467836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
10477836SJohn.Forte@Sun.COM
10489162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
10497836SJohn.Forte@Sun.COM }
10507836SJohn.Forte@Sun.COM
10517836SJohn.Forte@Sun.COM
10527836SJohn.Forte@Sun.COM /*
10537836SJohn.Forte@Sun.COM * iscsi_rx_process_reject_rsp - The server rejected a PDU
10547836SJohn.Forte@Sun.COM */
10559162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_reject_rsp(idm_conn_t * ic,idm_pdu_t * pdu)10569162SPeter.Dunlap@Sun.COM iscsi_rx_process_reject_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
10577836SJohn.Forte@Sun.COM {
10589162SPeter.Dunlap@Sun.COM iscsi_reject_rsp_hdr_t *irrhp = (iscsi_reject_rsp_hdr_t *)pdu->isp_hdr;
10599162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = NULL;
10609162SPeter.Dunlap@Sun.COM uint32_t dlength = 0;
10619162SPeter.Dunlap@Sun.COM iscsi_hdr_t *old_ihp = NULL;
10629162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
10639162SPeter.Dunlap@Sun.COM uint8_t *data = pdu->isp_data;
106411088SBing.Zhao@Sun.COM idm_status_t status = IDM_STATUS_SUCCESS;
106511088SBing.Zhao@Sun.COM int i = 0;
10669162SPeter.Dunlap@Sun.COM
10677836SJohn.Forte@Sun.COM ASSERT(data != NULL);
10689162SPeter.Dunlap@Sun.COM isp = icp->conn_sess;
10699162SPeter.Dunlap@Sun.COM ASSERT(isp != NULL);
10709162SPeter.Dunlap@Sun.COM
107111088SBing.Zhao@Sun.COM /*
107211088SBing.Zhao@Sun.COM * In RFC3720 section 10.17, this 4 bytes should be all 0xff.
107311088SBing.Zhao@Sun.COM */
107411088SBing.Zhao@Sun.COM for (i = 0; i < 4; i++) {
107511088SBing.Zhao@Sun.COM if (irrhp->must_be_ff[i] != 0xff) {
107611088SBing.Zhao@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
107711088SBing.Zhao@Sun.COM }
10787836SJohn.Forte@Sun.COM }
107911088SBing.Zhao@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
108011088SBing.Zhao@Sun.COM
108111088SBing.Zhao@Sun.COM if (icp->conn_expstatsn == ntohl(irrhp->statsn)) {
108211088SBing.Zhao@Sun.COM icp->conn_expstatsn++;
108311088SBing.Zhao@Sun.COM } else {
108411088SBing.Zhao@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
108511088SBing.Zhao@Sun.COM "received status out of order statsn:0x%x "
108611088SBing.Zhao@Sun.COM "expstatsn:0x%x", icp->conn_oid, irrhp->opcode,
108711088SBing.Zhao@Sun.COM ntohl(irrhp->statsn), icp->conn_expstatsn);
108811088SBing.Zhao@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
108911088SBing.Zhao@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
109011088SBing.Zhao@Sun.COM }
109111088SBing.Zhao@Sun.COM /* update expcmdsn and maxcmdsn */
109211088SBing.Zhao@Sun.COM iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn),
109311088SBing.Zhao@Sun.COM ntohl(irrhp->expcmdsn));
109411088SBing.Zhao@Sun.COM
109511088SBing.Zhao@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
10967836SJohn.Forte@Sun.COM
10977836SJohn.Forte@Sun.COM /* If we don't have the rejected header we can't do anything */
10987836SJohn.Forte@Sun.COM dlength = n2h24(irrhp->dlength);
10997836SJohn.Forte@Sun.COM if (dlength < sizeof (iscsi_hdr_t)) {
11009162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
11017836SJohn.Forte@Sun.COM }
11027836SJohn.Forte@Sun.COM
11037836SJohn.Forte@Sun.COM /* map old ihp */
11047836SJohn.Forte@Sun.COM old_ihp = (iscsi_hdr_t *)data;
11057836SJohn.Forte@Sun.COM
11067836SJohn.Forte@Sun.COM switch (irrhp->reason) {
11077836SJohn.Forte@Sun.COM /*
11087836SJohn.Forte@Sun.COM * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject
11097836SJohn.Forte@Sun.COM * too many immediate commands (original cmd can be resent)
11107836SJohn.Forte@Sun.COM */
11117836SJohn.Forte@Sun.COM case ISCSI_REJECT_IMM_CMD_REJECT:
11127836SJohn.Forte@Sun.COM /*
11137836SJohn.Forte@Sun.COM * We have exceeded the server's capacity for outstanding
11147836SJohn.Forte@Sun.COM * immediate commands. This must be a task management
11157836SJohn.Forte@Sun.COM * command so try to find it in the abortingqueue and
11167836SJohn.Forte@Sun.COM * complete it.
11177836SJohn.Forte@Sun.COM */
11187836SJohn.Forte@Sun.COM if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) {
11197836SJohn.Forte@Sun.COM /* Rejecting IMM but old old_hdr wasn't IMM */
11209162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
11217836SJohn.Forte@Sun.COM }
11227836SJohn.Forte@Sun.COM
11237836SJohn.Forte@Sun.COM /*
11247836SJohn.Forte@Sun.COM * We only send NOP and TASK_MGT as IMM. All other
11257836SJohn.Forte@Sun.COM * cases should be considered as a protocol error.
11267836SJohn.Forte@Sun.COM */
11277836SJohn.Forte@Sun.COM switch (old_ihp->opcode & ISCSI_OPCODE_MASK) {
11287836SJohn.Forte@Sun.COM case ISCSI_OP_NOOP_OUT:
11297836SJohn.Forte@Sun.COM /*
11307836SJohn.Forte@Sun.COM * A ping was rejected - treat this like
11317836SJohn.Forte@Sun.COM * ping response. The down side is we
11327836SJohn.Forte@Sun.COM * didn't get an updated MaxCmdSn.
11337836SJohn.Forte@Sun.COM */
11347836SJohn.Forte@Sun.COM break;
11357836SJohn.Forte@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG:
113611088SBing.Zhao@Sun.COM status =
113711088SBing.Zhao@Sun.COM iscsi_rx_process_rejected_tsk_mgt(ic, old_ihp);
11387836SJohn.Forte@Sun.COM break;
11397836SJohn.Forte@Sun.COM default:
11407836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
11417836SJohn.Forte@Sun.COM "- received a reject for a command(0x%02x) not "
11427836SJohn.Forte@Sun.COM "sent as an immediate", icp->conn_oid,
11437836SJohn.Forte@Sun.COM old_ihp->opcode);
11449162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
11459162SPeter.Dunlap@Sun.COM break;
11467836SJohn.Forte@Sun.COM }
11477836SJohn.Forte@Sun.COM break;
11487836SJohn.Forte@Sun.COM
11497836SJohn.Forte@Sun.COM /*
11507836SJohn.Forte@Sun.COM * For the rest of the reject cases just use the general
11517836SJohn.Forte@Sun.COM * hammer of dis/reconnecting. This will resolve all
11527836SJohn.Forte@Sun.COM * noted issues although could be more graceful.
11537836SJohn.Forte@Sun.COM */
11547836SJohn.Forte@Sun.COM case ISCSI_REJECT_DATA_DIGEST_ERROR:
11557836SJohn.Forte@Sun.COM case ISCSI_REJECT_CMD_BEFORE_LOGIN:
11567836SJohn.Forte@Sun.COM case ISCSI_REJECT_SNACK_REJECT:
11577836SJohn.Forte@Sun.COM case ISCSI_REJECT_PROTOCOL_ERROR:
11587836SJohn.Forte@Sun.COM case ISCSI_REJECT_CMD_NOT_SUPPORTED:
11597836SJohn.Forte@Sun.COM case ISCSI_REJECT_TASK_IN_PROGRESS:
11607836SJohn.Forte@Sun.COM case ISCSI_REJECT_INVALID_DATA_ACK:
11617836SJohn.Forte@Sun.COM case ISCSI_REJECT_INVALID_PDU_FIELD:
11627836SJohn.Forte@Sun.COM case ISCSI_REJECT_LONG_OPERATION_REJECT:
11637836SJohn.Forte@Sun.COM case ISCSI_REJECT_NEGOTIATION_RESET:
11647836SJohn.Forte@Sun.COM default:
116511088SBing.Zhao@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u/%x) closing connection - "
116611088SBing.Zhao@Sun.COM "target requested reason:0x%x",
116711088SBing.Zhao@Sun.COM icp->conn_oid, irrhp->opcode, irrhp->reason);
11689162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
11699162SPeter.Dunlap@Sun.COM break;
11707836SJohn.Forte@Sun.COM }
11717836SJohn.Forte@Sun.COM
117211088SBing.Zhao@Sun.COM return (status);
11737836SJohn.Forte@Sun.COM }
11747836SJohn.Forte@Sun.COM
11757836SJohn.Forte@Sun.COM
11767836SJohn.Forte@Sun.COM /*
11777836SJohn.Forte@Sun.COM * iscsi_rx_process_rejected_tsk_mgt -
11787836SJohn.Forte@Sun.COM */
11799162SPeter.Dunlap@Sun.COM /* ARGSUSED */
11809162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_rejected_tsk_mgt(idm_conn_t * ic,iscsi_hdr_t * old_ihp)11819162SPeter.Dunlap@Sun.COM iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic, iscsi_hdr_t *old_ihp)
11827836SJohn.Forte@Sun.COM {
11839162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = NULL;
11849162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp = NULL;
11859162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = NULL;
11869162SPeter.Dunlap@Sun.COM
11877836SJohn.Forte@Sun.COM isp = icp->conn_sess;
11887836SJohn.Forte@Sun.COM ASSERT(old_ihp != NULL);
11899162SPeter.Dunlap@Sun.COM ASSERT(isp != NULL);
11907836SJohn.Forte@Sun.COM
11917836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
11927836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
11937836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
11947836SJohn.Forte@Sun.COM isp, old_ihp, &icmdp))) {
11957836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
11967836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
11979162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
11987836SJohn.Forte@Sun.COM }
11997836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
12007836SJohn.Forte@Sun.COM
12017836SJohn.Forte@Sun.COM switch (icmdp->cmd_type) {
12027836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_ABORT:
12037836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_RESET:
12047836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4,
12057836SJohn.Forte@Sun.COM icp->conn_sess);
12067836SJohn.Forte@Sun.COM break;
12077836SJohn.Forte@Sun.COM /* We don't send any other task mgr types */
12087836SJohn.Forte@Sun.COM default:
12097836SJohn.Forte@Sun.COM ASSERT(B_FALSE);
12107836SJohn.Forte@Sun.COM break;
12117836SJohn.Forte@Sun.COM }
12127836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
12137836SJohn.Forte@Sun.COM
12149162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
12157836SJohn.Forte@Sun.COM }
12167836SJohn.Forte@Sun.COM
12177836SJohn.Forte@Sun.COM
12187836SJohn.Forte@Sun.COM /*
12197836SJohn.Forte@Sun.COM * iscsi_rx_process_task_mgt_rsp -
12207836SJohn.Forte@Sun.COM */
12217836SJohn.Forte@Sun.COM /* ARGSUSED */
12229162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_task_mgt_rsp(idm_conn_t * ic,idm_pdu_t * pdu)12239162SPeter.Dunlap@Sun.COM iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
12247836SJohn.Forte@Sun.COM {
12257836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
12267836SJohn.Forte@Sun.COM iscsi_scsi_task_mgt_rsp_hdr_t *istmrhp = NULL;
12277836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
12289162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
12299162SPeter.Dunlap@Sun.COM idm_status_t status = IDM_STATUS_SUCCESS;
12309162SPeter.Dunlap@Sun.COM
12317836SJohn.Forte@Sun.COM isp = icp->conn_sess;
12329162SPeter.Dunlap@Sun.COM istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr;
12339162SPeter.Dunlap@Sun.COM
12349162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
12359162SPeter.Dunlap@Sun.COM if ((status = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)istmrhp,
12369162SPeter.Dunlap@Sun.COM &icmdp)) != IDM_STATUS_SUCCESS) {
12379162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
12389162SPeter.Dunlap@Sun.COM return (status);
12397836SJohn.Forte@Sun.COM }
12407836SJohn.Forte@Sun.COM
12417836SJohn.Forte@Sun.COM switch (icmdp->cmd_type) {
12427836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_ABORT:
12437836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_RESET:
12447836SJohn.Forte@Sun.COM switch (istmrhp->response) {
12457836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_COMPLETE:
12467836SJohn.Forte@Sun.COM /* success */
12477836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp,
12487836SJohn.Forte@Sun.COM ISCSI_CMD_EVENT_E3, isp);
12497836SJohn.Forte@Sun.COM break;
12507836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_NO_TASK:
12517836SJohn.Forte@Sun.COM /*
12527836SJohn.Forte@Sun.COM * If the array no longer knows about
12537836SJohn.Forte@Sun.COM * an ABORT RTT and we no longer have
12547836SJohn.Forte@Sun.COM * a parent SCSI command it was just
12557836SJohn.Forte@Sun.COM * completed, free this ABORT resource.
12567836SJohn.Forte@Sun.COM * Otherwise FALLTHRU this will flag a
12577836SJohn.Forte@Sun.COM * protocol problem.
12587836SJohn.Forte@Sun.COM */
12597836SJohn.Forte@Sun.COM if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) &&
12607836SJohn.Forte@Sun.COM (icmdp->cmd_un.abort.icmdp == NULL)) {
12617836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp,
12627836SJohn.Forte@Sun.COM ISCSI_CMD_EVENT_E4, isp);
12637836SJohn.Forte@Sun.COM break;
12647836SJohn.Forte@Sun.COM }
12657836SJohn.Forte@Sun.COM /* FALLTHRU */
12669780SBing.Zhao@Sun.COM case SCSI_TCP_TM_RESP_REJECTED:
12679780SBing.Zhao@Sun.COM /*
12689780SBing.Zhao@Sun.COM * If the target rejects our reset task,
12699780SBing.Zhao@Sun.COM * we should record the response and complete
12709780SBing.Zhao@Sun.COM * this command with the result.
12719780SBing.Zhao@Sun.COM */
12729780SBing.Zhao@Sun.COM if (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET) {
12739780SBing.Zhao@Sun.COM icmdp->cmd_un.reset.response =
12749780SBing.Zhao@Sun.COM istmrhp->response;
12759780SBing.Zhao@Sun.COM iscsi_cmd_state_machine(icmdp,
12769780SBing.Zhao@Sun.COM ISCSI_CMD_EVENT_E3, isp);
12779780SBing.Zhao@Sun.COM break;
12789780SBing.Zhao@Sun.COM }
12799780SBing.Zhao@Sun.COM /* FALLTHRU */
12807836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_NO_LUN:
12817836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_TASK_ALLEGIANT:
12827836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_NO_FAILOVER:
12837836SJohn.Forte@Sun.COM case SCSI_TCP_TM_RESP_IN_PRGRESS:
12847836SJohn.Forte@Sun.COM default:
12857836SJohn.Forte@Sun.COM /*
12867836SJohn.Forte@Sun.COM * Something is out of sync. Flush
12877836SJohn.Forte@Sun.COM * active queues and resync the
12887836SJohn.Forte@Sun.COM * the connection to try and recover
12897836SJohn.Forte@Sun.COM * to a known state.
12907836SJohn.Forte@Sun.COM */
12919162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
12927836SJohn.Forte@Sun.COM }
12937836SJohn.Forte@Sun.COM break;
12947836SJohn.Forte@Sun.COM
12957836SJohn.Forte@Sun.COM default:
12967836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
12977836SJohn.Forte@Sun.COM "received a task mgt response for a non-task mgt "
12987836SJohn.Forte@Sun.COM "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt,
12997836SJohn.Forte@Sun.COM icmdp->cmd_type);
13009162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
13019162SPeter.Dunlap@Sun.COM break;
13027836SJohn.Forte@Sun.COM }
13037836SJohn.Forte@Sun.COM
13047836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
13059162SPeter.Dunlap@Sun.COM return (status);
13067836SJohn.Forte@Sun.COM }
13077836SJohn.Forte@Sun.COM
13087836SJohn.Forte@Sun.COM
13097836SJohn.Forte@Sun.COM /*
13109162SPeter.Dunlap@Sun.COM * iscsi_rx_process_logout_rsp -
13117836SJohn.Forte@Sun.COM *
13127836SJohn.Forte@Sun.COM */
13137836SJohn.Forte@Sun.COM /* ARGSUSED */
13149162SPeter.Dunlap@Sun.COM idm_status_t
iscsi_rx_process_logout_rsp(idm_conn_t * ic,idm_pdu_t * pdu)13159162SPeter.Dunlap@Sun.COM iscsi_rx_process_logout_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
13167836SJohn.Forte@Sun.COM {
13179162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
13189162SPeter.Dunlap@Sun.COM iscsi_logout_rsp_hdr_t *ilrhp =
13199162SPeter.Dunlap@Sun.COM (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr;
13207836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
13219162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp;
13229162SPeter.Dunlap@Sun.COM idm_status_t status = IDM_STATUS_SUCCESS;
13239162SPeter.Dunlap@Sun.COM
13247836SJohn.Forte@Sun.COM isp = icp->conn_sess;
13257836SJohn.Forte@Sun.COM
13267836SJohn.Forte@Sun.COM if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) {
13279162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - "
13287836SJohn.Forte@Sun.COM "received status out of order itt:0x%x statsn:0x%x "
13299162SPeter.Dunlap@Sun.COM "expstatsn:0x%x", icp->conn_oid, ilrhp->opcode, ilrhp->itt,
13307836SJohn.Forte@Sun.COM ntohl(ilrhp->statsn), icp->conn_expstatsn);
13319162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
13327836SJohn.Forte@Sun.COM }
13337836SJohn.Forte@Sun.COM
13347836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
13357836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
13367836SJohn.Forte@Sun.COM if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) {
13377836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(
13389162SPeter.Dunlap@Sun.COM isp, (iscsi_hdr_t *)ilrhp, &icmdp))) {
13397836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
13407836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
13419162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
13427836SJohn.Forte@Sun.COM }
13437836SJohn.Forte@Sun.COM }
13447836SJohn.Forte@Sun.COM
13457836SJohn.Forte@Sun.COM /* update expcmdsn and maxcmdsn */
13467836SJohn.Forte@Sun.COM iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn),
13477836SJohn.Forte@Sun.COM ntohl(ilrhp->expcmdsn));
13487836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
13497836SJohn.Forte@Sun.COM
13509162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
13519162SPeter.Dunlap@Sun.COM "DEBUG: iscsi_rx_process_logout_rsp: response: %d",
13529162SPeter.Dunlap@Sun.COM ilrhp->response);
13537836SJohn.Forte@Sun.COM switch (ilrhp->response) {
13547836SJohn.Forte@Sun.COM case ISCSI_LOGOUT_CID_NOT_FOUND:
13557836SJohn.Forte@Sun.COM /*
13567836SJohn.Forte@Sun.COM * If the target doesn't know about our connection
13577836SJohn.Forte@Sun.COM * then we can consider our self disconnected.
13587836SJohn.Forte@Sun.COM */
13597836SJohn.Forte@Sun.COM /* FALLTHRU */
13607836SJohn.Forte@Sun.COM case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
13617836SJohn.Forte@Sun.COM /*
13627836SJohn.Forte@Sun.COM * We don't support ErrorRecovery levels above 0
13637836SJohn.Forte@Sun.COM * currently so consider this success.
13647836SJohn.Forte@Sun.COM */
13657836SJohn.Forte@Sun.COM /* FALLTHRU */
13667836SJohn.Forte@Sun.COM case ISCSI_LOGOUT_CLEANUP_FAILED:
13677836SJohn.Forte@Sun.COM /*
13687836SJohn.Forte@Sun.COM * per spec. "cleanup failed for various reasons."
13697836SJohn.Forte@Sun.COM * Although those various reasons are undefined.
13707836SJohn.Forte@Sun.COM * Not sure what to do here. So fake success,
13717836SJohn.Forte@Sun.COM * which will disconnect the connection.
13727836SJohn.Forte@Sun.COM */
13737836SJohn.Forte@Sun.COM /* FALLTHRU */
13747836SJohn.Forte@Sun.COM case ISCSI_LOGOUT_SUCCESS:
13757836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
13767836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
13779162SPeter.Dunlap@Sun.COM iscsi_drop_conn_cleanup(icp);
13787836SJohn.Forte@Sun.COM break;
13797836SJohn.Forte@Sun.COM default:
13807836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
13819162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
13829162SPeter.Dunlap@Sun.COM break;
13839162SPeter.Dunlap@Sun.COM
13847836SJohn.Forte@Sun.COM }
13859162SPeter.Dunlap@Sun.COM return (status);
13867836SJohn.Forte@Sun.COM }
13877836SJohn.Forte@Sun.COM
13887836SJohn.Forte@Sun.COM /*
13899162SPeter.Dunlap@Sun.COM * iscsi_rx_process_async_rsp
13907836SJohn.Forte@Sun.COM *
13917836SJohn.Forte@Sun.COM */
13927836SJohn.Forte@Sun.COM /* ARGSUSED */
13939162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_async_rsp(idm_conn_t * ic,idm_pdu_t * pdu)13949162SPeter.Dunlap@Sun.COM iscsi_rx_process_async_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
13957836SJohn.Forte@Sun.COM {
13969162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
13979162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = icp->conn_sess;
13989162SPeter.Dunlap@Sun.COM idm_status_t rval = IDM_STATUS_SUCCESS;
13999162SPeter.Dunlap@Sun.COM iscsi_task_t *itp;
14009162SPeter.Dunlap@Sun.COM iscsi_async_evt_hdr_t *iaehp =
14019162SPeter.Dunlap@Sun.COM (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
14027836SJohn.Forte@Sun.COM
14037836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
14049162SPeter.Dunlap@Sun.COM ASSERT(pdu != NULL);
14059162SPeter.Dunlap@Sun.COM ASSERT(isp != NULL);
14069162SPeter.Dunlap@Sun.COM
14079162SPeter.Dunlap@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
14089162SPeter.Dunlap@Sun.COM if (icp->conn_expstatsn == ntohl(iaehp->statsn)) {
14099162SPeter.Dunlap@Sun.COM icp->conn_expstatsn++;
14109162SPeter.Dunlap@Sun.COM } else {
14117836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
14129162SPeter.Dunlap@Sun.COM "received status out of order statsn:0x%x "
14139162SPeter.Dunlap@Sun.COM "expstatsn:0x%x", icp->conn_oid,
14147836SJohn.Forte@Sun.COM ntohl(iaehp->statsn), icp->conn_expstatsn);
14159162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
14169162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
14177836SJohn.Forte@Sun.COM }
14189162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
14197836SJohn.Forte@Sun.COM
14207836SJohn.Forte@Sun.COM switch (iaehp->async_event) {
14217836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_SCSI_EVENT:
14227836SJohn.Forte@Sun.COM /*
14237836SJohn.Forte@Sun.COM * SCSI asynchronous event is reported in
14247836SJohn.Forte@Sun.COM * the sense data. Sense data that accompanies
14257836SJohn.Forte@Sun.COM * the report in the data segment identifies the
14267836SJohn.Forte@Sun.COM * condition. If the target supports SCSI
14277836SJohn.Forte@Sun.COM * asynchronous events reporting (see [SAM2])
14287836SJohn.Forte@Sun.COM * as indicated in the stardard INQUIRY data
14297836SJohn.Forte@Sun.COM * (see [SPC3]), its use may be enabled by
14307836SJohn.Forte@Sun.COM * parameters in the SCSI control mode page
14317836SJohn.Forte@Sun.COM * (see [SPC3]).
14327836SJohn.Forte@Sun.COM *
14337836SJohn.Forte@Sun.COM * T-10 has removed SCSI asunchronous events
14347836SJohn.Forte@Sun.COM * from the standard. Although we have seen
14357836SJohn.Forte@Sun.COM * a couple targets still spending these requests.
14367836SJohn.Forte@Sun.COM * Those targets were specifically sending them
14377836SJohn.Forte@Sun.COM * for notification of a LUN/Volume change
1438*12161SJack.Meng@Sun.COM * (ex. LUN addition/removal). Fire the enumeration
1439*12161SJack.Meng@Sun.COM * to handle the change.
14407836SJohn.Forte@Sun.COM */
1441*12161SJack.Meng@Sun.COM if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
1442*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
1443*12161SJack.Meng@Sun.COM if (isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) {
1444*12161SJack.Meng@Sun.COM (void) iscsi_sess_enum_request(isp, B_FALSE,
1445*12161SJack.Meng@Sun.COM isp->sess_state_event_count);
1446*12161SJack.Meng@Sun.COM }
1447*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
1448*12161SJack.Meng@Sun.COM }
14497836SJohn.Forte@Sun.COM break;
14507836SJohn.Forte@Sun.COM
14517836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
14529162SPeter.Dunlap@Sun.COM /*
14539162SPeter.Dunlap@Sun.COM * We've been asked to logout by the target --
14549162SPeter.Dunlap@Sun.COM * we need to treat this differently from a normal logout
14559162SPeter.Dunlap@Sun.COM * due to a discovery failure. Normal logouts result in
14569162SPeter.Dunlap@Sun.COM * an N3 event to the session state machine and an offline
14579162SPeter.Dunlap@Sun.COM * of the lun. In this case we want to put the connection
14589162SPeter.Dunlap@Sun.COM * into "failed" state and generate N5 to the session state
14599162SPeter.Dunlap@Sun.COM * machine since the initiator logged out at the target's
14609162SPeter.Dunlap@Sun.COM * request. To track this we set a flag indicating we
14619162SPeter.Dunlap@Sun.COM * received this async logout request from the tharget
14629162SPeter.Dunlap@Sun.COM */
14637836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_state_mutex);
14649162SPeter.Dunlap@Sun.COM icp->conn_async_logout = B_TRUE;
14657836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_state_mutex);
14669162SPeter.Dunlap@Sun.COM
146711078SPeter.Cudhea@Sun.COM /* Hold is released in iscsi_handle_logout. */
146811078SPeter.Cudhea@Sun.COM idm_conn_hold(ic);
146911078SPeter.Cudhea@Sun.COM
14709162SPeter.Dunlap@Sun.COM /* Target has requested this connection to logout. */
14719162SPeter.Dunlap@Sun.COM itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
14729162SPeter.Dunlap@Sun.COM itp->t_arg = icp;
14739162SPeter.Dunlap@Sun.COM itp->t_blocking = B_FALSE;
1474*12161SJack.Meng@Sun.COM if (ddi_taskq_dispatch(isp->sess_login_taskq,
14759162SPeter.Dunlap@Sun.COM (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
14769162SPeter.Dunlap@Sun.COM DDI_SUCCESS) {
147711078SPeter.Cudhea@Sun.COM idm_conn_rele(ic);
14789162SPeter.Dunlap@Sun.COM /* Disconnect if we couldn't dispatch the task */
14799162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(ic);
14809162SPeter.Dunlap@Sun.COM }
14817836SJohn.Forte@Sun.COM break;
14827836SJohn.Forte@Sun.COM
14837836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
14847836SJohn.Forte@Sun.COM /*
14857836SJohn.Forte@Sun.COM * Target is going to drop our connection.
14867836SJohn.Forte@Sun.COM * param1 - CID which will be dropped.
14877836SJohn.Forte@Sun.COM * param2 - Min time to reconnect.
14887836SJohn.Forte@Sun.COM * param3 - Max time to reconnect.
14897836SJohn.Forte@Sun.COM *
14907836SJohn.Forte@Sun.COM * For now just let fail as another disconnect.
14917836SJohn.Forte@Sun.COM *
14927836SJohn.Forte@Sun.COM * MC/S Once we support > 1 connections then
14937836SJohn.Forte@Sun.COM * we need to check the CID and drop that
14947836SJohn.Forte@Sun.COM * specific connection.
14957836SJohn.Forte@Sun.COM */
14969162SPeter.Dunlap@Sun.COM iscsi_conn_set_login_min_max(icp, iaehp->param2,
14979162SPeter.Dunlap@Sun.COM iaehp->param3);
14989162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(ic);
14997836SJohn.Forte@Sun.COM break;
15007836SJohn.Forte@Sun.COM
15017836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
15027836SJohn.Forte@Sun.COM /*
15037836SJohn.Forte@Sun.COM * Target is going to drop ALL connections.
15047836SJohn.Forte@Sun.COM * param2 - Min time to reconnect.
15057836SJohn.Forte@Sun.COM * param3 - Max time to reconnect.
15067836SJohn.Forte@Sun.COM *
15077836SJohn.Forte@Sun.COM * For now just let fail as anyother disconnect.
15087836SJohn.Forte@Sun.COM *
15097836SJohn.Forte@Sun.COM * MC/S Once we support more than > 1 connections
15107836SJohn.Forte@Sun.COM * then we need to drop all connections on the
15117836SJohn.Forte@Sun.COM * session.
15127836SJohn.Forte@Sun.COM */
15139162SPeter.Dunlap@Sun.COM iscsi_conn_set_login_min_max(icp, iaehp->param2,
15149162SPeter.Dunlap@Sun.COM iaehp->param3);
15159162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(ic);
15167836SJohn.Forte@Sun.COM break;
15177836SJohn.Forte@Sun.COM
15187836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
15197836SJohn.Forte@Sun.COM /*
15207836SJohn.Forte@Sun.COM * Target requests parameter negotiation
15217836SJohn.Forte@Sun.COM * on this connection.
15227836SJohn.Forte@Sun.COM *
15237836SJohn.Forte@Sun.COM * The initiator must honor this request. For
15247836SJohn.Forte@Sun.COM * now we will request a logout. We can't
15257836SJohn.Forte@Sun.COM * just ignore this or it might force corruption?
15267836SJohn.Forte@Sun.COM */
152711078SPeter.Cudhea@Sun.COM
152811078SPeter.Cudhea@Sun.COM /* Hold is released in iscsi_handle_logout */
152911078SPeter.Cudhea@Sun.COM idm_conn_hold(ic);
15309162SPeter.Dunlap@Sun.COM itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP);
15319162SPeter.Dunlap@Sun.COM itp->t_arg = icp;
15329162SPeter.Dunlap@Sun.COM itp->t_blocking = B_FALSE;
1533*12161SJack.Meng@Sun.COM if (ddi_taskq_dispatch(isp->sess_login_taskq,
15349162SPeter.Dunlap@Sun.COM (void(*)())iscsi_logout_start, itp, DDI_SLEEP) !=
15359162SPeter.Dunlap@Sun.COM DDI_SUCCESS) {
15369162SPeter.Dunlap@Sun.COM /* Disconnect if we couldn't dispatch the task */
153711078SPeter.Cudhea@Sun.COM idm_conn_rele(ic);
15389162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(ic);
15399162SPeter.Dunlap@Sun.COM }
15407836SJohn.Forte@Sun.COM break;
15417836SJohn.Forte@Sun.COM
15427836SJohn.Forte@Sun.COM case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC:
15437836SJohn.Forte@Sun.COM /*
15447836SJohn.Forte@Sun.COM * We currently don't handle any vendor
15457836SJohn.Forte@Sun.COM * specific async events. So just ignore
15467836SJohn.Forte@Sun.COM * the request.
15477836SJohn.Forte@Sun.COM */
15489162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(ic);
15497836SJohn.Forte@Sun.COM break;
15507836SJohn.Forte@Sun.COM default:
15519162SPeter.Dunlap@Sun.COM rval = IDM_STATUS_PROTOCOL_ERROR;
15527836SJohn.Forte@Sun.COM }
15537836SJohn.Forte@Sun.COM
15547836SJohn.Forte@Sun.COM return (rval);
15557836SJohn.Forte@Sun.COM }
15567836SJohn.Forte@Sun.COM
15577836SJohn.Forte@Sun.COM /*
15587836SJohn.Forte@Sun.COM * iscsi_rx_process_text_rsp - processes iSCSI text response. It sets
15597836SJohn.Forte@Sun.COM * the cmd_result field of the command data structure with the actual
15607836SJohn.Forte@Sun.COM * status value instead of returning the status value. The return value
15617836SJohn.Forte@Sun.COM * is SUCCESS in order to let iscsi_handle_text control the operation of
15627836SJohn.Forte@Sun.COM * a text request.
15639162SPeter.Dunlap@Sun.COM * Text requests are a handled a little different than other types of
15647836SJohn.Forte@Sun.COM * iSCSI commands because the initiator sends additional empty text requests
15657836SJohn.Forte@Sun.COM * in order to obtain the remaining responses required to complete the
15667836SJohn.Forte@Sun.COM * request. iscsi_handle_text controls the operation of text request, while
15677836SJohn.Forte@Sun.COM * iscsi_rx_process_text_rsp just process the current response.
15687836SJohn.Forte@Sun.COM */
15699162SPeter.Dunlap@Sun.COM static idm_status_t
iscsi_rx_process_text_rsp(idm_conn_t * ic,idm_pdu_t * pdu)15709162SPeter.Dunlap@Sun.COM iscsi_rx_process_text_rsp(idm_conn_t *ic, idm_pdu_t *pdu)
15717836SJohn.Forte@Sun.COM {
15727836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
15739162SPeter.Dunlap@Sun.COM iscsi_text_rsp_hdr_t *ithp =
15749162SPeter.Dunlap@Sun.COM (iscsi_text_rsp_hdr_t *)pdu->isp_hdr;
15759162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = ic->ic_handle;
15767836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
15777836SJohn.Forte@Sun.COM boolean_t final = B_FALSE;
15787836SJohn.Forte@Sun.COM uint32_t data_len;
15799162SPeter.Dunlap@Sun.COM uint8_t *data = pdu->isp_data;
15809162SPeter.Dunlap@Sun.COM idm_status_t rval;
15817836SJohn.Forte@Sun.COM
15827836SJohn.Forte@Sun.COM isp = icp->conn_sess;
15837836SJohn.Forte@Sun.COM
15847836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
15859162SPeter.Dunlap@Sun.COM if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)ithp,
15869162SPeter.Dunlap@Sun.COM &icmdp)) != IDM_STATUS_SUCCESS) {
15877836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
15889162SPeter.Dunlap@Sun.COM return (rval);
15897836SJohn.Forte@Sun.COM }
15907836SJohn.Forte@Sun.COM
15917836SJohn.Forte@Sun.COM /* update local final response flag */
15927836SJohn.Forte@Sun.COM if (ithp->flags & ISCSI_FLAG_FINAL) {
15937836SJohn.Forte@Sun.COM final = B_TRUE;
15947836SJohn.Forte@Sun.COM }
15957836SJohn.Forte@Sun.COM
15967836SJohn.Forte@Sun.COM /*
15977836SJohn.Forte@Sun.COM * validate received TTT value. RFC3720 specifies the following:
15987836SJohn.Forte@Sun.COM * - F bit set to 1 MUST have a reserved TTT value 0xffffffff
15997836SJohn.Forte@Sun.COM * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff
16007836SJohn.Forte@Sun.COM * In addition, the received TTT value must not change between
16017836SJohn.Forte@Sun.COM * responses of a long text response
16027836SJohn.Forte@Sun.COM */
16037836SJohn.Forte@Sun.COM if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) ||
16047836SJohn.Forte@Sun.COM ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) {
16057836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
16067836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
16077836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
16087836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error - "
16097836SJohn.Forte@Sun.COM "received text response with invalid flags:0x%x or "
16107836SJohn.Forte@Sun.COM "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt);
16119162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
16127836SJohn.Forte@Sun.COM }
16137836SJohn.Forte@Sun.COM
16147836SJohn.Forte@Sun.COM if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) &&
16157836SJohn.Forte@Sun.COM (ithp->ttt == ISCSI_RSVD_TASK_TAG) &&
16167836SJohn.Forte@Sun.COM (final == B_FALSE)) {
16177836SJohn.Forte@Sun.COM /* TTT should have matched reserved value */
16187836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR;
16197836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
16207836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
16217836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol "
16227836SJohn.Forte@Sun.COM "error - received text response with invalid "
16237836SJohn.Forte@Sun.COM "ttt:0x%x", icp->conn_oid, ithp->ttt);
16249162SPeter.Dunlap@Sun.COM return (IDM_STATUS_PROTOCOL_ERROR);
16257836SJohn.Forte@Sun.COM }
16267836SJohn.Forte@Sun.COM
16277836SJohn.Forte@Sun.COM /*
16287836SJohn.Forte@Sun.COM * If this is first response, save away TTT value for later use
16297836SJohn.Forte@Sun.COM * in a long text request/response sequence
16307836SJohn.Forte@Sun.COM */
16317836SJohn.Forte@Sun.COM if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) {
16327836SJohn.Forte@Sun.COM icmdp->cmd_un.text.ttt = ithp->ttt;
16337836SJohn.Forte@Sun.COM }
16347836SJohn.Forte@Sun.COM
16357836SJohn.Forte@Sun.COM data_len = ntoh24(ithp->dlength);
16367836SJohn.Forte@Sun.COM
16377836SJohn.Forte@Sun.COM /* check whether enough buffer available to copy data */
16387836SJohn.Forte@Sun.COM if ((icmdp->cmd_un.text.total_rx_len + data_len) >
16397836SJohn.Forte@Sun.COM icmdp->cmd_un.text.buf_len) {
16407836SJohn.Forte@Sun.COM icmdp->cmd_un.text.total_rx_len += data_len;
16417836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW;
16427836SJohn.Forte@Sun.COM /*
16437836SJohn.Forte@Sun.COM * DATA_OVERFLOW will result in a SUCCESS return so that
16447836SJohn.Forte@Sun.COM * iscsi_handle_text can continue to obtain the remaining
16457836SJohn.Forte@Sun.COM * text response if needed.
16467836SJohn.Forte@Sun.COM */
16477836SJohn.Forte@Sun.COM } else {
16487836SJohn.Forte@Sun.COM char *buf_data = (icmdp->cmd_un.text.buf +
16497836SJohn.Forte@Sun.COM icmdp->cmd_un.text.offset);
16507836SJohn.Forte@Sun.COM
16517836SJohn.Forte@Sun.COM bcopy(data, buf_data, data_len);
16527836SJohn.Forte@Sun.COM icmdp->cmd_un.text.offset += data_len;
16537836SJohn.Forte@Sun.COM icmdp->cmd_un.text.total_rx_len += data_len;
16547836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
16557836SJohn.Forte@Sun.COM bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun,
16567836SJohn.Forte@Sun.COM sizeof (icmdp->cmd_un.text.lun));
16577836SJohn.Forte@Sun.COM }
16587836SJohn.Forte@Sun.COM
16597836SJohn.Forte@Sun.COM /* update stage */
16607836SJohn.Forte@Sun.COM if (final == B_TRUE) {
16617836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
16627836SJohn.Forte@Sun.COM } else {
16637836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
16647836SJohn.Forte@Sun.COM }
16657836SJohn.Forte@Sun.COM
16667836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp);
16677836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
16689162SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
16699162SPeter.Dunlap@Sun.COM }
16709162SPeter.Dunlap@Sun.COM
16719162SPeter.Dunlap@Sun.COM /*
16729162SPeter.Dunlap@Sun.COM * iscsi_rx_process_scsi_itt_to_icmdp - Lookup itt using IDM to find matching
16739162SPeter.Dunlap@Sun.COM * icmdp. Verify itt in hdr and icmdp are the same.
16749162SPeter.Dunlap@Sun.COM */
16759162SPeter.Dunlap@Sun.COM static iscsi_status_t
iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t * isp,idm_conn_t * ic,iscsi_scsi_rsp_hdr_t * ihp,iscsi_cmd_t ** icmdp)16769162SPeter.Dunlap@Sun.COM iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp, idm_conn_t *ic,
16779162SPeter.Dunlap@Sun.COM iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp)
16789162SPeter.Dunlap@Sun.COM {
16799162SPeter.Dunlap@Sun.COM idm_task_t *itp;
16809162SPeter.Dunlap@Sun.COM
16819162SPeter.Dunlap@Sun.COM ASSERT(isp != NULL);
16829162SPeter.Dunlap@Sun.COM ASSERT(ihp != NULL);
16839162SPeter.Dunlap@Sun.COM ASSERT(icmdp != NULL);
16849162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
16859162SPeter.Dunlap@Sun.COM itp = idm_task_find_and_complete(ic, ihp->itt, ISCSI_INI_TASK_TTT);
16869162SPeter.Dunlap@Sun.COM if (itp == NULL) {
16879162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
16889162SPeter.Dunlap@Sun.COM "received unknown itt:0x%x - protocol error",
16899162SPeter.Dunlap@Sun.COM isp->sess_oid, ihp->itt);
16909162SPeter.Dunlap@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
16919162SPeter.Dunlap@Sun.COM }
16929162SPeter.Dunlap@Sun.COM *icmdp = itp->idt_private;
16939162SPeter.Dunlap@Sun.COM
16949162SPeter.Dunlap@Sun.COM idm_task_rele(itp);
16959162SPeter.Dunlap@Sun.COM
16967836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
16979162SPeter.Dunlap@Sun.COM
16987836SJohn.Forte@Sun.COM }
16997836SJohn.Forte@Sun.COM
17007836SJohn.Forte@Sun.COM /*
17017836SJohn.Forte@Sun.COM * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's
17027836SJohn.Forte@Sun.COM * cmd table to find matching icmdp. Verify itt in hdr and
17037836SJohn.Forte@Sun.COM * icmdp are the same.
17047836SJohn.Forte@Sun.COM */
17057836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_rx_process_itt_to_icmdp(iscsi_sess_t * isp,iscsi_hdr_t * ihp,iscsi_cmd_t ** icmdp)17067836SJohn.Forte@Sun.COM iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp,
17077836SJohn.Forte@Sun.COM iscsi_cmd_t **icmdp)
17087836SJohn.Forte@Sun.COM {
17097836SJohn.Forte@Sun.COM int cmd_table_idx = 0;
17107836SJohn.Forte@Sun.COM
17117836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
17127836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
17137836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
17147836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&isp->sess_cmdsn_mutex));
17157836SJohn.Forte@Sun.COM
17167836SJohn.Forte@Sun.COM /* try to find an associated iscsi_pkt */
17179162SPeter.Dunlap@Sun.COM cmd_table_idx = (ihp->itt - IDM_TASKIDS_MAX) % ISCSI_CMD_TABLE_SIZE;
17187836SJohn.Forte@Sun.COM if (isp->sess_cmd_table[cmd_table_idx] == NULL) {
17197836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi session(%u) protocol error - "
17207836SJohn.Forte@Sun.COM "received unknown itt:0x%x - protocol error",
17217836SJohn.Forte@Sun.COM isp->sess_oid, ihp->itt);
17227836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
17237836SJohn.Forte@Sun.COM }
17247836SJohn.Forte@Sun.COM
17257836SJohn.Forte@Sun.COM /* verify itt */
17267836SJohn.Forte@Sun.COM if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) {
17277836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
17287836SJohn.Forte@Sun.COM " which is out of sync with itt:0x%x", isp->sess_oid,
17297836SJohn.Forte@Sun.COM ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt);
17307836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
17317836SJohn.Forte@Sun.COM }
17327836SJohn.Forte@Sun.COM
17337996Sandrew.rutz@sun.com /* ensure that icmdp is still in Active state */
17347996Sandrew.rutz@sun.com if (isp->sess_cmd_table[cmd_table_idx]->cmd_state !=
17357996Sandrew.rutz@sun.com ISCSI_CMD_STATE_ACTIVE) {
17367996Sandrew.rutz@sun.com cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x "
17377996Sandrew.rutz@sun.com "but icmdp (%p) is not in active state",
17387996Sandrew.rutz@sun.com isp->sess_oid, ihp->itt,
17397996Sandrew.rutz@sun.com (void *)isp->sess_cmd_table[cmd_table_idx]);
17407996Sandrew.rutz@sun.com return (ISCSI_STATUS_INTERNAL_ERROR);
17417996Sandrew.rutz@sun.com }
17427996Sandrew.rutz@sun.com
17437836SJohn.Forte@Sun.COM /* make sure this is a SCSI cmd */
17447836SJohn.Forte@Sun.COM *icmdp = isp->sess_cmd_table[cmd_table_idx];
17457836SJohn.Forte@Sun.COM
17467836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
17477836SJohn.Forte@Sun.COM }
17487836SJohn.Forte@Sun.COM
17497836SJohn.Forte@Sun.COM /*
17507836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
17517836SJohn.Forte@Sun.COM * | End of protocol receive routines |
17527836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
17537836SJohn.Forte@Sun.COM */
17547836SJohn.Forte@Sun.COM
17557836SJohn.Forte@Sun.COM /*
17567836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
17577836SJohn.Forte@Sun.COM * | Beginning of protocol send routines |
17587836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
17597836SJohn.Forte@Sun.COM */
17607836SJohn.Forte@Sun.COM
17617836SJohn.Forte@Sun.COM
17627836SJohn.Forte@Sun.COM /*
17637836SJohn.Forte@Sun.COM * iscsi_tx_thread - This thread is the driving point for all
17649162SPeter.Dunlap@Sun.COM * iSCSI PDUs after login. No PDUs should call idm_pdu_tx()
17657836SJohn.Forte@Sun.COM * directly they should be funneled through iscsi_tx_thread.
17667836SJohn.Forte@Sun.COM */
17677836SJohn.Forte@Sun.COM void
iscsi_tx_thread(iscsi_thread_t * thread,void * arg)17687836SJohn.Forte@Sun.COM iscsi_tx_thread(iscsi_thread_t *thread, void *arg)
17697836SJohn.Forte@Sun.COM {
17707836SJohn.Forte@Sun.COM iscsi_conn_t *icp = (iscsi_conn_t *)arg;
17717836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
17727836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
17737836SJohn.Forte@Sun.COM clock_t tout;
17747836SJohn.Forte@Sun.COM int ret = 1;
17757836SJohn.Forte@Sun.COM
17767836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
17777836SJohn.Forte@Sun.COM isp = icp->conn_sess;
17787836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
17797836SJohn.Forte@Sun.COM ASSERT(thread != NULL);
17807836SJohn.Forte@Sun.COM ASSERT(thread->signature == SIG_ISCSI_THREAD);
17817836SJohn.Forte@Sun.COM
17827836SJohn.Forte@Sun.COM tout = SEC_TO_TICK(1);
17837836SJohn.Forte@Sun.COM /*
17847836SJohn.Forte@Sun.COM * Transfer icmdps until shutdown by owning session.
17857836SJohn.Forte@Sun.COM */
17867836SJohn.Forte@Sun.COM while (ret != 0) {
17877836SJohn.Forte@Sun.COM
17887836SJohn.Forte@Sun.COM isp->sess_window_open = B_TRUE;
17897836SJohn.Forte@Sun.COM /*
17907836SJohn.Forte@Sun.COM * While the window is open, there are commands available
17917836SJohn.Forte@Sun.COM * to send and the session state allows those commands to
17927836SJohn.Forte@Sun.COM * be sent try to transfer them.
17937836SJohn.Forte@Sun.COM */
17947836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
17957836SJohn.Forte@Sun.COM while ((isp->sess_window_open == B_TRUE) &&
1796*12161SJack.Meng@Sun.COM ((icmdp = isp->sess_queue_pending.head) != NULL)) {
1797*12161SJack.Meng@Sun.COM if (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) &&
1798*12161SJack.Meng@Sun.COM (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) ||
1799*12161SJack.Meng@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN)) {
1800*12161SJack.Meng@Sun.COM
1801*12161SJack.Meng@Sun.COM /* update command with this connection info */
1802*12161SJack.Meng@Sun.COM icmdp->cmd_conn = icp;
1803*12161SJack.Meng@Sun.COM /* attempt to send this command */
1804*12161SJack.Meng@Sun.COM iscsi_cmd_state_machine(icmdp,
1805*12161SJack.Meng@Sun.COM ISCSI_CMD_EVENT_E2, isp);
1806*12161SJack.Meng@Sun.COM
1807*12161SJack.Meng@Sun.COM ASSERT(!mutex_owned(
1808*12161SJack.Meng@Sun.COM &isp->sess_queue_pending.mutex));
1809*12161SJack.Meng@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
1810*12161SJack.Meng@Sun.COM } else {
1811*12161SJack.Meng@Sun.COM while (icmdp != NULL) {
1812*12161SJack.Meng@Sun.COM if ((icmdp->cmd_type !=
1813*12161SJack.Meng@Sun.COM ISCSI_CMD_TYPE_SCSI) &&
1814*12161SJack.Meng@Sun.COM (ISCSI_CONN_STATE_FULL_FEATURE
1815*12161SJack.Meng@Sun.COM (icp->conn_state) != B_TRUE)) {
1816*12161SJack.Meng@Sun.COM icmdp->cmd_misc_flags |=
1817*12161SJack.Meng@Sun.COM ISCSI_CMD_MISCFLAG_STUCK;
1818*12161SJack.Meng@Sun.COM } else if (icp->conn_state !=
1819*12161SJack.Meng@Sun.COM ISCSI_CONN_STATE_LOGGED_IN) {
1820*12161SJack.Meng@Sun.COM icmdp->cmd_misc_flags |=
1821*12161SJack.Meng@Sun.COM ISCSI_CMD_MISCFLAG_STUCK;
1822*12161SJack.Meng@Sun.COM }
1823*12161SJack.Meng@Sun.COM icmdp = icmdp->cmd_next;
1824*12161SJack.Meng@Sun.COM }
1825*12161SJack.Meng@Sun.COM break;
1826*12161SJack.Meng@Sun.COM }
18277836SJohn.Forte@Sun.COM }
18287836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
18297836SJohn.Forte@Sun.COM
18307836SJohn.Forte@Sun.COM /*
18317836SJohn.Forte@Sun.COM * Go to sleep until there is something new
18327836SJohn.Forte@Sun.COM * to process (awoken via cv_boardcast).
18337836SJohn.Forte@Sun.COM * Or the timer goes off.
18347836SJohn.Forte@Sun.COM */
18357836SJohn.Forte@Sun.COM ret = iscsi_thread_wait(thread, tout);
18367836SJohn.Forte@Sun.COM }
18377836SJohn.Forte@Sun.COM
18387836SJohn.Forte@Sun.COM }
18397836SJohn.Forte@Sun.COM
18407836SJohn.Forte@Sun.COM
18417836SJohn.Forte@Sun.COM /*
18427836SJohn.Forte@Sun.COM * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu
18437836SJohn.Forte@Sun.COM *
18447836SJohn.Forte@Sun.COM * Just prior to sending the command to the networking layer the
18457836SJohn.Forte@Sun.COM * pending queue lock will be dropped. At this point only local
18467836SJohn.Forte@Sun.COM * resources will be used, not the icmdp. Holding the queue lock
18477836SJohn.Forte@Sun.COM * across the networking call can lead to a hang. (This is due
18487836SJohn.Forte@Sun.COM * to the the target driver and networking layers competing use
18497836SJohn.Forte@Sun.COM * of the timeout() resources and the queue lock being held for
18507836SJohn.Forte@Sun.COM * both sides.) Upon the completion of this command the lock
18517836SJohn.Forte@Sun.COM * will have been re-acquired.
18527836SJohn.Forte@Sun.COM */
18537836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_tx_cmd(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)18547836SJohn.Forte@Sun.COM iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
18557836SJohn.Forte@Sun.COM {
18567836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR;
18577836SJohn.Forte@Sun.COM
18587836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
18597836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
18607836SJohn.Forte@Sun.COM
18617836SJohn.Forte@Sun.COM /* transfer specific command type */
18627836SJohn.Forte@Sun.COM switch (icmdp->cmd_type) {
18637836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_SCSI:
18647836SJohn.Forte@Sun.COM rval = iscsi_tx_scsi(isp, icmdp);
18657836SJohn.Forte@Sun.COM break;
18667836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_NOP:
18677836SJohn.Forte@Sun.COM rval = iscsi_tx_nop(isp, icmdp);
18687836SJohn.Forte@Sun.COM break;
18697836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_ABORT:
18707836SJohn.Forte@Sun.COM rval = iscsi_tx_abort(isp, icmdp);
18717836SJohn.Forte@Sun.COM break;
18727836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_RESET:
18737836SJohn.Forte@Sun.COM rval = iscsi_tx_reset(isp, icmdp);
18747836SJohn.Forte@Sun.COM break;
18757836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_LOGOUT:
18767836SJohn.Forte@Sun.COM rval = iscsi_tx_logout(isp, icmdp);
18777836SJohn.Forte@Sun.COM break;
18787836SJohn.Forte@Sun.COM case ISCSI_CMD_TYPE_TEXT:
18797836SJohn.Forte@Sun.COM rval = iscsi_tx_text(isp, icmdp);
18807836SJohn.Forte@Sun.COM break;
18817836SJohn.Forte@Sun.COM default:
18829162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi_tx_cmd: invalid cmdtype: %d",
18839162SPeter.Dunlap@Sun.COM icmdp->cmd_type);
18847836SJohn.Forte@Sun.COM ASSERT(FALSE);
18857836SJohn.Forte@Sun.COM }
18867836SJohn.Forte@Sun.COM
18877836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
18887836SJohn.Forte@Sun.COM return (rval);
18897836SJohn.Forte@Sun.COM }
18907836SJohn.Forte@Sun.COM
18917836SJohn.Forte@Sun.COM /*
18927836SJohn.Forte@Sun.COM * a variable length cdb can be up to 16K, but we obviously don't want
18937836SJohn.Forte@Sun.COM * to put that on the stack; go with 200 bytes; if we get something
18947836SJohn.Forte@Sun.COM * bigger than that we will kmem_alloc a buffer
18957836SJohn.Forte@Sun.COM */
18967836SJohn.Forte@Sun.COM #define DEF_CDB_LEN 200
18977836SJohn.Forte@Sun.COM
18987836SJohn.Forte@Sun.COM /*
18997836SJohn.Forte@Sun.COM * given the size of the cdb, return how many bytes the header takes,
19007836SJohn.Forte@Sun.COM * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes
19017836SJohn.Forte@Sun.COM * stored in the basic header, minus sizeof (ahs_extscb)
19027836SJohn.Forte@Sun.COM */
19037836SJohn.Forte@Sun.COM #define ADDLHDRSZ(x) (sizeof (iscsi_addl_hdr_t) + (x) - \
19047836SJohn.Forte@Sun.COM 16 - 4)
19057836SJohn.Forte@Sun.COM
19069162SPeter.Dunlap@Sun.COM static void
iscsi_tx_init_hdr(iscsi_sess_t * isp,iscsi_conn_t * icp,iscsi_text_hdr_t * ihp,int opcode,iscsi_cmd_t * icmdp)19079162SPeter.Dunlap@Sun.COM iscsi_tx_init_hdr(iscsi_sess_t *isp, iscsi_conn_t *icp,
19089780SBing.Zhao@Sun.COM iscsi_text_hdr_t *ihp, int opcode, iscsi_cmd_t *icmdp)
19097836SJohn.Forte@Sun.COM {
19109162SPeter.Dunlap@Sun.COM ihp->opcode = opcode;
19119780SBing.Zhao@Sun.COM ihp->itt = icmdp->cmd_itt;
19127836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
19139780SBing.Zhao@Sun.COM icmdp->cmd_sn = isp->sess_cmdsn;
19147836SJohn.Forte@Sun.COM ihp->cmdsn = htonl(isp->sess_cmdsn);
19157836SJohn.Forte@Sun.COM isp->sess_cmdsn++;
19167836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
19177836SJohn.Forte@Sun.COM ihp->expstatsn = htonl(icp->conn_expstatsn);
19187836SJohn.Forte@Sun.COM icp->conn_laststatsn = icp->conn_expstatsn;
19199162SPeter.Dunlap@Sun.COM }
19209162SPeter.Dunlap@Sun.COM
19219162SPeter.Dunlap@Sun.COM
19229162SPeter.Dunlap@Sun.COM static void
iscsi_tx_scsi_data(iscsi_cmd_t * icmdp,iscsi_scsi_cmd_hdr_t * ihp,iscsi_conn_t * icp,idm_pdu_t * pdu)19239162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_data(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp,
19249162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp, idm_pdu_t *pdu)
19259162SPeter.Dunlap@Sun.COM {
19269162SPeter.Dunlap@Sun.COM struct buf *bp = NULL;
19279162SPeter.Dunlap@Sun.COM size_t buflen = 0;
19289162SPeter.Dunlap@Sun.COM uint32_t first_burst_length = 0;
19299162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt;
19309162SPeter.Dunlap@Sun.COM
19319162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
19327836SJohn.Forte@Sun.COM bp = icmdp->cmd_un.scsi.bp;
19337836SJohn.Forte@Sun.COM if ((bp != NULL) && bp->b_bcount) {
19347836SJohn.Forte@Sun.COM buflen = bp->b_bcount;
19359162SPeter.Dunlap@Sun.COM first_burst_length =
19369162SPeter.Dunlap@Sun.COM icp->conn_params.first_burst_length;
19377836SJohn.Forte@Sun.COM
19387836SJohn.Forte@Sun.COM if (bp->b_flags & B_READ) {
19397836SJohn.Forte@Sun.COM ihp->flags = ISCSI_FLAG_FINAL;
19407836SJohn.Forte@Sun.COM /*
19417836SJohn.Forte@Sun.COM * fix problem where OS sends bp (B_READ &
19427836SJohn.Forte@Sun.COM * b_bcount!=0) for a TUR or START_STOP.
19437836SJohn.Forte@Sun.COM * (comment came from cisco code.)
19447836SJohn.Forte@Sun.COM */
19457836SJohn.Forte@Sun.COM if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) &&
19467836SJohn.Forte@Sun.COM (pkt->pkt_cdbp[0] != SCMD_START_STOP)) {
19477836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_FLAG_CMD_READ;
19487836SJohn.Forte@Sun.COM ihp->data_length = htonl(buflen);
19497836SJohn.Forte@Sun.COM }
19507836SJohn.Forte@Sun.COM } else {
19517836SJohn.Forte@Sun.COM ihp->flags = ISCSI_FLAG_CMD_WRITE;
19527836SJohn.Forte@Sun.COM /*
19537836SJohn.Forte@Sun.COM * FinalBit on the the iSCSI PDU denotes this
19547836SJohn.Forte@Sun.COM * is the last PDU in the sequence.
19557836SJohn.Forte@Sun.COM *
19567836SJohn.Forte@Sun.COM * initial_r2t = true means R2T is required
19577836SJohn.Forte@Sun.COM * for additional PDU, so there will be no more
19587836SJohn.Forte@Sun.COM * unsolicited PDUs following
19597836SJohn.Forte@Sun.COM */
19607836SJohn.Forte@Sun.COM if (icp->conn_params.initial_r2t) {
19617836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_FLAG_FINAL;
19627836SJohn.Forte@Sun.COM }
19637836SJohn.Forte@Sun.COM
19647836SJohn.Forte@Sun.COM /* Check if we should send ImmediateData */
19657836SJohn.Forte@Sun.COM if (icp->conn_params.immediate_data) {
19669162SPeter.Dunlap@Sun.COM pdu->isp_data =
19679162SPeter.Dunlap@Sun.COM (uint8_t *)icmdp->
19689162SPeter.Dunlap@Sun.COM cmd_un.scsi.bp->b_un.b_addr;
19699162SPeter.Dunlap@Sun.COM
19709162SPeter.Dunlap@Sun.COM pdu->isp_datalen = MIN(MIN(buflen,
19717836SJohn.Forte@Sun.COM first_burst_length),
19727836SJohn.Forte@Sun.COM icmdp->cmd_conn->conn_params.
19737836SJohn.Forte@Sun.COM max_xmit_data_seg_len);
19747836SJohn.Forte@Sun.COM
19757836SJohn.Forte@Sun.COM /*
19767836SJohn.Forte@Sun.COM * if everything fits immediate, or
19777836SJohn.Forte@Sun.COM * we can send all burst data immediate
19787836SJohn.Forte@Sun.COM * (not unsol), set F
19797836SJohn.Forte@Sun.COM */
19809162SPeter.Dunlap@Sun.COM /*
19819162SPeter.Dunlap@Sun.COM * XXX This doesn't look right -- it's not
19829162SPeter.Dunlap@Sun.COM * clear how we can handle transmitting
19839162SPeter.Dunlap@Sun.COM * any unsolicited data. It looks like
19849162SPeter.Dunlap@Sun.COM * we only support immediate data. So what
19859162SPeter.Dunlap@Sun.COM * happens if we don't set ISCSI_FLAG_FINAL?
19869162SPeter.Dunlap@Sun.COM *
19879162SPeter.Dunlap@Sun.COM * Unless there's magic code somewhere that
19889162SPeter.Dunlap@Sun.COM * is sending the remaining PDU's we should
19899162SPeter.Dunlap@Sun.COM * simply set ISCSI_FLAG_FINAL and forget
19909162SPeter.Dunlap@Sun.COM * about sending unsolicited data. The big
19919162SPeter.Dunlap@Sun.COM * win is the immediate data anyway for small
19929162SPeter.Dunlap@Sun.COM * PDU's.
19939162SPeter.Dunlap@Sun.COM */
19949162SPeter.Dunlap@Sun.COM if ((pdu->isp_datalen == buflen) ||
19959162SPeter.Dunlap@Sun.COM (pdu->isp_datalen == first_burst_length)) {
19967836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_FLAG_FINAL;
19977836SJohn.Forte@Sun.COM }
19987836SJohn.Forte@Sun.COM
19999162SPeter.Dunlap@Sun.COM hton24(ihp->dlength, pdu->isp_datalen);
20007836SJohn.Forte@Sun.COM }
20017836SJohn.Forte@Sun.COM /* total data transfer length */
20027836SJohn.Forte@Sun.COM ihp->data_length = htonl(buflen);
20037836SJohn.Forte@Sun.COM }
20047836SJohn.Forte@Sun.COM } else {
20057836SJohn.Forte@Sun.COM ihp->flags = ISCSI_FLAG_FINAL;
20067836SJohn.Forte@Sun.COM }
20079162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred += pdu->isp_datalen;
20089162SPeter.Dunlap@Sun.COM /* XXX How is this different from the code above? */
20099162SPeter.Dunlap@Sun.COM /* will idm send the next data command up to burst length? */
20109162SPeter.Dunlap@Sun.COM /* send the burstlen if we haven't sent immediate data */
20119162SPeter.Dunlap@Sun.COM /* CRM: should idm send difference min(buflen, first_burst) and imm? */
20129162SPeter.Dunlap@Sun.COM /* (MIN(first_burst_length, buflen) - imdata > 0) */
20139162SPeter.Dunlap@Sun.COM /* CRM_LATER: change this to generate unsolicited pdu */
20149162SPeter.Dunlap@Sun.COM if ((buflen > 0) &&
20159162SPeter.Dunlap@Sun.COM ((bp->b_flags & B_READ) == 0) &&
20169162SPeter.Dunlap@Sun.COM (icp->conn_params.initial_r2t == 0) &&
20179162SPeter.Dunlap@Sun.COM pdu->isp_datalen == 0) {
20189162SPeter.Dunlap@Sun.COM
20199162SPeter.Dunlap@Sun.COM pdu->isp_datalen = MIN(first_burst_length, buflen);
20209162SPeter.Dunlap@Sun.COM if ((pdu->isp_datalen == buflen) ||
20219162SPeter.Dunlap@Sun.COM (pdu->isp_datalen == first_burst_length)) {
20229162SPeter.Dunlap@Sun.COM ihp->flags |= ISCSI_FLAG_FINAL;
20239162SPeter.Dunlap@Sun.COM }
20249162SPeter.Dunlap@Sun.COM pdu->isp_data = (uint8_t *)icmdp->cmd_un.scsi.bp->b_un.b_addr;
20259162SPeter.Dunlap@Sun.COM hton24(ihp->dlength, pdu->isp_datalen);
20269162SPeter.Dunlap@Sun.COM }
20279162SPeter.Dunlap@Sun.COM }
20289162SPeter.Dunlap@Sun.COM
20299162SPeter.Dunlap@Sun.COM static void
iscsi_tx_scsi_init_pkt(iscsi_cmd_t * icmdp,iscsi_scsi_cmd_hdr_t * ihp)20309162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_init_pkt(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp)
20319162SPeter.Dunlap@Sun.COM {
20329162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt;
20339162SPeter.Dunlap@Sun.COM
20349162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
20359162SPeter.Dunlap@Sun.COM pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET);
20369162SPeter.Dunlap@Sun.COM pkt->pkt_reason = CMD_INCOMPLETE;
20377836SJohn.Forte@Sun.COM
20387836SJohn.Forte@Sun.COM /* tagged queuing */
20397836SJohn.Forte@Sun.COM if (pkt->pkt_flags & FLAG_HTAG) {
20407836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE;
20417836SJohn.Forte@Sun.COM } else if (pkt->pkt_flags & FLAG_OTAG) {
20427836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_ATTR_ORDERED;
20437836SJohn.Forte@Sun.COM } else if (pkt->pkt_flags & FLAG_STAG) {
20447836SJohn.Forte@Sun.COM ihp->flags |= ISCSI_ATTR_SIMPLE;
20457836SJohn.Forte@Sun.COM } else {
20467836SJohn.Forte@Sun.COM /* ihp->flags |= ISCSI_ATTR_UNTAGGED; */
20477836SJohn.Forte@Sun.COM /* EMPTY */
20487836SJohn.Forte@Sun.COM }
20497836SJohn.Forte@Sun.COM
20507836SJohn.Forte@Sun.COM /* iscsi states lun is based on spc.2 */
20517836SJohn.Forte@Sun.COM ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun);
20527836SJohn.Forte@Sun.COM
20537836SJohn.Forte@Sun.COM if (icmdp->cmd_un.scsi.cmdlen <= 16) {
20547836SJohn.Forte@Sun.COM /* copy the SCSI Command Block into the PDU */
20557836SJohn.Forte@Sun.COM bcopy(pkt->pkt_cdbp, ihp->scb,
20567836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.cmdlen);
20577836SJohn.Forte@Sun.COM } else {
20587836SJohn.Forte@Sun.COM iscsi_addl_hdr_t *iahp;
20597836SJohn.Forte@Sun.COM
20607836SJohn.Forte@Sun.COM iahp = (iscsi_addl_hdr_t *)ihp;
20617836SJohn.Forte@Sun.COM
20627836SJohn.Forte@Sun.COM ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) -
20637836SJohn.Forte@Sun.COM sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4;
20647836SJohn.Forte@Sun.COM iahp->ahs_hlen_hi = 0;
20657836SJohn.Forte@Sun.COM iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15);
20667836SJohn.Forte@Sun.COM iahp->ahs_key = 0x01;
20677836SJohn.Forte@Sun.COM iahp->ahs_resv = 0;
20687836SJohn.Forte@Sun.COM bcopy(pkt->pkt_cdbp, ihp->scb, 16);
20697836SJohn.Forte@Sun.COM bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0],
20707836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.cmdlen);
20717836SJohn.Forte@Sun.COM }
20727836SJohn.Forte@Sun.COM
20737836SJohn.Forte@Sun.COM /*
20747836SJohn.Forte@Sun.COM * Update all values before transfering.
20757836SJohn.Forte@Sun.COM * We should never touch the icmdp after
20767836SJohn.Forte@Sun.COM * transfering if there is no more data
20779162SPeter.Dunlap@Sun.COM * to send. The only case the idm_pdu_tx()
20787836SJohn.Forte@Sun.COM * will fail is a on a connection disconnect
20797836SJohn.Forte@Sun.COM * in that case the command will be flushed.
20807836SJohn.Forte@Sun.COM */
20817836SJohn.Forte@Sun.COM pkt->pkt_state |= STATE_SENT_CMD;
20829162SPeter.Dunlap@Sun.COM }
20839162SPeter.Dunlap@Sun.COM
20849162SPeter.Dunlap@Sun.COM static void
iscsi_tx_scsi_init_task(iscsi_cmd_t * icmdp,iscsi_conn_t * icp,iscsi_scsi_cmd_hdr_t * ihp)20859162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_init_task(iscsi_cmd_t *icmdp, iscsi_conn_t *icp,
20869162SPeter.Dunlap@Sun.COM iscsi_scsi_cmd_hdr_t *ihp)
20879162SPeter.Dunlap@Sun.COM {
20889162SPeter.Dunlap@Sun.COM idm_task_t *itp;
20899162SPeter.Dunlap@Sun.COM struct buf *bp = NULL;
20909162SPeter.Dunlap@Sun.COM uint32_t data_length;
20919162SPeter.Dunlap@Sun.COM
20929162SPeter.Dunlap@Sun.COM bp = icmdp->cmd_un.scsi.bp;
20939162SPeter.Dunlap@Sun.COM
20949162SPeter.Dunlap@Sun.COM itp = icmdp->cmd_itp;
20959162SPeter.Dunlap@Sun.COM ASSERT(itp != NULL);
20969162SPeter.Dunlap@Sun.COM data_length = ntohl(ihp->data_length);
20979162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
20989162SPeter.Dunlap@Sun.COM "DEBUG: iscsi_tx_init_task: task_start: %p idt_tt: %x cmdsn: %x "
20999162SPeter.Dunlap@Sun.COM "sess_cmdsn: %x cmd: %p "
21009162SPeter.Dunlap@Sun.COM "cmdtype: %d datalen: %u",
21019162SPeter.Dunlap@Sun.COM (void *)itp, itp->idt_tt, ihp->cmdsn, icp->conn_sess->sess_cmdsn,
21029162SPeter.Dunlap@Sun.COM (void *)icmdp, icmdp->cmd_type, data_length);
21039162SPeter.Dunlap@Sun.COM if (data_length > 0) {
21049162SPeter.Dunlap@Sun.COM if (bp->b_flags & B_READ) {
21059162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_ibuf =
21069162SPeter.Dunlap@Sun.COM idm_buf_alloc(icp->conn_ic,
21079162SPeter.Dunlap@Sun.COM bp->b_un.b_addr, bp->b_bcount);
21089162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.ibp_ibuf)
21099162SPeter.Dunlap@Sun.COM idm_buf_bind_in(itp,
21109162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_ibuf);
21119162SPeter.Dunlap@Sun.COM } else {
21129162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_obuf =
21139162SPeter.Dunlap@Sun.COM idm_buf_alloc(icp->conn_ic,
21149162SPeter.Dunlap@Sun.COM bp->b_un.b_addr, bp->b_bcount);
21159162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.ibp_obuf)
21169162SPeter.Dunlap@Sun.COM idm_buf_bind_out(itp,
21179162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.ibp_obuf);
21189162SPeter.Dunlap@Sun.COM }
21199162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE,
21209162SPeter.Dunlap@Sun.COM "DEBUG: pdu_tx: task_start(%s): %p ic: %p idt_tt: %x "
21219162SPeter.Dunlap@Sun.COM "cmdsn: %x sess_cmdsn: %x sess_expcmdsn: %x obuf: %p "
21229162SPeter.Dunlap@Sun.COM "cmdp: %p cmdtype: %d "
21239162SPeter.Dunlap@Sun.COM "buflen: %lu " "bpaddr: %p datalen: %u ",
21249162SPeter.Dunlap@Sun.COM bp->b_flags & B_READ ? "B_READ" : "B_WRITE",
21259162SPeter.Dunlap@Sun.COM (void *)itp, (void *)icp->conn_ic,
21269162SPeter.Dunlap@Sun.COM itp->idt_tt, ihp->cmdsn,
21279162SPeter.Dunlap@Sun.COM icp->conn_sess->sess_cmdsn,
21289162SPeter.Dunlap@Sun.COM icp->conn_sess->sess_expcmdsn,
21299162SPeter.Dunlap@Sun.COM (void *)icmdp->cmd_un.scsi.ibp_ibuf,
21309162SPeter.Dunlap@Sun.COM (void *)icmdp, icmdp->cmd_type, bp->b_bcount,
21319162SPeter.Dunlap@Sun.COM (void *)bp->b_un.b_addr,
21329162SPeter.Dunlap@Sun.COM data_length);
21339162SPeter.Dunlap@Sun.COM }
21347836SJohn.Forte@Sun.COM
21357836SJohn.Forte@Sun.COM /*
21369162SPeter.Dunlap@Sun.COM * Task is now active
21377836SJohn.Forte@Sun.COM */
21389162SPeter.Dunlap@Sun.COM idm_task_start(itp, ISCSI_INI_TASK_TTT);
21397836SJohn.Forte@Sun.COM }
21407836SJohn.Forte@Sun.COM
21417836SJohn.Forte@Sun.COM /*
21429162SPeter.Dunlap@Sun.COM * iscsi_tx_scsi -
21437836SJohn.Forte@Sun.COM *
21447836SJohn.Forte@Sun.COM */
21457836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_scsi(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)21469162SPeter.Dunlap@Sun.COM iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
21477836SJohn.Forte@Sun.COM {
21489162SPeter.Dunlap@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
21499162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = NULL;
21509162SPeter.Dunlap@Sun.COM struct scsi_pkt *pkt = NULL;
21519162SPeter.Dunlap@Sun.COM iscsi_scsi_cmd_hdr_t *ihp = NULL;
21529162SPeter.Dunlap@Sun.COM int cdblen = 0;
21539162SPeter.Dunlap@Sun.COM idm_pdu_t *pdu;
21549162SPeter.Dunlap@Sun.COM int len;
21557836SJohn.Forte@Sun.COM
21567836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
21577836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
21589162SPeter.Dunlap@Sun.COM
21599162SPeter.Dunlap@Sun.COM pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
21609162SPeter.Dunlap@Sun.COM
21619162SPeter.Dunlap@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
21629162SPeter.Dunlap@Sun.COM ASSERT(pkt != NULL);
21637836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
21649162SPeter.Dunlap@Sun.COM ASSERT(icp != NULL);
21659162SPeter.Dunlap@Sun.COM
21669162SPeter.Dunlap@Sun.COM /* Reset counts in case we are on a retry */
21679162SPeter.Dunlap@Sun.COM icmdp->cmd_un.scsi.data_transferred = 0;
21689162SPeter.Dunlap@Sun.COM
21699162SPeter.Dunlap@Sun.COM if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) {
21709162SPeter.Dunlap@Sun.COM cdblen = icmdp->cmd_un.scsi.cmdlen;
21719162SPeter.Dunlap@Sun.COM ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP);
21729162SPeter.Dunlap@Sun.COM len = ADDLHDRSZ(cdblen);
21739162SPeter.Dunlap@Sun.COM } else {
21749162SPeter.Dunlap@Sun.COM /*
21759162SPeter.Dunlap@Sun.COM * only bzero the basic header; the additional header
21769162SPeter.Dunlap@Sun.COM * will be set up correctly later, if needed
21779162SPeter.Dunlap@Sun.COM */
21789162SPeter.Dunlap@Sun.COM ihp = kmem_zalloc(sizeof (iscsi_scsi_cmd_hdr_t), KM_SLEEP);
21799162SPeter.Dunlap@Sun.COM len = sizeof (iscsi_scsi_cmd_hdr_t);
21807836SJohn.Forte@Sun.COM }
21819162SPeter.Dunlap@Sun.COM
21829162SPeter.Dunlap@Sun.COM iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ihp,
21839780SBing.Zhao@Sun.COM ISCSI_OP_SCSI_CMD, icmdp);
21849162SPeter.Dunlap@Sun.COM
21859162SPeter.Dunlap@Sun.COM idm_pdu_init(pdu, icp->conn_ic, (void *)icmdp, &iscsi_tx_done);
21869162SPeter.Dunlap@Sun.COM idm_pdu_init_hdr(pdu, (uint8_t *)ihp, len);
21879162SPeter.Dunlap@Sun.COM pdu->isp_data = NULL;
21889162SPeter.Dunlap@Sun.COM pdu->isp_datalen = 0;
21899162SPeter.Dunlap@Sun.COM
21907836SJohn.Forte@Sun.COM /*
21919162SPeter.Dunlap@Sun.COM * Sestion 12.11 of the iSCSI specification has a good table
21929162SPeter.Dunlap@Sun.COM * describing when uncolicited data and/or immediate data
21939162SPeter.Dunlap@Sun.COM * should be sent.
21947836SJohn.Forte@Sun.COM */
21959162SPeter.Dunlap@Sun.COM
21969162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_data(icmdp, ihp, icp, pdu);
21979162SPeter.Dunlap@Sun.COM
21989162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_init_pkt(icmdp, ihp);
21999162SPeter.Dunlap@Sun.COM
22009162SPeter.Dunlap@Sun.COM /* Calls idm_task_start */
22019162SPeter.Dunlap@Sun.COM iscsi_tx_scsi_init_task(icmdp, icp, ihp);
22029162SPeter.Dunlap@Sun.COM
22039162SPeter.Dunlap@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
22049162SPeter.Dunlap@Sun.COM
22059162SPeter.Dunlap@Sun.COM idm_pdu_tx(pdu);
22069162SPeter.Dunlap@Sun.COM
22079780SBing.Zhao@Sun.COM icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
22089780SBing.Zhao@Sun.COM
22097836SJohn.Forte@Sun.COM return (rval);
22107836SJohn.Forte@Sun.COM }
22117836SJohn.Forte@Sun.COM
22127836SJohn.Forte@Sun.COM
22139162SPeter.Dunlap@Sun.COM /* ARGSUSED */
22149162SPeter.Dunlap@Sun.COM static void
iscsi_tx_done(idm_pdu_t * pdu,idm_status_t status)22159162SPeter.Dunlap@Sun.COM iscsi_tx_done(idm_pdu_t *pdu, idm_status_t status)
22169162SPeter.Dunlap@Sun.COM {
22179162SPeter.Dunlap@Sun.COM kmem_free((iscsi_hdr_t *)pdu->isp_hdr, pdu->isp_hdrlen);
22189162SPeter.Dunlap@Sun.COM kmem_free(pdu, sizeof (idm_pdu_t));
22199162SPeter.Dunlap@Sun.COM }
22209162SPeter.Dunlap@Sun.COM
22219162SPeter.Dunlap@Sun.COM
22229162SPeter.Dunlap@Sun.COM static void
iscsi_tx_pdu(iscsi_conn_t * icp,int opcode,void * hdr,int hdrlen,iscsi_cmd_t * icmdp)22239162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(iscsi_conn_t *icp, int opcode, void *hdr, int hdrlen,
22249162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp)
22257836SJohn.Forte@Sun.COM {
22269162SPeter.Dunlap@Sun.COM idm_pdu_t *tx_pdu;
22279162SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp = (iscsi_hdr_t *)hdr;
22289162SPeter.Dunlap@Sun.COM
22299162SPeter.Dunlap@Sun.COM tx_pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP);
22309162SPeter.Dunlap@Sun.COM ASSERT(tx_pdu != NULL);
22319162SPeter.Dunlap@Sun.COM
22329162SPeter.Dunlap@Sun.COM idm_pdu_init(tx_pdu, icp->conn_ic, icmdp, &iscsi_tx_done);
22339162SPeter.Dunlap@Sun.COM idm_pdu_init_hdr(tx_pdu, hdr, hdrlen);
22349162SPeter.Dunlap@Sun.COM if (opcode == ISCSI_OP_TEXT_CMD) {
22359162SPeter.Dunlap@Sun.COM idm_pdu_init_data(tx_pdu,
22369162SPeter.Dunlap@Sun.COM (uint8_t *)icmdp->cmd_un.text.buf,
22379162SPeter.Dunlap@Sun.COM ntoh24(ihp->dlength));
22387836SJohn.Forte@Sun.COM }
22397836SJohn.Forte@Sun.COM
22409162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_sess->sess_queue_pending.mutex);
22419162SPeter.Dunlap@Sun.COM idm_pdu_tx(tx_pdu);
22429780SBing.Zhao@Sun.COM icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT;
22437836SJohn.Forte@Sun.COM }
22447836SJohn.Forte@Sun.COM
22457836SJohn.Forte@Sun.COM
22467836SJohn.Forte@Sun.COM /*
22477836SJohn.Forte@Sun.COM * iscsi_tx_nop -
22487836SJohn.Forte@Sun.COM *
22497836SJohn.Forte@Sun.COM */
22507836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_nop(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)22517836SJohn.Forte@Sun.COM iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
22527836SJohn.Forte@Sun.COM {
22537836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
22547836SJohn.Forte@Sun.COM iscsi_conn_t *icp = NULL;
22559162SPeter.Dunlap@Sun.COM iscsi_nop_out_hdr_t *inohp;
22567836SJohn.Forte@Sun.COM
22577836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
22587836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
22597836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
22607836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
22617836SJohn.Forte@Sun.COM
22629162SPeter.Dunlap@Sun.COM inohp = kmem_zalloc(sizeof (iscsi_nop_out_hdr_t), KM_SLEEP);
22639162SPeter.Dunlap@Sun.COM ASSERT(inohp != NULL);
22649162SPeter.Dunlap@Sun.COM
22659162SPeter.Dunlap@Sun.COM inohp->opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
22669162SPeter.Dunlap@Sun.COM inohp->flags = ISCSI_FLAG_FINAL;
22679162SPeter.Dunlap@Sun.COM inohp->itt = icmdp->cmd_itt;
22689162SPeter.Dunlap@Sun.COM inohp->ttt = icmdp->cmd_ttt;
22697836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
22709780SBing.Zhao@Sun.COM icmdp->cmd_sn = isp->sess_cmdsn;
22719162SPeter.Dunlap@Sun.COM inohp->cmdsn = htonl(isp->sess_cmdsn);
22727836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
22739162SPeter.Dunlap@Sun.COM inohp->expstatsn = htonl(icp->conn_expstatsn);
22747836SJohn.Forte@Sun.COM icp->conn_laststatsn = icp->conn_expstatsn;
22759162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(icp, ISCSI_OP_NOOP_OUT, inohp,
22769162SPeter.Dunlap@Sun.COM sizeof (iscsi_nop_out_hdr_t), icmdp);
22777836SJohn.Forte@Sun.COM return (rval);
22787836SJohn.Forte@Sun.COM }
22797836SJohn.Forte@Sun.COM
22807836SJohn.Forte@Sun.COM
22817836SJohn.Forte@Sun.COM /*
22827836SJohn.Forte@Sun.COM * iscsi_tx_abort -
22837836SJohn.Forte@Sun.COM *
22847836SJohn.Forte@Sun.COM */
22857836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_abort(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)22867836SJohn.Forte@Sun.COM iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
22877836SJohn.Forte@Sun.COM {
22887836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
22897836SJohn.Forte@Sun.COM iscsi_conn_t *icp = NULL;
22909162SPeter.Dunlap@Sun.COM iscsi_scsi_task_mgt_hdr_t *istmh;
22917836SJohn.Forte@Sun.COM
22927836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
22937836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
22947836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
22957836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
22967836SJohn.Forte@Sun.COM
22979162SPeter.Dunlap@Sun.COM istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
22989162SPeter.Dunlap@Sun.COM ASSERT(istmh != NULL);
22997836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
23009780SBing.Zhao@Sun.COM icmdp->cmd_sn = isp->sess_cmdsn;
23019162SPeter.Dunlap@Sun.COM istmh->cmdsn = htonl(isp->sess_cmdsn);
23027836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
23039162SPeter.Dunlap@Sun.COM istmh->expstatsn = htonl(icp->conn_expstatsn);
23047836SJohn.Forte@Sun.COM icp->conn_laststatsn = icp->conn_expstatsn;
23059162SPeter.Dunlap@Sun.COM istmh->itt = icmdp->cmd_itt;
23069162SPeter.Dunlap@Sun.COM istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
23079162SPeter.Dunlap@Sun.COM istmh->function = ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK;
23089162SPeter.Dunlap@Sun.COM ISCSI_LUN_BYTE_COPY(istmh->lun,
23097836SJohn.Forte@Sun.COM icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun);
23109162SPeter.Dunlap@Sun.COM istmh->rtt = icmdp->cmd_un.abort.icmdp->cmd_itt;
23119162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
23129162SPeter.Dunlap@Sun.COM sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
23137836SJohn.Forte@Sun.COM
23147836SJohn.Forte@Sun.COM return (rval);
23157836SJohn.Forte@Sun.COM }
23167836SJohn.Forte@Sun.COM
23177836SJohn.Forte@Sun.COM
23187836SJohn.Forte@Sun.COM /*
23197836SJohn.Forte@Sun.COM * iscsi_tx_reset -
23207836SJohn.Forte@Sun.COM *
23217836SJohn.Forte@Sun.COM */
23227836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_reset(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)23237836SJohn.Forte@Sun.COM iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
23247836SJohn.Forte@Sun.COM {
23257836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
23267836SJohn.Forte@Sun.COM iscsi_conn_t *icp = NULL;
23279162SPeter.Dunlap@Sun.COM iscsi_scsi_task_mgt_hdr_t *istmh;
23287836SJohn.Forte@Sun.COM
23297836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
23307836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
23317836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
23327836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
23337836SJohn.Forte@Sun.COM
23349162SPeter.Dunlap@Sun.COM istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP);
23359162SPeter.Dunlap@Sun.COM ASSERT(istmh != NULL);
23369162SPeter.Dunlap@Sun.COM istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE;
23377836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
23389780SBing.Zhao@Sun.COM icmdp->cmd_sn = isp->sess_cmdsn;
23399162SPeter.Dunlap@Sun.COM istmh->cmdsn = htonl(isp->sess_cmdsn);
23407836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
23419162SPeter.Dunlap@Sun.COM istmh->expstatsn = htonl(icp->conn_expstatsn);
23429162SPeter.Dunlap@Sun.COM istmh->itt = icmdp->cmd_itt;
23437836SJohn.Forte@Sun.COM
23447836SJohn.Forte@Sun.COM switch (icmdp->cmd_un.reset.level) {
23457836SJohn.Forte@Sun.COM case RESET_LUN:
23469162SPeter.Dunlap@Sun.COM istmh->function = ISCSI_FLAG_FINAL |
23477836SJohn.Forte@Sun.COM ISCSI_TM_FUNC_LOGICAL_UNIT_RESET;
23489162SPeter.Dunlap@Sun.COM ISCSI_LUN_BYTE_COPY(istmh->lun, icmdp->cmd_lun->lun_num);
23497836SJohn.Forte@Sun.COM break;
23507836SJohn.Forte@Sun.COM case RESET_TARGET:
23517836SJohn.Forte@Sun.COM case RESET_BUS:
23529162SPeter.Dunlap@Sun.COM istmh->function = ISCSI_FLAG_FINAL |
23537836SJohn.Forte@Sun.COM ISCSI_TM_FUNC_TARGET_WARM_RESET;
23547836SJohn.Forte@Sun.COM break;
23557836SJohn.Forte@Sun.COM default:
23567836SJohn.Forte@Sun.COM /* unsupported / unknown level */
23577836SJohn.Forte@Sun.COM ASSERT(FALSE);
23587836SJohn.Forte@Sun.COM break;
23597836SJohn.Forte@Sun.COM }
23607836SJohn.Forte@Sun.COM
23619162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh,
23629162SPeter.Dunlap@Sun.COM sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp);
23637836SJohn.Forte@Sun.COM
23647836SJohn.Forte@Sun.COM return (rval);
23657836SJohn.Forte@Sun.COM }
23667836SJohn.Forte@Sun.COM
23677836SJohn.Forte@Sun.COM
23687836SJohn.Forte@Sun.COM /*
23697836SJohn.Forte@Sun.COM * iscsi_tx_logout -
23707836SJohn.Forte@Sun.COM *
23717836SJohn.Forte@Sun.COM */
23727836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_logout(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)23737836SJohn.Forte@Sun.COM iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
23747836SJohn.Forte@Sun.COM {
23757836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
23767836SJohn.Forte@Sun.COM iscsi_conn_t *icp = NULL;
23779162SPeter.Dunlap@Sun.COM iscsi_logout_hdr_t *ilh;
23787836SJohn.Forte@Sun.COM
23797836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
23807836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
23817836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
23827836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
23837836SJohn.Forte@Sun.COM
23849162SPeter.Dunlap@Sun.COM ilh = kmem_zalloc(sizeof (iscsi_logout_hdr_t), KM_SLEEP);
23859162SPeter.Dunlap@Sun.COM ilh->opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE;
23869162SPeter.Dunlap@Sun.COM ilh->flags = ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION;
23879162SPeter.Dunlap@Sun.COM ilh->itt = icmdp->cmd_itt;
23889162SPeter.Dunlap@Sun.COM ilh->cid = icp->conn_cid;
23897836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_cmdsn_mutex);
23909780SBing.Zhao@Sun.COM icmdp->cmd_sn = isp->sess_cmdsn;
23919162SPeter.Dunlap@Sun.COM ilh->cmdsn = htonl(isp->sess_cmdsn);
23927836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_cmdsn_mutex);
23939162SPeter.Dunlap@Sun.COM ilh->expstatsn = htonl(icp->conn_expstatsn);
23949162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(icp, ISCSI_OP_LOGOUT_CMD, ilh,
23959162SPeter.Dunlap@Sun.COM sizeof (iscsi_logout_hdr_t), icmdp);
23967836SJohn.Forte@Sun.COM
23977836SJohn.Forte@Sun.COM return (rval);
23987836SJohn.Forte@Sun.COM }
23997836SJohn.Forte@Sun.COM
24007836SJohn.Forte@Sun.COM /*
24017836SJohn.Forte@Sun.COM * iscsi_tx_text - setup iSCSI text request header and send PDU with
24027836SJohn.Forte@Sun.COM * data given in the buffer attached to the command. For a single
24037836SJohn.Forte@Sun.COM * text request, the target may need to send its response in multiple
24047836SJohn.Forte@Sun.COM * text response. In this case, empty text requests are sent after
24057836SJohn.Forte@Sun.COM * each received response to notify the target the initiator is ready
24067836SJohn.Forte@Sun.COM * for more response. For the initial request, the data_len field in
24077836SJohn.Forte@Sun.COM * the text specific portion of a command is set to the amount of data
24087836SJohn.Forte@Sun.COM * the initiator wants to send as part of the request. If additional
24097836SJohn.Forte@Sun.COM * empty text requests are required for long responses, the data_len
24107836SJohn.Forte@Sun.COM * field is set to 0 by the iscsi_handle_text function.
24117836SJohn.Forte@Sun.COM */
24127836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_tx_text(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)24137836SJohn.Forte@Sun.COM iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
24147836SJohn.Forte@Sun.COM {
24157836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
24167836SJohn.Forte@Sun.COM iscsi_conn_t *icp = NULL;
24179162SPeter.Dunlap@Sun.COM iscsi_text_hdr_t *ith;
24189162SPeter.Dunlap@Sun.COM
24197836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
24207836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
24217836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
24227836SJohn.Forte@Sun.COM
24239162SPeter.Dunlap@Sun.COM ith = kmem_zalloc(sizeof (iscsi_text_hdr_t), KM_SLEEP);
24249162SPeter.Dunlap@Sun.COM ASSERT(ith != NULL);
24259162SPeter.Dunlap@Sun.COM ith->flags = ISCSI_FLAG_FINAL;
24269162SPeter.Dunlap@Sun.COM hton24(ith->dlength, icmdp->cmd_un.text.data_len);
24279162SPeter.Dunlap@Sun.COM ith->ttt = icmdp->cmd_un.text.ttt;
24289162SPeter.Dunlap@Sun.COM iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ith,
24299780SBing.Zhao@Sun.COM ISCSI_OP_TEXT_CMD, icmdp);
24309162SPeter.Dunlap@Sun.COM bcopy(icmdp->cmd_un.text.lun, ith->rsvd4, sizeof (ith->rsvd4));
24319162SPeter.Dunlap@Sun.COM
24329162SPeter.Dunlap@Sun.COM iscsi_tx_pdu(icp, ISCSI_OP_TEXT_CMD, ith, sizeof (iscsi_text_hdr_t),
24339162SPeter.Dunlap@Sun.COM icmdp);
24347836SJohn.Forte@Sun.COM
24357836SJohn.Forte@Sun.COM return (rval);
24367836SJohn.Forte@Sun.COM }
24377836SJohn.Forte@Sun.COM
24387836SJohn.Forte@Sun.COM /*
24397836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
24407836SJohn.Forte@Sun.COM * | End of protocol send routines |
24417836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
24427836SJohn.Forte@Sun.COM */
24437836SJohn.Forte@Sun.COM
24447836SJohn.Forte@Sun.COM /*
24457836SJohn.Forte@Sun.COM * iscsi_handle_abort -
24467836SJohn.Forte@Sun.COM *
24477836SJohn.Forte@Sun.COM */
24487836SJohn.Forte@Sun.COM void
iscsi_handle_abort(void * arg)24497836SJohn.Forte@Sun.COM iscsi_handle_abort(void *arg)
24507836SJohn.Forte@Sun.COM {
24517836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
24527836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = (iscsi_cmd_t *)arg;
24537836SJohn.Forte@Sun.COM iscsi_cmd_t *new_icmdp;
24547836SJohn.Forte@Sun.COM iscsi_conn_t *icp;
24557836SJohn.Forte@Sun.COM
24567836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
24577836SJohn.Forte@Sun.COM icp = icmdp->cmd_conn;
24587836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
24597836SJohn.Forte@Sun.COM isp = icp->conn_sess;
24607836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
24617836SJohn.Forte@Sun.COM
24627836SJohn.Forte@Sun.COM /* there should only be one abort */
24637836SJohn.Forte@Sun.COM ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
24647836SJohn.Forte@Sun.COM
24657836SJohn.Forte@Sun.COM new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
24669780SBing.Zhao@Sun.COM new_icmdp->cmd_type = ISCSI_CMD_TYPE_ABORT;
24679780SBing.Zhao@Sun.COM new_icmdp->cmd_lun = icmdp->cmd_lun;
24689780SBing.Zhao@Sun.COM new_icmdp->cmd_un.abort.icmdp = icmdp;
24699780SBing.Zhao@Sun.COM new_icmdp->cmd_conn = icmdp->cmd_conn;
24709780SBing.Zhao@Sun.COM icmdp->cmd_un.scsi.abort_icmdp = new_icmdp;
24717836SJohn.Forte@Sun.COM
24727836SJohn.Forte@Sun.COM /* pending queue mutex is already held by timeout_checks */
24737836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp);
24747836SJohn.Forte@Sun.COM }
24757836SJohn.Forte@Sun.COM
24769162SPeter.Dunlap@Sun.COM /*
24779162SPeter.Dunlap@Sun.COM * Callback from IDM indicating that the task has been suspended or aborted.
24789162SPeter.Dunlap@Sun.COM */
24799162SPeter.Dunlap@Sun.COM void
iscsi_task_aborted(idm_task_t * idt,idm_status_t status)24809162SPeter.Dunlap@Sun.COM iscsi_task_aborted(idm_task_t *idt, idm_status_t status)
24819162SPeter.Dunlap@Sun.COM {
24829162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp = idt->idt_private;
24839162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = icmdp->cmd_conn;
24849162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp = icp->conn_sess;
24859162SPeter.Dunlap@Sun.COM
24869162SPeter.Dunlap@Sun.COM ASSERT(icmdp->cmd_conn != NULL);
24879162SPeter.Dunlap@Sun.COM
24889162SPeter.Dunlap@Sun.COM switch (status) {
24899162SPeter.Dunlap@Sun.COM case IDM_STATUS_SUSPENDED:
24909162SPeter.Dunlap@Sun.COM /*
24919162SPeter.Dunlap@Sun.COM * If the task is suspended, it may be aborted later,
24929162SPeter.Dunlap@Sun.COM * so we can ignore this notification.
24939162SPeter.Dunlap@Sun.COM */
24949162SPeter.Dunlap@Sun.COM break;
24959162SPeter.Dunlap@Sun.COM
24969162SPeter.Dunlap@Sun.COM case IDM_STATUS_ABORTED:
24979162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
24989162SPeter.Dunlap@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E9, isp);
24999162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
25009162SPeter.Dunlap@Sun.COM break;
25019162SPeter.Dunlap@Sun.COM
25029162SPeter.Dunlap@Sun.COM default:
25039162SPeter.Dunlap@Sun.COM /*
25049162SPeter.Dunlap@Sun.COM * Unexpected status.
25059162SPeter.Dunlap@Sun.COM */
25069162SPeter.Dunlap@Sun.COM ASSERT(0);
25079162SPeter.Dunlap@Sun.COM }
25089162SPeter.Dunlap@Sun.COM
25099162SPeter.Dunlap@Sun.COM }
25107836SJohn.Forte@Sun.COM
25117836SJohn.Forte@Sun.COM /*
25127836SJohn.Forte@Sun.COM * iscsi_handle_nop -
25137836SJohn.Forte@Sun.COM *
25147836SJohn.Forte@Sun.COM */
25157836SJohn.Forte@Sun.COM static void
iscsi_handle_nop(iscsi_conn_t * icp,uint32_t itt,uint32_t ttt)25167836SJohn.Forte@Sun.COM iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt)
25177836SJohn.Forte@Sun.COM {
25187836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
25197836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
25207836SJohn.Forte@Sun.COM
25217836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
25227836SJohn.Forte@Sun.COM isp = icp->conn_sess;
25237836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
25247836SJohn.Forte@Sun.COM
25257836SJohn.Forte@Sun.COM icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP);
25267836SJohn.Forte@Sun.COM if (icmdp == NULL) {
25277836SJohn.Forte@Sun.COM return;
25287836SJohn.Forte@Sun.COM }
25297836SJohn.Forte@Sun.COM
25307836SJohn.Forte@Sun.COM icmdp->cmd_type = ISCSI_CMD_TYPE_NOP;
25317836SJohn.Forte@Sun.COM icmdp->cmd_itt = itt;
25327836SJohn.Forte@Sun.COM icmdp->cmd_ttt = ttt;
25337836SJohn.Forte@Sun.COM icmdp->cmd_lun = NULL;
25347836SJohn.Forte@Sun.COM icp->conn_nop_lbolt = ddi_get_lbolt();
25357836SJohn.Forte@Sun.COM
25367836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
25377836SJohn.Forte@Sun.COM }
25387836SJohn.Forte@Sun.COM
25397836SJohn.Forte@Sun.COM /*
25409780SBing.Zhao@Sun.COM * iscsi_handle_reset - send reset request to the target
25417836SJohn.Forte@Sun.COM *
25427836SJohn.Forte@Sun.COM */
25437836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_handle_reset(iscsi_sess_t * isp,int level,iscsi_lun_t * ilp)25447836SJohn.Forte@Sun.COM iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp)
25457836SJohn.Forte@Sun.COM {
25467836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
25477836SJohn.Forte@Sun.COM iscsi_conn_t *icp;
25487836SJohn.Forte@Sun.COM iscsi_cmd_t icmd;
25497836SJohn.Forte@Sun.COM
25507836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
25517836SJohn.Forte@Sun.COM
25529780SBing.Zhao@Sun.COM if (level == RESET_LUN) {
25539780SBing.Zhao@Sun.COM rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
25549780SBing.Zhao@Sun.COM ASSERT(ilp != NULL);
25559780SBing.Zhao@Sun.COM if (ilp->lun_state & ISCSI_LUN_STATE_BUSY) {
25569780SBing.Zhao@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
25579780SBing.Zhao@Sun.COM return (ISCSI_STATUS_SUCCESS);
25589780SBing.Zhao@Sun.COM }
25599780SBing.Zhao@Sun.COM ilp->lun_state |= ISCSI_LUN_STATE_BUSY;
25609780SBing.Zhao@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
25619780SBing.Zhao@Sun.COM } else {
25629780SBing.Zhao@Sun.COM mutex_enter(&isp->sess_reset_mutex);
25639780SBing.Zhao@Sun.COM if (isp->sess_reset_in_progress == B_TRUE) {
25649780SBing.Zhao@Sun.COM /*
25659780SBing.Zhao@Sun.COM * If the reset is in progress, it is unnecessary
25669780SBing.Zhao@Sun.COM * to send reset to the target redunantly.
25679780SBing.Zhao@Sun.COM */
25689780SBing.Zhao@Sun.COM mutex_exit(&isp->sess_reset_mutex);
25699780SBing.Zhao@Sun.COM return (ISCSI_STATUS_SUCCESS);
25709780SBing.Zhao@Sun.COM }
25719780SBing.Zhao@Sun.COM isp->sess_reset_in_progress = B_TRUE;
25729780SBing.Zhao@Sun.COM mutex_exit(&isp->sess_reset_mutex);
25739780SBing.Zhao@Sun.COM }
25749780SBing.Zhao@Sun.COM
25757836SJohn.Forte@Sun.COM bzero(&icmd, sizeof (iscsi_cmd_t));
25767836SJohn.Forte@Sun.COM icmd.cmd_sig = ISCSI_SIG_CMD;
25777836SJohn.Forte@Sun.COM icmd.cmd_state = ISCSI_CMD_STATE_FREE;
25787836SJohn.Forte@Sun.COM icmd.cmd_type = ISCSI_CMD_TYPE_RESET;
25797836SJohn.Forte@Sun.COM icmd.cmd_lun = ilp;
25807836SJohn.Forte@Sun.COM icmd.cmd_un.reset.level = level;
25817836SJohn.Forte@Sun.COM icmd.cmd_result = ISCSI_STATUS_SUCCESS;
25827836SJohn.Forte@Sun.COM icmd.cmd_completed = B_FALSE;
25839780SBing.Zhao@Sun.COM icmd.cmd_un.reset.response = SCSI_TCP_TM_RESP_COMPLETE;
25849780SBing.Zhao@Sun.COM
25857836SJohn.Forte@Sun.COM mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL);
25867836SJohn.Forte@Sun.COM cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL);
25877836SJohn.Forte@Sun.COM /*
25887836SJohn.Forte@Sun.COM * If we received an IO and we are not in the
25897836SJohn.Forte@Sun.COM * LOGGED_IN state we are in the process of
25907836SJohn.Forte@Sun.COM * failing. Just respond that we are BUSY.
25917836SJohn.Forte@Sun.COM */
2592*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
25937836SJohn.Forte@Sun.COM if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
25947836SJohn.Forte@Sun.COM /* We aren't connected to the target fake success */
2595*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
25969780SBing.Zhao@Sun.COM
25979780SBing.Zhao@Sun.COM if (level == RESET_LUN) {
25989780SBing.Zhao@Sun.COM rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
25999780SBing.Zhao@Sun.COM ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
26009780SBing.Zhao@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
26019780SBing.Zhao@Sun.COM } else {
26029780SBing.Zhao@Sun.COM mutex_enter(&isp->sess_reset_mutex);
26039780SBing.Zhao@Sun.COM isp->sess_reset_in_progress = B_FALSE;
26049780SBing.Zhao@Sun.COM mutex_exit(&isp->sess_reset_mutex);
26059780SBing.Zhao@Sun.COM }
26069780SBing.Zhao@Sun.COM
26077836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
26087836SJohn.Forte@Sun.COM }
26097836SJohn.Forte@Sun.COM
26107836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
26117836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp);
26127836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
2613*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
26147836SJohn.Forte@Sun.COM
26157836SJohn.Forte@Sun.COM /* stall until completed */
26167836SJohn.Forte@Sun.COM mutex_enter(&icmd.cmd_mutex);
26177836SJohn.Forte@Sun.COM while (icmd.cmd_completed == B_FALSE) {
26187836SJohn.Forte@Sun.COM cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex);
26197836SJohn.Forte@Sun.COM }
26207836SJohn.Forte@Sun.COM mutex_exit(&icmd.cmd_mutex);
26217836SJohn.Forte@Sun.COM
26227836SJohn.Forte@Sun.COM /* copy rval */
26237836SJohn.Forte@Sun.COM rval = icmd.cmd_result;
26247836SJohn.Forte@Sun.COM
26257836SJohn.Forte@Sun.COM if (rval == ISCSI_STATUS_SUCCESS) {
26267836SJohn.Forte@Sun.COM /*
26277836SJohn.Forte@Sun.COM * Reset was successful. We need to flush
26287836SJohn.Forte@Sun.COM * all active IOs.
26297836SJohn.Forte@Sun.COM */
26307836SJohn.Forte@Sun.COM rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
26317836SJohn.Forte@Sun.COM icp = isp->sess_conn_list;
26327836SJohn.Forte@Sun.COM while (icp != NULL) {
26337836SJohn.Forte@Sun.COM iscsi_cmd_t *t_icmdp = NULL;
26349780SBing.Zhao@Sun.COM iscsi_cmd_t *next_icmdp = NULL;
26357836SJohn.Forte@Sun.COM
26367836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
26377836SJohn.Forte@Sun.COM t_icmdp = icp->conn_queue_active.head;
26387836SJohn.Forte@Sun.COM while (t_icmdp != NULL) {
26399780SBing.Zhao@Sun.COM next_icmdp = t_icmdp->cmd_next;
26409780SBing.Zhao@Sun.COM mutex_enter(&t_icmdp->cmd_mutex);
26419780SBing.Zhao@Sun.COM if (!(t_icmdp->cmd_misc_flags &
26429780SBing.Zhao@Sun.COM ISCSI_CMD_MISCFLAG_SENT)) {
26439780SBing.Zhao@Sun.COM /*
26449780SBing.Zhao@Sun.COM * Although this command is in the
26459780SBing.Zhao@Sun.COM * active queue, it has not been sent.
26469780SBing.Zhao@Sun.COM * Skip it.
26479780SBing.Zhao@Sun.COM */
26489780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
26499780SBing.Zhao@Sun.COM t_icmdp = next_icmdp;
26509780SBing.Zhao@Sun.COM continue;
26519780SBing.Zhao@Sun.COM }
26529780SBing.Zhao@Sun.COM if (level == RESET_LUN) {
26539780SBing.Zhao@Sun.COM if (icmd.cmd_lun == NULL ||
26549780SBing.Zhao@Sun.COM t_icmdp->cmd_lun == NULL ||
26559780SBing.Zhao@Sun.COM (icmd.cmd_lun->lun_num !=
26569780SBing.Zhao@Sun.COM t_icmdp->cmd_lun->lun_num)) {
26579780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
26589780SBing.Zhao@Sun.COM t_icmdp = next_icmdp;
26599780SBing.Zhao@Sun.COM continue;
26609780SBing.Zhao@Sun.COM }
26619780SBing.Zhao@Sun.COM }
26629780SBing.Zhao@Sun.COM
26639780SBing.Zhao@Sun.COM if (icmd.cmd_sn == t_icmdp->cmd_sn) {
26649780SBing.Zhao@Sun.COM /*
26659780SBing.Zhao@Sun.COM * This command may be replied with
26669780SBing.Zhao@Sun.COM * UA sense key later. So currently
26679780SBing.Zhao@Sun.COM * it is not a suitable time to flush
26689780SBing.Zhao@Sun.COM * it. Mark its flag with FLUSH. There
26699780SBing.Zhao@Sun.COM * is no harm to keep it for a while.
26709780SBing.Zhao@Sun.COM */
26719780SBing.Zhao@Sun.COM t_icmdp->cmd_misc_flags |=
26729780SBing.Zhao@Sun.COM ISCSI_CMD_MISCFLAG_FLUSH;
26739780SBing.Zhao@Sun.COM if (t_icmdp->cmd_type ==
26749780SBing.Zhao@Sun.COM ISCSI_CMD_TYPE_SCSI) {
26759780SBing.Zhao@Sun.COM t_icmdp->cmd_un.scsi.pkt_stat |=
26769780SBing.Zhao@Sun.COM STAT_BUS_RESET;
26779780SBing.Zhao@Sun.COM }
26789780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
26799780SBing.Zhao@Sun.COM } else if ((icmd.cmd_sn > t_icmdp->cmd_sn) ||
26809780SBing.Zhao@Sun.COM ((t_icmdp->cmd_sn - icmd.cmd_sn) >
26819780SBing.Zhao@Sun.COM ISCSI_CMD_SN_WRAP)) {
26829780SBing.Zhao@Sun.COM /*
26839780SBing.Zhao@Sun.COM * This reset request must act on all
26849780SBing.Zhao@Sun.COM * the commnds from the same session
26859780SBing.Zhao@Sun.COM * having a CmdSN lower than the task
26869780SBing.Zhao@Sun.COM * mangement CmdSN. So flush these
26879780SBing.Zhao@Sun.COM * commands here.
26889780SBing.Zhao@Sun.COM */
26899780SBing.Zhao@Sun.COM if (t_icmdp->cmd_type ==
26909780SBing.Zhao@Sun.COM ISCSI_CMD_TYPE_SCSI) {
26919780SBing.Zhao@Sun.COM t_icmdp->cmd_un.scsi.pkt_stat |=
26929780SBing.Zhao@Sun.COM STAT_BUS_RESET;
26939780SBing.Zhao@Sun.COM }
26949780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
26959780SBing.Zhao@Sun.COM iscsi_cmd_state_machine(t_icmdp,
26969780SBing.Zhao@Sun.COM ISCSI_CMD_EVENT_E7, isp);
26979780SBing.Zhao@Sun.COM } else {
26989780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
26999780SBing.Zhao@Sun.COM }
27009780SBing.Zhao@Sun.COM
27019780SBing.Zhao@Sun.COM t_icmdp = next_icmdp;
27027836SJohn.Forte@Sun.COM }
27037836SJohn.Forte@Sun.COM
27047836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
27057836SJohn.Forte@Sun.COM icp = icp->conn_next;
27067836SJohn.Forte@Sun.COM }
27077836SJohn.Forte@Sun.COM rw_exit(&isp->sess_conn_list_rwlock);
27087836SJohn.Forte@Sun.COM }
27097836SJohn.Forte@Sun.COM
27107836SJohn.Forte@Sun.COM /* clean up */
27117836SJohn.Forte@Sun.COM cv_destroy(&icmd.cmd_completion);
27127836SJohn.Forte@Sun.COM mutex_destroy(&icmd.cmd_mutex);
27137836SJohn.Forte@Sun.COM
27149780SBing.Zhao@Sun.COM if (level == RESET_LUN) {
27159780SBing.Zhao@Sun.COM rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER);
27169780SBing.Zhao@Sun.COM ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY;
27179780SBing.Zhao@Sun.COM rw_exit(&isp->sess_lun_list_rwlock);
27189780SBing.Zhao@Sun.COM } else {
27199780SBing.Zhao@Sun.COM mutex_enter(&isp->sess_reset_mutex);
27209780SBing.Zhao@Sun.COM isp->sess_reset_in_progress = B_FALSE;
27219780SBing.Zhao@Sun.COM mutex_exit(&isp->sess_reset_mutex);
27229780SBing.Zhao@Sun.COM }
27239780SBing.Zhao@Sun.COM
27247836SJohn.Forte@Sun.COM return (rval);
27257836SJohn.Forte@Sun.COM }
27267836SJohn.Forte@Sun.COM
27279162SPeter.Dunlap@Sun.COM /*
272811078SPeter.Cudhea@Sun.COM * iscsi_logout_start - task handler for deferred logout
272911078SPeter.Cudhea@Sun.COM * Acquire a hold before call, released in iscsi_handle_logout
27309162SPeter.Dunlap@Sun.COM */
27319162SPeter.Dunlap@Sun.COM static void
iscsi_logout_start(void * arg)27329162SPeter.Dunlap@Sun.COM iscsi_logout_start(void *arg)
27339162SPeter.Dunlap@Sun.COM {
27349162SPeter.Dunlap@Sun.COM iscsi_task_t *itp = (iscsi_task_t *)arg;
27359162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp;
27369162SPeter.Dunlap@Sun.COM
27379162SPeter.Dunlap@Sun.COM icp = (iscsi_conn_t *)itp->t_arg;
27389162SPeter.Dunlap@Sun.COM
27399162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_state_mutex);
27409162SPeter.Dunlap@Sun.COM (void) iscsi_handle_logout(icp);
27419162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
27429162SPeter.Dunlap@Sun.COM }
27437836SJohn.Forte@Sun.COM
27447836SJohn.Forte@Sun.COM /*
27457836SJohn.Forte@Sun.COM * iscsi_handle_logout - This function will issue a logout for
27467836SJohn.Forte@Sun.COM * the session from a specific connection.
274711078SPeter.Cudhea@Sun.COM * Acquire idm_conn_hold before call. Released internally.
27487836SJohn.Forte@Sun.COM */
27497836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_handle_logout(iscsi_conn_t * icp)27507836SJohn.Forte@Sun.COM iscsi_handle_logout(iscsi_conn_t *icp)
27517836SJohn.Forte@Sun.COM {
27527836SJohn.Forte@Sun.COM iscsi_sess_t *isp;
27539162SPeter.Dunlap@Sun.COM idm_conn_t *ic;
27547836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp;
27557836SJohn.Forte@Sun.COM int rval;
27567836SJohn.Forte@Sun.COM
27577836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
27587836SJohn.Forte@Sun.COM isp = icp->conn_sess;
27599162SPeter.Dunlap@Sun.COM ic = icp->conn_ic;
27607836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
27617836SJohn.Forte@Sun.COM ASSERT(isp->sess_hba != NULL);
27629162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&icp->conn_state_mutex));
27639162SPeter.Dunlap@Sun.COM
27649162SPeter.Dunlap@Sun.COM /*
276511078SPeter.Cudhea@Sun.COM * If the connection has already gone down (e.g. if the transport
276611078SPeter.Cudhea@Sun.COM * failed between when this LOGOUT was generated and now) then we
276711078SPeter.Cudhea@Sun.COM * can and must skip sending the LOGOUT. Check the same condition
276811078SPeter.Cudhea@Sun.COM * we use below to determine that connection has "settled".
27699162SPeter.Dunlap@Sun.COM */
277011078SPeter.Cudhea@Sun.COM if ((icp->conn_state == ISCSI_CONN_STATE_FREE) ||
277111078SPeter.Cudhea@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
277211078SPeter.Cudhea@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_POLLING)) {
277311078SPeter.Cudhea@Sun.COM idm_conn_rele(ic);
277411078SPeter.Cudhea@Sun.COM return (0);
277511078SPeter.Cudhea@Sun.COM }
27767836SJohn.Forte@Sun.COM
27777836SJohn.Forte@Sun.COM icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
27787836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
27797836SJohn.Forte@Sun.COM icmdp->cmd_type = ISCSI_CMD_TYPE_LOGOUT;
27807836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
27817836SJohn.Forte@Sun.COM icmdp->cmd_completed = B_FALSE;
27827836SJohn.Forte@Sun.COM
27837836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
27847836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
27857836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
27867836SJohn.Forte@Sun.COM
27877836SJohn.Forte@Sun.COM /*
27887836SJohn.Forte@Sun.COM * release connection state mutex to avoid a deadlock. This
27897836SJohn.Forte@Sun.COM * function is called from within the connection state
27907836SJohn.Forte@Sun.COM * machine with the lock held. When the logout response is
27917836SJohn.Forte@Sun.COM * received another call to the connection state machine
27927836SJohn.Forte@Sun.COM * occurs which causes the deadlock
27937836SJohn.Forte@Sun.COM */
27947836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_state_mutex);
27957836SJohn.Forte@Sun.COM
27967836SJohn.Forte@Sun.COM /* stall until completed */
27977836SJohn.Forte@Sun.COM mutex_enter(&icmdp->cmd_mutex);
27987836SJohn.Forte@Sun.COM while (icmdp->cmd_completed == B_FALSE) {
27997836SJohn.Forte@Sun.COM cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
28007836SJohn.Forte@Sun.COM }
28017836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
28027836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_state_mutex);
28037836SJohn.Forte@Sun.COM
28047836SJohn.Forte@Sun.COM /* copy rval */
28057836SJohn.Forte@Sun.COM rval = icmdp->cmd_result;
28067836SJohn.Forte@Sun.COM
28077836SJohn.Forte@Sun.COM /* clean up */
28087836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
28097836SJohn.Forte@Sun.COM
28109162SPeter.Dunlap@Sun.COM if (rval != 0) {
28119162SPeter.Dunlap@Sun.COM /* If the logout failed then drop the connection */
28129162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(icp->conn_ic);
28139162SPeter.Dunlap@Sun.COM }
28149162SPeter.Dunlap@Sun.COM
28159162SPeter.Dunlap@Sun.COM /* stall until connection settles */
28169162SPeter.Dunlap@Sun.COM while ((icp->conn_state != ISCSI_CONN_STATE_FREE) &&
28179162SPeter.Dunlap@Sun.COM (icp->conn_state != ISCSI_CONN_STATE_FAILED) &&
28189162SPeter.Dunlap@Sun.COM (icp->conn_state != ISCSI_CONN_STATE_POLLING)) {
28199162SPeter.Dunlap@Sun.COM /* wait for transition */
28209162SPeter.Dunlap@Sun.COM cv_wait(&icp->conn_state_change, &icp->conn_state_mutex);
28219162SPeter.Dunlap@Sun.COM }
28229162SPeter.Dunlap@Sun.COM
28239162SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
28249162SPeter.Dunlap@Sun.COM
28259162SPeter.Dunlap@Sun.COM /*
28269162SPeter.Dunlap@Sun.COM * Return value reflects whether the logout command completed --
28279162SPeter.Dunlap@Sun.COM * regardless of the return value the connection is closed and
28289162SPeter.Dunlap@Sun.COM * ready for reconnection.
28299162SPeter.Dunlap@Sun.COM */
28307836SJohn.Forte@Sun.COM return (rval);
28317836SJohn.Forte@Sun.COM }
28327836SJohn.Forte@Sun.COM
28339162SPeter.Dunlap@Sun.COM
28347836SJohn.Forte@Sun.COM /*
28357836SJohn.Forte@Sun.COM * iscsi_handle_text - main control function for iSCSI text requests. This
28367836SJohn.Forte@Sun.COM * function handles allocating the command, sending initial text request, and
28377836SJohn.Forte@Sun.COM * handling long response sequence.
28387836SJohn.Forte@Sun.COM * If a data overflow condition occurs, iscsi_handle_text continues to
28397836SJohn.Forte@Sun.COM * receive responses until the all data has been recieved. This allows
28407836SJohn.Forte@Sun.COM * the full data length to be returned to the caller.
28417836SJohn.Forte@Sun.COM */
28427836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_handle_text(iscsi_conn_t * icp,char * buf,uint32_t buf_len,uint32_t data_len,uint32_t * rx_data_len)28437836SJohn.Forte@Sun.COM iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len,
28447836SJohn.Forte@Sun.COM uint32_t data_len, uint32_t *rx_data_len)
28457836SJohn.Forte@Sun.COM {
28467836SJohn.Forte@Sun.COM iscsi_sess_t *isp;
28477836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp;
28487836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
28497836SJohn.Forte@Sun.COM
28507836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
28517836SJohn.Forte@Sun.COM ASSERT(buf != NULL);
28527836SJohn.Forte@Sun.COM ASSERT(rx_data_len != NULL);
28537836SJohn.Forte@Sun.COM
28547836SJohn.Forte@Sun.COM isp = icp->conn_sess;
28557836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
28567836SJohn.Forte@Sun.COM
28577836SJohn.Forte@Sun.COM /*
28587836SJohn.Forte@Sun.COM * Ensure data for text request command is not greater
28597836SJohn.Forte@Sun.COM * than the negotiated maximum receive data seqment length.
28607836SJohn.Forte@Sun.COM *
28617836SJohn.Forte@Sun.COM * Although iSCSI allows for long text requests (multiple
28627836SJohn.Forte@Sun.COM * pdus), this function places a restriction on text
28637836SJohn.Forte@Sun.COM * requests to ensure it is handled by a single PDU.
28647836SJohn.Forte@Sun.COM */
28657836SJohn.Forte@Sun.COM if (data_len > icp->conn_params.max_xmit_data_seg_len) {
28667836SJohn.Forte@Sun.COM return (ISCSI_STATUS_CMD_FAILED);
28677836SJohn.Forte@Sun.COM }
28687836SJohn.Forte@Sun.COM
28697836SJohn.Forte@Sun.COM icmdp = iscsi_cmd_alloc(icp, KM_SLEEP);
28707836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
28717836SJohn.Forte@Sun.COM
28727836SJohn.Forte@Sun.COM icmdp->cmd_type = ISCSI_CMD_TYPE_TEXT;
28737836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
28748231SJack.Meng@Sun.COM icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE;
28757836SJohn.Forte@Sun.COM icmdp->cmd_completed = B_FALSE;
28767836SJohn.Forte@Sun.COM
28777836SJohn.Forte@Sun.COM icmdp->cmd_un.text.buf = buf;
28787836SJohn.Forte@Sun.COM icmdp->cmd_un.text.buf_len = buf_len;
28797836SJohn.Forte@Sun.COM icmdp->cmd_un.text.offset = 0;
28807836SJohn.Forte@Sun.COM icmdp->cmd_un.text.data_len = data_len;
28817836SJohn.Forte@Sun.COM icmdp->cmd_un.text.total_rx_len = 0;
28827836SJohn.Forte@Sun.COM icmdp->cmd_un.text.ttt = ISCSI_RSVD_TASK_TAG;
28837836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_INITIAL_REQ;
28847836SJohn.Forte@Sun.COM
28857836SJohn.Forte@Sun.COM long_text_response:
2886*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
28877836SJohn.Forte@Sun.COM if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
28887836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
2889*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
28907836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NO_CONN_LOGGED_IN);
28917836SJohn.Forte@Sun.COM }
28927836SJohn.Forte@Sun.COM
28937836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
28947836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
28957836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
2896*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
28977836SJohn.Forte@Sun.COM
28987836SJohn.Forte@Sun.COM /* stall until completed */
28997836SJohn.Forte@Sun.COM mutex_enter(&icmdp->cmd_mutex);
29007836SJohn.Forte@Sun.COM while (icmdp->cmd_completed == B_FALSE) {
29017836SJohn.Forte@Sun.COM cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
29027836SJohn.Forte@Sun.COM }
29037836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
29047836SJohn.Forte@Sun.COM
29057836SJohn.Forte@Sun.COM /*
29067836SJohn.Forte@Sun.COM * check if error occured. If data overflow occured, continue on
29077836SJohn.Forte@Sun.COM * to ensure we get all data so that the full data length can be
29087836SJohn.Forte@Sun.COM * returned to the user
29097836SJohn.Forte@Sun.COM */
29107836SJohn.Forte@Sun.COM if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) &&
29117836SJohn.Forte@Sun.COM (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) {
29127836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)",
29137836SJohn.Forte@Sun.COM icmdp->cmd_result);
29147836SJohn.Forte@Sun.COM rval = icmdp->cmd_result;
29157836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
29167836SJohn.Forte@Sun.COM return (rval);
29177836SJohn.Forte@Sun.COM }
29187836SJohn.Forte@Sun.COM
29197836SJohn.Forte@Sun.COM /* check if this was a partial text PDU */
29207836SJohn.Forte@Sun.COM if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) {
29217836SJohn.Forte@Sun.COM /*
29227836SJohn.Forte@Sun.COM * If a paritial text rexponse received, send an empty
29237836SJohn.Forte@Sun.COM * text request. This follows the behaviour specified
29247836SJohn.Forte@Sun.COM * in RFC3720 regarding long text responses.
29257836SJohn.Forte@Sun.COM */
29268231SJack.Meng@Sun.COM icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE;
29277836SJohn.Forte@Sun.COM icmdp->cmd_completed = B_FALSE;
29287836SJohn.Forte@Sun.COM icmdp->cmd_un.text.data_len = 0;
29297836SJohn.Forte@Sun.COM icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION;
29307836SJohn.Forte@Sun.COM goto long_text_response;
29317836SJohn.Forte@Sun.COM }
29327836SJohn.Forte@Sun.COM
29337836SJohn.Forte@Sun.COM /*
29347836SJohn.Forte@Sun.COM * set total received data length. If data overflow this would be
29357836SJohn.Forte@Sun.COM * amount of data that would have been received if buffer large
29367836SJohn.Forte@Sun.COM * enough.
29377836SJohn.Forte@Sun.COM */
29387836SJohn.Forte@Sun.COM *rx_data_len = icmdp->cmd_un.text.total_rx_len;
29397836SJohn.Forte@Sun.COM
29407836SJohn.Forte@Sun.COM /* copy rval */
29417836SJohn.Forte@Sun.COM rval = icmdp->cmd_result;
29427836SJohn.Forte@Sun.COM
29437836SJohn.Forte@Sun.COM /* clean up */
29447836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
29457836SJohn.Forte@Sun.COM
29467836SJohn.Forte@Sun.COM return (rval);
29477836SJohn.Forte@Sun.COM }
29487836SJohn.Forte@Sun.COM
29497836SJohn.Forte@Sun.COM /*
29507836SJohn.Forte@Sun.COM * iscsi_handle_passthru - This function is used to send a uscsi_cmd
29517836SJohn.Forte@Sun.COM * to a specific target lun. This routine is used for internal purposes
29527836SJohn.Forte@Sun.COM * during enumeration and via the ISCSI_USCSICMD IOCTL. We restrict
29537836SJohn.Forte@Sun.COM * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS,
29547836SJohn.Forte@Sun.COM * and READ_CAPACITY for security purposes.
29557836SJohn.Forte@Sun.COM *
29567836SJohn.Forte@Sun.COM * The logic here is broken into three phases.
29577836SJohn.Forte@Sun.COM * 1) Allocate and initialize a pkt/icmdp
29587836SJohn.Forte@Sun.COM * 2) Send the pkt/icmdp
29597836SJohn.Forte@Sun.COM * 3) cv_wait for completion
29607836SJohn.Forte@Sun.COM */
29617836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_handle_passthru(iscsi_sess_t * isp,uint16_t lun,struct uscsi_cmd * ucmdp)29627836SJohn.Forte@Sun.COM iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp)
29637836SJohn.Forte@Sun.COM {
296411271SMilos.Muzik@Sun.COM iscsi_status_t rval;
296511271SMilos.Muzik@Sun.COM iscsi_cmd_t *icmdp;
296611271SMilos.Muzik@Sun.COM struct scsi_pkt *pkt;
296711271SMilos.Muzik@Sun.COM struct buf *bp;
296811271SMilos.Muzik@Sun.COM struct scsi_arq_status *arqstat;
296911271SMilos.Muzik@Sun.COM int statuslen;
29707836SJohn.Forte@Sun.COM
29717836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
29727836SJohn.Forte@Sun.COM ASSERT(ucmdp != NULL);
29737836SJohn.Forte@Sun.COM
29747836SJohn.Forte@Sun.COM if (ucmdp->uscsi_rqlen > SENSE_LENGTH) {
297511271SMilos.Muzik@Sun.COM /*
297611271SMilos.Muzik@Sun.COM * The caller provided sense buffer large enough for additional
297711271SMilos.Muzik@Sun.COM * sense bytes. We need to allocate pkt_scbp to fit them there
297811271SMilos.Muzik@Sun.COM * too.
297911271SMilos.Muzik@Sun.COM */
298011271SMilos.Muzik@Sun.COM statuslen = ucmdp->uscsi_rqlen + ISCSI_ARQ_STATUS_NOSENSE_LEN;
298111271SMilos.Muzik@Sun.COM } else {
298211271SMilos.Muzik@Sun.COM /* The default size of pkt_scbp */
298311271SMilos.Muzik@Sun.COM statuslen = sizeof (struct scsi_arq_status);
29847836SJohn.Forte@Sun.COM }
29857836SJohn.Forte@Sun.COM
29867836SJohn.Forte@Sun.COM /*
29877836SJohn.Forte@Sun.COM * Step 1. Setup structs - KM_SLEEP will always succeed
29887836SJohn.Forte@Sun.COM */
29897836SJohn.Forte@Sun.COM bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP);
29907836SJohn.Forte@Sun.COM ASSERT(bp != NULL);
29917836SJohn.Forte@Sun.COM pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP);
29927836SJohn.Forte@Sun.COM ASSERT(pkt != NULL);
29937836SJohn.Forte@Sun.COM icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP);
29947836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
29957836SJohn.Forte@Sun.COM
29967836SJohn.Forte@Sun.COM /* setup bp structure */
29977836SJohn.Forte@Sun.COM bp->b_flags = B_READ;
29987836SJohn.Forte@Sun.COM bp->b_bcount = ucmdp->uscsi_buflen;
29997836SJohn.Forte@Sun.COM bp->b_un.b_addr = ucmdp->uscsi_bufaddr;
30007836SJohn.Forte@Sun.COM
30017836SJohn.Forte@Sun.COM /* setup scsi_pkt structure */
30027836SJohn.Forte@Sun.COM pkt->pkt_ha_private = icmdp;
300311271SMilos.Muzik@Sun.COM pkt->pkt_scbp = kmem_zalloc(statuslen, KM_SLEEP);
30047836SJohn.Forte@Sun.COM pkt->pkt_cdbp = kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP);
30057836SJohn.Forte@Sun.COM /* callback routine for passthru, will wake cv_wait */
30067836SJohn.Forte@Sun.COM pkt->pkt_comp = iscsi_handle_passthru_callback;
30077836SJohn.Forte@Sun.COM pkt->pkt_time = ucmdp->uscsi_timeout;
30087836SJohn.Forte@Sun.COM
30097836SJohn.Forte@Sun.COM /* setup iscsi_cmd structure */
30107836SJohn.Forte@Sun.COM icmdp->cmd_lun = NULL;
30117836SJohn.Forte@Sun.COM icmdp->cmd_type = ISCSI_CMD_TYPE_SCSI;
30127836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.lun = lun;
30137836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.pkt = pkt;
30147836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.bp = bp;
30157836SJohn.Forte@Sun.COM bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
30167836SJohn.Forte@Sun.COM icmdp->cmd_un.scsi.cmdlen = ucmdp->uscsi_cdblen;
301711271SMilos.Muzik@Sun.COM icmdp->cmd_un.scsi.statuslen = statuslen;
30187836SJohn.Forte@Sun.COM icmdp->cmd_crc_error_seen = B_FALSE;
30197836SJohn.Forte@Sun.COM icmdp->cmd_completed = B_FALSE;
30207836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
30217836SJohn.Forte@Sun.COM
30227836SJohn.Forte@Sun.COM /*
30237836SJohn.Forte@Sun.COM * Step 2. Push IO onto pending queue. If we aren't in
30247836SJohn.Forte@Sun.COM * FULL_FEATURE we need to fail the IO.
30257836SJohn.Forte@Sun.COM */
3026*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
30277836SJohn.Forte@Sun.COM if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) {
3028*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
30297836SJohn.Forte@Sun.COM
30307836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
30317836SJohn.Forte@Sun.COM kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
303211271SMilos.Muzik@Sun.COM kmem_free(pkt->pkt_scbp, statuslen);
30337836SJohn.Forte@Sun.COM kmem_free(pkt, sizeof (struct scsi_pkt));
30347836SJohn.Forte@Sun.COM kmem_free(bp, sizeof (struct buf));
30357836SJohn.Forte@Sun.COM
30367836SJohn.Forte@Sun.COM return (ISCSI_STATUS_CMD_FAILED);
30377836SJohn.Forte@Sun.COM }
30387836SJohn.Forte@Sun.COM
30397836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
30407836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp);
30417836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
3042*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
30437836SJohn.Forte@Sun.COM
30447836SJohn.Forte@Sun.COM /*
30457836SJohn.Forte@Sun.COM * Step 3. Wait on cv_wait for completion routine
30467836SJohn.Forte@Sun.COM */
30477836SJohn.Forte@Sun.COM mutex_enter(&icmdp->cmd_mutex);
30487836SJohn.Forte@Sun.COM while (icmdp->cmd_completed == B_FALSE) {
30497836SJohn.Forte@Sun.COM cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex);
30507836SJohn.Forte@Sun.COM }
30517836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
30527836SJohn.Forte@Sun.COM
30537836SJohn.Forte@Sun.COM /* copy rval */
30547836SJohn.Forte@Sun.COM rval = icmdp->cmd_result;
30557836SJohn.Forte@Sun.COM
30567836SJohn.Forte@Sun.COM ucmdp->uscsi_resid = pkt->pkt_resid;
30577836SJohn.Forte@Sun.COM
30587836SJohn.Forte@Sun.COM /* update scsi status */
30597836SJohn.Forte@Sun.COM arqstat = (struct scsi_arq_status *)pkt->pkt_scbp;
30607836SJohn.Forte@Sun.COM ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0];
30617836SJohn.Forte@Sun.COM
30627836SJohn.Forte@Sun.COM /* copy request sense buffers if caller gave space */
30637836SJohn.Forte@Sun.COM if ((ucmdp->uscsi_rqlen > 0) &&
30647836SJohn.Forte@Sun.COM (ucmdp->uscsi_rqbuf != NULL)) {
306511271SMilos.Muzik@Sun.COM ASSERT(ucmdp->uscsi_rqlen >= arqstat->sts_rqpkt_resid);
306611271SMilos.Muzik@Sun.COM ucmdp->uscsi_rqresid = arqstat->sts_rqpkt_resid;
306711271SMilos.Muzik@Sun.COM bcopy(&arqstat->sts_sensedata, ucmdp->uscsi_rqbuf,
306811271SMilos.Muzik@Sun.COM ucmdp->uscsi_rqlen - arqstat->sts_rqpkt_resid);
30697836SJohn.Forte@Sun.COM }
30707836SJohn.Forte@Sun.COM
3071*12161SJack.Meng@Sun.COM if ((ucmdp->uscsi_status == STATUS_CHECK) &&
3072*12161SJack.Meng@Sun.COM ((icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL)) == B_TRUE) {
3073*12161SJack.Meng@Sun.COM /*
3074*12161SJack.Meng@Sun.COM * Internal SCSI commands received status
3075*12161SJack.Meng@Sun.COM */
3076*12161SJack.Meng@Sun.COM (void) iscsi_decode_sense(
3077*12161SJack.Meng@Sun.COM (uint8_t *)&arqstat->sts_sensedata, icmdp);
3078*12161SJack.Meng@Sun.COM }
3079*12161SJack.Meng@Sun.COM
30807836SJohn.Forte@Sun.COM /* clean up */
30817836SJohn.Forte@Sun.COM iscsi_cmd_free(icmdp);
30827836SJohn.Forte@Sun.COM kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen);
308311271SMilos.Muzik@Sun.COM kmem_free(pkt->pkt_scbp, statuslen);
30847836SJohn.Forte@Sun.COM kmem_free(pkt, sizeof (struct scsi_pkt));
30857836SJohn.Forte@Sun.COM kmem_free(bp, sizeof (struct buf));
30867836SJohn.Forte@Sun.COM
30877836SJohn.Forte@Sun.COM return (rval);
30887836SJohn.Forte@Sun.COM }
30897836SJohn.Forte@Sun.COM
30907836SJohn.Forte@Sun.COM
30917836SJohn.Forte@Sun.COM /*
30927836SJohn.Forte@Sun.COM * iscsi_handle_passthru_callback -
30937836SJohn.Forte@Sun.COM *
30947836SJohn.Forte@Sun.COM */
30957836SJohn.Forte@Sun.COM static void
iscsi_handle_passthru_callback(struct scsi_pkt * pkt)30967836SJohn.Forte@Sun.COM iscsi_handle_passthru_callback(struct scsi_pkt *pkt)
30977836SJohn.Forte@Sun.COM {
30987836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp = NULL;
30997836SJohn.Forte@Sun.COM
31007836SJohn.Forte@Sun.COM ASSERT(pkt != NULL);
31017836SJohn.Forte@Sun.COM icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private;
31027836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
31037836SJohn.Forte@Sun.COM
31047836SJohn.Forte@Sun.COM mutex_enter(&icmdp->cmd_mutex);
31057836SJohn.Forte@Sun.COM icmdp->cmd_completed = B_TRUE;
31067836SJohn.Forte@Sun.COM icmdp->cmd_result = ISCSI_STATUS_SUCCESS;
31077836SJohn.Forte@Sun.COM cv_broadcast(&icmdp->cmd_completion);
31087836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
31097836SJohn.Forte@Sun.COM
31107836SJohn.Forte@Sun.COM }
31117836SJohn.Forte@Sun.COM
31127836SJohn.Forte@Sun.COM /*
31139162SPeter.Dunlap@Sun.COM * IDM callbacks
31149162SPeter.Dunlap@Sun.COM */
31159162SPeter.Dunlap@Sun.COM void
iscsi_build_hdr(idm_task_t * idm_task,idm_pdu_t * pdu,uint8_t opcode)31169162SPeter.Dunlap@Sun.COM iscsi_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode)
31179162SPeter.Dunlap@Sun.COM {
31189162SPeter.Dunlap@Sun.COM iscsi_cmd_t *icmdp = idm_task->idt_private;
31199162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = icmdp->cmd_conn;
31209162SPeter.Dunlap@Sun.COM iscsi_data_hdr_t *ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
31219162SPeter.Dunlap@Sun.COM
31229162SPeter.Dunlap@Sun.COM mutex_enter(&icmdp->cmd_mutex);
31239162SPeter.Dunlap@Sun.COM if (opcode == ISCSI_OP_SCSI_DATA) {
31249162SPeter.Dunlap@Sun.COM uint32_t data_sn;
31259162SPeter.Dunlap@Sun.COM uint32_t lun;
31269162SPeter.Dunlap@Sun.COM icmdp = idm_task->idt_private;
31279162SPeter.Dunlap@Sun.COM icp = icmdp->cmd_conn;
31289162SPeter.Dunlap@Sun.COM ihp->opcode = opcode;
31299162SPeter.Dunlap@Sun.COM ihp->itt = icmdp->cmd_itt;
31309162SPeter.Dunlap@Sun.COM ihp->ttt = idm_task->idt_r2t_ttt;
31319162SPeter.Dunlap@Sun.COM ihp->expstatsn = htonl(icp->conn_expstatsn);
31329162SPeter.Dunlap@Sun.COM icp->conn_laststatsn = icp->conn_expstatsn;
31339162SPeter.Dunlap@Sun.COM data_sn = ntohl(ihp->datasn);
31349162SPeter.Dunlap@Sun.COM data_sn++;
31359162SPeter.Dunlap@Sun.COM lun = icmdp->cmd_un.scsi.lun;
31369162SPeter.Dunlap@Sun.COM ISCSI_LUN_BYTE_COPY(ihp->lun, lun);
31379162SPeter.Dunlap@Sun.COM /* CRM: upate_flow_control */
31389162SPeter.Dunlap@Sun.COM ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_build_hdr"
31399162SPeter.Dunlap@Sun.COM "(ISCSI_OP_SCSI_DATA): task: %p icp: %p ic: %p itt: %x "
31409162SPeter.Dunlap@Sun.COM "exp: %d data_sn: %d", (void *)idm_task, (void *)icp,
31419162SPeter.Dunlap@Sun.COM (void *)icp->conn_ic, ihp->itt, icp->conn_expstatsn,
31429162SPeter.Dunlap@Sun.COM data_sn);
31439162SPeter.Dunlap@Sun.COM } else {
31449162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi_build_hdr: unprocessed build "
31459162SPeter.Dunlap@Sun.COM "header opcode: %x", opcode);
31469162SPeter.Dunlap@Sun.COM }
31479162SPeter.Dunlap@Sun.COM mutex_exit(&icmdp->cmd_mutex);
31489162SPeter.Dunlap@Sun.COM }
31499162SPeter.Dunlap@Sun.COM
31509162SPeter.Dunlap@Sun.COM static void
iscsi_process_rsp_status(iscsi_sess_t * isp,iscsi_conn_t * icp,idm_status_t status)31519162SPeter.Dunlap@Sun.COM iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp,
31529162SPeter.Dunlap@Sun.COM idm_status_t status)
31539162SPeter.Dunlap@Sun.COM {
31549162SPeter.Dunlap@Sun.COM switch (status) {
31559162SPeter.Dunlap@Sun.COM case IDM_STATUS_SUCCESS:
31569162SPeter.Dunlap@Sun.COM if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) &&
31579162SPeter.Dunlap@Sun.COM (icp->conn_queue_active.count == 0)) {
31589162SPeter.Dunlap@Sun.COM iscsi_drop_conn_cleanup(icp);
31599162SPeter.Dunlap@Sun.COM }
31609162SPeter.Dunlap@Sun.COM break;
31619162SPeter.Dunlap@Sun.COM case IDM_STATUS_PROTOCOL_ERROR:
31629162SPeter.Dunlap@Sun.COM KSTAT_INC_CONN_ERR_PROTOCOL(icp);
31639162SPeter.Dunlap@Sun.COM iscsi_drop_conn_cleanup(icp);
31649162SPeter.Dunlap@Sun.COM break;
31659162SPeter.Dunlap@Sun.COM default:
31669162SPeter.Dunlap@Sun.COM break;
31679162SPeter.Dunlap@Sun.COM }
31689162SPeter.Dunlap@Sun.COM }
31699162SPeter.Dunlap@Sun.COM
31709162SPeter.Dunlap@Sun.COM static void
iscsi_drop_conn_cleanup(iscsi_conn_t * icp)31719162SPeter.Dunlap@Sun.COM iscsi_drop_conn_cleanup(iscsi_conn_t *icp) {
31729162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_state_mutex);
31739162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(icp->conn_ic);
31749162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
31759162SPeter.Dunlap@Sun.COM }
31769162SPeter.Dunlap@Sun.COM
31779162SPeter.Dunlap@Sun.COM void
iscsi_rx_error_pdu(idm_conn_t * ic,idm_pdu_t * pdu,idm_status_t status)31789162SPeter.Dunlap@Sun.COM iscsi_rx_error_pdu(idm_conn_t *ic, idm_pdu_t *pdu, idm_status_t status)
31799162SPeter.Dunlap@Sun.COM {
31809162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp = (iscsi_conn_t *)ic->ic_handle;
31819162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp;
31829162SPeter.Dunlap@Sun.COM
31839162SPeter.Dunlap@Sun.COM ASSERT(icp != NULL);
31849162SPeter.Dunlap@Sun.COM isp = icp->conn_sess;
31859162SPeter.Dunlap@Sun.COM ASSERT(isp != NULL);
31869162SPeter.Dunlap@Sun.COM iscsi_process_rsp_status(isp, icp, status);
31879162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
31889162SPeter.Dunlap@Sun.COM }
31899162SPeter.Dunlap@Sun.COM
31909162SPeter.Dunlap@Sun.COM void
iscsi_rx_misc_pdu(idm_conn_t * ic,idm_pdu_t * pdu)31919162SPeter.Dunlap@Sun.COM iscsi_rx_misc_pdu(idm_conn_t *ic, idm_pdu_t *pdu)
31929162SPeter.Dunlap@Sun.COM {
31939162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp;
31949162SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr;
31959162SPeter.Dunlap@Sun.COM iscsi_sess_t *isp;
31969162SPeter.Dunlap@Sun.COM idm_status_t status;
31979162SPeter.Dunlap@Sun.COM
31989162SPeter.Dunlap@Sun.COM icp = ic->ic_handle;
31999162SPeter.Dunlap@Sun.COM isp = icp->conn_sess;
32009162SPeter.Dunlap@Sun.COM isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt();
32019162SPeter.Dunlap@Sun.COM switch (ihp->opcode & ISCSI_OPCODE_MASK) {
32029162SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP:
32039162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_login_pdu(ic, pdu);
32049162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
32059162SPeter.Dunlap@Sun.COM break;
32069162SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP:
32079162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_logout_rsp(ic, pdu);
32089162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
32099162SPeter.Dunlap@Sun.COM break;
32109162SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG:
32119162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_reject_rsp(ic, pdu);
32129162SPeter.Dunlap@Sun.COM break;
32139162SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP:
32149162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_task_mgt_rsp(ic, pdu);
32159162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
32169162SPeter.Dunlap@Sun.COM break;
32179162SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN:
32189162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_nop(ic, pdu);
32199162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
32209162SPeter.Dunlap@Sun.COM break;
32219162SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT:
32229162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_async_rsp(ic, pdu);
32239162SPeter.Dunlap@Sun.COM break;
32249162SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP:
32259162SPeter.Dunlap@Sun.COM status = iscsi_rx_process_text_rsp(ic, pdu);
32269162SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, status);
32279162SPeter.Dunlap@Sun.COM break;
32289162SPeter.Dunlap@Sun.COM default:
32299162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) protocol error "
32309162SPeter.Dunlap@Sun.COM "- received misc unsupported opcode 0x%02x",
32319162SPeter.Dunlap@Sun.COM icp->conn_oid, ihp->opcode);
32329162SPeter.Dunlap@Sun.COM status = IDM_STATUS_PROTOCOL_ERROR;
32339162SPeter.Dunlap@Sun.COM break;
32349162SPeter.Dunlap@Sun.COM }
32359162SPeter.Dunlap@Sun.COM iscsi_process_rsp_status(isp, icp, status);
32369162SPeter.Dunlap@Sun.COM }
32379162SPeter.Dunlap@Sun.COM
32389162SPeter.Dunlap@Sun.COM /*
32397836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
32407836SJohn.Forte@Sun.COM * | Beginning of completion routines |
32417836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
32427836SJohn.Forte@Sun.COM */
32437836SJohn.Forte@Sun.COM
32447836SJohn.Forte@Sun.COM /*
32457836SJohn.Forte@Sun.COM * iscsi_ic_thread -
32467836SJohn.Forte@Sun.COM */
32477836SJohn.Forte@Sun.COM void
iscsi_ic_thread(iscsi_thread_t * thread,void * arg)32487836SJohn.Forte@Sun.COM iscsi_ic_thread(iscsi_thread_t *thread, void *arg)
32497836SJohn.Forte@Sun.COM {
32507836SJohn.Forte@Sun.COM iscsi_sess_t *isp = (iscsi_sess_t *)arg;
32517836SJohn.Forte@Sun.COM int ret;
32527836SJohn.Forte@Sun.COM iscsi_queue_t q;
32537836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp;
32547836SJohn.Forte@Sun.COM iscsi_cmd_t *next_icmdp;
32557836SJohn.Forte@Sun.COM
32567836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
32577836SJohn.Forte@Sun.COM ASSERT(thread != NULL);
32587836SJohn.Forte@Sun.COM ASSERT(thread->signature == SIG_ISCSI_THREAD);
32597836SJohn.Forte@Sun.COM
32607836SJohn.Forte@Sun.COM for (;;) {
32617836SJohn.Forte@Sun.COM
32627836SJohn.Forte@Sun.COM /*
32637836SJohn.Forte@Sun.COM * We wait till iodone or somebody else wakes us up.
32647836SJohn.Forte@Sun.COM */
32657836SJohn.Forte@Sun.COM ret = iscsi_thread_wait(thread, -1);
32667836SJohn.Forte@Sun.COM
32677836SJohn.Forte@Sun.COM /*
32687836SJohn.Forte@Sun.COM * The value should never be negative since we never timeout.
32697836SJohn.Forte@Sun.COM */
32707836SJohn.Forte@Sun.COM ASSERT(ret >= 0);
32717836SJohn.Forte@Sun.COM
32727836SJohn.Forte@Sun.COM q.count = 0;
32737836SJohn.Forte@Sun.COM q.head = NULL;
32747836SJohn.Forte@Sun.COM q.tail = NULL;
32757836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_completion.mutex);
32767836SJohn.Forte@Sun.COM icmdp = isp->sess_queue_completion.head;
32777836SJohn.Forte@Sun.COM while (icmdp != NULL) {
32787836SJohn.Forte@Sun.COM next_icmdp = icmdp->cmd_next;
32797836SJohn.Forte@Sun.COM mutex_enter(&icmdp->cmd_mutex);
32807836SJohn.Forte@Sun.COM /*
32817836SJohn.Forte@Sun.COM * check if the associated r2t/abort has finished
32829162SPeter.Dunlap@Sun.COM * yet. If not, don't complete the command.
32837836SJohn.Forte@Sun.COM */
32847836SJohn.Forte@Sun.COM if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) &&
32859162SPeter.Dunlap@Sun.COM (icmdp->cmd_un.scsi.abort_icmdp == NULL)) {
32867836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
32877836SJohn.Forte@Sun.COM (void) iscsi_dequeue_cmd(&isp->
32887836SJohn.Forte@Sun.COM sess_queue_completion.head,
32897836SJohn.Forte@Sun.COM &isp->sess_queue_completion.tail,
32907836SJohn.Forte@Sun.COM icmdp);
32917836SJohn.Forte@Sun.COM --isp->sess_queue_completion.count;
32927836SJohn.Forte@Sun.COM iscsi_enqueue_cmd_head(&q.head,
32937836SJohn.Forte@Sun.COM &q.tail, icmdp);
32949162SPeter.Dunlap@Sun.COM } else {
32957836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
32969162SPeter.Dunlap@Sun.COM }
32977836SJohn.Forte@Sun.COM icmdp = next_icmdp;
32987836SJohn.Forte@Sun.COM }
32997836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_completion.mutex);
33007836SJohn.Forte@Sun.COM icmdp = q.head;
33017836SJohn.Forte@Sun.COM while (icmdp != NULL) {
33027836SJohn.Forte@Sun.COM next_icmdp = icmdp->cmd_next;
33037836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp);
33047836SJohn.Forte@Sun.COM icmdp = next_icmdp;
33057836SJohn.Forte@Sun.COM }
33067836SJohn.Forte@Sun.COM
33077836SJohn.Forte@Sun.COM if (ret > 0)
33087836SJohn.Forte@Sun.COM /* Somebody woke us up to work */
33097836SJohn.Forte@Sun.COM continue;
33107836SJohn.Forte@Sun.COM else
33117836SJohn.Forte@Sun.COM /*
33127836SJohn.Forte@Sun.COM * Somebody woke us up to kill ourselves. We will
33137836SJohn.Forte@Sun.COM * make sure, however that the completion queue is
33147836SJohn.Forte@Sun.COM * empty before leaving. After we've done that it
33157836SJohn.Forte@Sun.COM * is the originator of the signal that has to make
33167836SJohn.Forte@Sun.COM * sure no other SCSI command is posted.
33177836SJohn.Forte@Sun.COM */
33187836SJohn.Forte@Sun.COM break;
33197836SJohn.Forte@Sun.COM }
33207836SJohn.Forte@Sun.COM
33217836SJohn.Forte@Sun.COM }
33227836SJohn.Forte@Sun.COM
33237836SJohn.Forte@Sun.COM /*
33247836SJohn.Forte@Sun.COM * iscsi_iodone -
33257836SJohn.Forte@Sun.COM *
33267836SJohn.Forte@Sun.COM */
33277836SJohn.Forte@Sun.COM void
iscsi_iodone(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)33287836SJohn.Forte@Sun.COM iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
33297836SJohn.Forte@Sun.COM {
33307836SJohn.Forte@Sun.COM struct scsi_pkt *pkt = NULL;
33317836SJohn.Forte@Sun.COM struct buf *bp = icmdp->cmd_un.scsi.bp;
33327836SJohn.Forte@Sun.COM
33337836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
33347836SJohn.Forte@Sun.COM ASSERT(icmdp != NULL);
33357836SJohn.Forte@Sun.COM pkt = icmdp->cmd_un.scsi.pkt;
33367836SJohn.Forte@Sun.COM ASSERT(pkt != NULL);
33377836SJohn.Forte@Sun.COM
33387836SJohn.Forte@Sun.COM ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
33397836SJohn.Forte@Sun.COM ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
33407836SJohn.Forte@Sun.COM if (pkt->pkt_reason == CMD_CMPLT) {
33417836SJohn.Forte@Sun.COM if (bp) {
33427836SJohn.Forte@Sun.COM if (bp->b_flags & B_READ) {
33437836SJohn.Forte@Sun.COM KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount);
33447836SJohn.Forte@Sun.COM } else {
33457836SJohn.Forte@Sun.COM KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount);
33467836SJohn.Forte@Sun.COM }
33477836SJohn.Forte@Sun.COM }
33487836SJohn.Forte@Sun.COM }
33497836SJohn.Forte@Sun.COM
33507836SJohn.Forte@Sun.COM if (pkt->pkt_flags & FLAG_NOINTR) {
33517836SJohn.Forte@Sun.COM cv_broadcast(&icmdp->cmd_completion);
33527836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
33537836SJohn.Forte@Sun.COM } else {
33547836SJohn.Forte@Sun.COM /*
33557836SJohn.Forte@Sun.COM * Release mutex. As soon as callback is
33567836SJohn.Forte@Sun.COM * issued the caller may destroy the command.
33577836SJohn.Forte@Sun.COM */
33587836SJohn.Forte@Sun.COM mutex_exit(&icmdp->cmd_mutex);
33597836SJohn.Forte@Sun.COM /*
33607836SJohn.Forte@Sun.COM * We can't just directly call the pk_comp routine. In
33617836SJohn.Forte@Sun.COM * many error cases the target driver will use the calling
33627836SJohn.Forte@Sun.COM * thread to re-drive error handling (reset, retries...)
33637836SJohn.Forte@Sun.COM * back into the hba driver (iscsi). If the target redrives
33647836SJohn.Forte@Sun.COM * a reset back into the iscsi driver off this thead we have
33657836SJohn.Forte@Sun.COM * a chance of deadlocking. So instead use the io completion
33667836SJohn.Forte@Sun.COM * thread.
33677836SJohn.Forte@Sun.COM */
33687836SJohn.Forte@Sun.COM (*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt);
33697836SJohn.Forte@Sun.COM }
33707836SJohn.Forte@Sun.COM }
33717836SJohn.Forte@Sun.COM
33727836SJohn.Forte@Sun.COM /*
33737836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
33747836SJohn.Forte@Sun.COM * | End of completion routines |
33757836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
33767836SJohn.Forte@Sun.COM */
33777836SJohn.Forte@Sun.COM
33787836SJohn.Forte@Sun.COM /*
33797836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
33807836SJohn.Forte@Sun.COM * | Beginning of watchdog routines |
33817836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
33827836SJohn.Forte@Sun.COM */
33837836SJohn.Forte@Sun.COM
33847836SJohn.Forte@Sun.COM /*
33857836SJohn.Forte@Sun.COM * iscsi_watchdog_thread -
33867836SJohn.Forte@Sun.COM *
33877836SJohn.Forte@Sun.COM */
33887836SJohn.Forte@Sun.COM void
iscsi_wd_thread(iscsi_thread_t * thread,void * arg)33897836SJohn.Forte@Sun.COM iscsi_wd_thread(iscsi_thread_t *thread, void *arg)
33907836SJohn.Forte@Sun.COM {
33917836SJohn.Forte@Sun.COM iscsi_sess_t *isp = (iscsi_sess_t *)arg;
33927836SJohn.Forte@Sun.COM int rc = 1;
33937836SJohn.Forte@Sun.COM
33947836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
33957836SJohn.Forte@Sun.COM
33967836SJohn.Forte@Sun.COM while (rc != NULL) {
33977836SJohn.Forte@Sun.COM
33987836SJohn.Forte@Sun.COM iscsi_timeout_checks(isp);
33997836SJohn.Forte@Sun.COM iscsi_nop_checks(isp);
34007836SJohn.Forte@Sun.COM
34017836SJohn.Forte@Sun.COM rc = iscsi_thread_wait(thread, SEC_TO_TICK(1));
34027836SJohn.Forte@Sun.COM }
34037836SJohn.Forte@Sun.COM }
34047836SJohn.Forte@Sun.COM
34057836SJohn.Forte@Sun.COM /*
34067836SJohn.Forte@Sun.COM * iscsi_timeout_checks -
34077836SJohn.Forte@Sun.COM *
34087836SJohn.Forte@Sun.COM */
34097836SJohn.Forte@Sun.COM static void
iscsi_timeout_checks(iscsi_sess_t * isp)34107836SJohn.Forte@Sun.COM iscsi_timeout_checks(iscsi_sess_t *isp)
34117836SJohn.Forte@Sun.COM {
34127836SJohn.Forte@Sun.COM clock_t now = ddi_get_lbolt();
34139162SPeter.Dunlap@Sun.COM iscsi_conn_t *icp;
34147836SJohn.Forte@Sun.COM iscsi_cmd_t *icmdp, *nicmdp;
34157836SJohn.Forte@Sun.COM
34167836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
34177836SJohn.Forte@Sun.COM
34187836SJohn.Forte@Sun.COM /* PENDING */
3419*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
34207836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
34217836SJohn.Forte@Sun.COM for (icmdp = isp->sess_queue_pending.head;
34227836SJohn.Forte@Sun.COM icmdp; icmdp = nicmdp) {
34237836SJohn.Forte@Sun.COM nicmdp = icmdp->cmd_next;
34247836SJohn.Forte@Sun.COM
34257836SJohn.Forte@Sun.COM /* Skip entries with no timeout */
34267836SJohn.Forte@Sun.COM if (icmdp->cmd_lbolt_timeout == 0)
34277836SJohn.Forte@Sun.COM continue;
34287836SJohn.Forte@Sun.COM
34297836SJohn.Forte@Sun.COM /*
34307836SJohn.Forte@Sun.COM * Skip pending queue entries for cmd_type values that depend
34317836SJohn.Forte@Sun.COM * on having an open cmdsn window for successfull transition
34327836SJohn.Forte@Sun.COM * from pending to the active (i.e. ones that depend on
34337836SJohn.Forte@Sun.COM * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts
34347836SJohn.Forte@Sun.COM * when they are successfully moved to the active queue by
34357836SJohn.Forte@Sun.COM * iscsi_cmd_state_pending() code.
34367836SJohn.Forte@Sun.COM */
34378231SJack.Meng@Sun.COM /*
34388231SJack.Meng@Sun.COM * If the cmd is stuck, at least give it a chance
34398231SJack.Meng@Sun.COM * to timeout
34408231SJack.Meng@Sun.COM */
34418231SJack.Meng@Sun.COM if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) ||
34428231SJack.Meng@Sun.COM (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) &&
34438231SJack.Meng@Sun.COM !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK))
34447836SJohn.Forte@Sun.COM continue;
34457836SJohn.Forte@Sun.COM
34467836SJohn.Forte@Sun.COM /* Skip if timeout still in the future */
34477836SJohn.Forte@Sun.COM if (now <= icmdp->cmd_lbolt_timeout)
34487836SJohn.Forte@Sun.COM continue;
34497836SJohn.Forte@Sun.COM
34507836SJohn.Forte@Sun.COM /* timeout */
34517836SJohn.Forte@Sun.COM iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp);
34527836SJohn.Forte@Sun.COM }
34537836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
3454*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
34557836SJohn.Forte@Sun.COM
34567836SJohn.Forte@Sun.COM rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
34577836SJohn.Forte@Sun.COM icp = isp->sess_conn_list;
34587836SJohn.Forte@Sun.COM while (icp != NULL) {
34597836SJohn.Forte@Sun.COM
346010156SZhang.Yi@Sun.COM icp->conn_timeout = B_FALSE;
34617836SJohn.Forte@Sun.COM /* ACTIVE */
34627836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_state_mutex);
34637836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
34647836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_queue_active.mutex);
34657836SJohn.Forte@Sun.COM for (icmdp = icp->conn_queue_active.head;
34667836SJohn.Forte@Sun.COM icmdp; icmdp = nicmdp) {
34677836SJohn.Forte@Sun.COM nicmdp = icmdp->cmd_next;
34687836SJohn.Forte@Sun.COM
346910156SZhang.Yi@Sun.COM if (iscsi_nop_timeout_checks(icmdp) == B_TRUE) {
347010156SZhang.Yi@Sun.COM icp->conn_timeout = B_TRUE;
347110156SZhang.Yi@Sun.COM }
347210156SZhang.Yi@Sun.COM
34737836SJohn.Forte@Sun.COM /* Skip entries with no timeout */
34747836SJohn.Forte@Sun.COM if (icmdp->cmd_lbolt_timeout == 0)
34757836SJohn.Forte@Sun.COM continue;
34767836SJohn.Forte@Sun.COM
34779780SBing.Zhao@Sun.COM /*
34789780SBing.Zhao@Sun.COM * Skip if command is not active or not needed
34799780SBing.Zhao@Sun.COM * to flush.
34809780SBing.Zhao@Sun.COM */
34819780SBing.Zhao@Sun.COM if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE &&
34829780SBing.Zhao@Sun.COM !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH))
34837836SJohn.Forte@Sun.COM continue;
34847836SJohn.Forte@Sun.COM
34857836SJohn.Forte@Sun.COM /* Skip if timeout still in the future */
34867836SJohn.Forte@Sun.COM if (now <= icmdp->cmd_lbolt_timeout)
34877836SJohn.Forte@Sun.COM continue;
34887836SJohn.Forte@Sun.COM
34899780SBing.Zhao@Sun.COM if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH) {
34909780SBing.Zhao@Sun.COM /*
34919780SBing.Zhao@Sun.COM * This command is left during target reset,
34929780SBing.Zhao@Sun.COM * we can flush it now.
34939780SBing.Zhao@Sun.COM */
34949780SBing.Zhao@Sun.COM iscsi_cmd_state_machine(icmdp,
34959780SBing.Zhao@Sun.COM ISCSI_CMD_EVENT_E7, isp);
34969780SBing.Zhao@Sun.COM } else if (icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE) {
34979780SBing.Zhao@Sun.COM /* timeout */
34989780SBing.Zhao@Sun.COM iscsi_cmd_state_machine(icmdp,
34999780SBing.Zhao@Sun.COM ISCSI_CMD_EVENT_E6, isp);
35009780SBing.Zhao@Sun.COM }
35019780SBing.Zhao@Sun.COM
35027836SJohn.Forte@Sun.COM }
35037836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_queue_active.mutex);
35047836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
35057836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_state_mutex);
35067836SJohn.Forte@Sun.COM
35077836SJohn.Forte@Sun.COM icp = icp->conn_next;
35087836SJohn.Forte@Sun.COM }
350910156SZhang.Yi@Sun.COM
351010156SZhang.Yi@Sun.COM icp = isp->sess_conn_list;
351110156SZhang.Yi@Sun.COM while (icp != NULL) {
351210156SZhang.Yi@Sun.COM if (icp->conn_timeout == B_TRUE) {
351310156SZhang.Yi@Sun.COM /* timeout on this connect detected */
351410156SZhang.Yi@Sun.COM idm_ini_conn_disconnect(icp->conn_ic);
351510156SZhang.Yi@Sun.COM icp->conn_timeout = B_FALSE;
351610156SZhang.Yi@Sun.COM }
351710156SZhang.Yi@Sun.COM icp = icp->conn_next;
351810156SZhang.Yi@Sun.COM }
35197836SJohn.Forte@Sun.COM rw_exit(&isp->sess_conn_list_rwlock);
35207836SJohn.Forte@Sun.COM }
35217836SJohn.Forte@Sun.COM
35227836SJohn.Forte@Sun.COM /*
35237836SJohn.Forte@Sun.COM * iscsi_nop_checks - sends a NOP on idle connections
35247836SJohn.Forte@Sun.COM *
35257836SJohn.Forte@Sun.COM * This function walks the connections on a session and
35267836SJohn.Forte@Sun.COM * issues NOPs on those connections that are in FULL
35277836SJohn.Forte@Sun.COM * FEATURE mode and have not received data for the
35287836SJohn.Forte@Sun.COM * time period specified by iscsi_nop_delay (global).
35297836SJohn.Forte@Sun.COM */
35307836SJohn.Forte@Sun.COM static void
iscsi_nop_checks(iscsi_sess_t * isp)35317836SJohn.Forte@Sun.COM iscsi_nop_checks(iscsi_sess_t *isp)
35327836SJohn.Forte@Sun.COM {
35337836SJohn.Forte@Sun.COM iscsi_conn_t *icp;
35347836SJohn.Forte@Sun.COM
35357836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
35367836SJohn.Forte@Sun.COM
35377836SJohn.Forte@Sun.COM if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
35387836SJohn.Forte@Sun.COM return;
35397836SJohn.Forte@Sun.COM }
35407836SJohn.Forte@Sun.COM
35417836SJohn.Forte@Sun.COM rw_enter(&isp->sess_conn_list_rwlock, RW_READER);
35427836SJohn.Forte@Sun.COM icp = isp->sess_conn_act;
35437836SJohn.Forte@Sun.COM if (icp != NULL) {
35447836SJohn.Forte@Sun.COM
35457836SJohn.Forte@Sun.COM mutex_enter(&icp->conn_state_mutex);
35467836SJohn.Forte@Sun.COM if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) &&
35477836SJohn.Forte@Sun.COM (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt +
35487836SJohn.Forte@Sun.COM SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() >
35497836SJohn.Forte@Sun.COM isp->sess_conn_act->conn_nop_lbolt +
35507836SJohn.Forte@Sun.COM SEC_TO_TICK(iscsi_nop_delay))) {
35517836SJohn.Forte@Sun.COM
35527836SJohn.Forte@Sun.COM /*
35537836SJohn.Forte@Sun.COM * We haven't received anything from the
35547836SJohn.Forte@Sun.COM * target is a defined period of time,
35557836SJohn.Forte@Sun.COM * send NOP to see if the target is alive.
35567836SJohn.Forte@Sun.COM */
35577836SJohn.Forte@Sun.COM mutex_enter(&isp->sess_queue_pending.mutex);
35587836SJohn.Forte@Sun.COM iscsi_handle_nop(isp->sess_conn_act,
35597836SJohn.Forte@Sun.COM 0, ISCSI_RSVD_TASK_TAG);
35607836SJohn.Forte@Sun.COM mutex_exit(&isp->sess_queue_pending.mutex);
35617836SJohn.Forte@Sun.COM }
35627836SJohn.Forte@Sun.COM mutex_exit(&icp->conn_state_mutex);
35637836SJohn.Forte@Sun.COM
35647836SJohn.Forte@Sun.COM icp = icp->conn_next;
35657836SJohn.Forte@Sun.COM }
35667836SJohn.Forte@Sun.COM rw_exit(&isp->sess_conn_list_rwlock);
35677836SJohn.Forte@Sun.COM }
35687836SJohn.Forte@Sun.COM
356910156SZhang.Yi@Sun.COM static boolean_t
iscsi_nop_timeout_checks(iscsi_cmd_t * icmdp)357010156SZhang.Yi@Sun.COM iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp)
357110156SZhang.Yi@Sun.COM {
357210156SZhang.Yi@Sun.COM if (icmdp->cmd_type == ISCSI_CMD_TYPE_NOP) {
357310156SZhang.Yi@Sun.COM if ((ddi_get_lbolt() - icmdp->cmd_lbolt_active) >
357410156SZhang.Yi@Sun.COM SEC_TO_TICK(ISCSI_CONN_TIEMOUT_DETECT)) {
357510156SZhang.Yi@Sun.COM return (B_TRUE);
357610156SZhang.Yi@Sun.COM } else {
357710156SZhang.Yi@Sun.COM return (B_FALSE);
357810156SZhang.Yi@Sun.COM }
357910156SZhang.Yi@Sun.COM }
358010156SZhang.Yi@Sun.COM return (B_FALSE);
358110156SZhang.Yi@Sun.COM }
35827836SJohn.Forte@Sun.COM /*
35837836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
35847836SJohn.Forte@Sun.COM * | End of wd routines |
35857836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
35867836SJohn.Forte@Sun.COM */
35879780SBing.Zhao@Sun.COM
35889780SBing.Zhao@Sun.COM /*
35899780SBing.Zhao@Sun.COM * iscsi_flush_cmd_after_reset - flush commands after reset
35909780SBing.Zhao@Sun.COM *
359111272SMilos.Muzik@Sun.COM * Here we will flush all the commands for a specified LUN whose cmdsn is less
359211272SMilos.Muzik@Sun.COM * than the one received with the Unit Attention.
35939780SBing.Zhao@Sun.COM */
35949780SBing.Zhao@Sun.COM static void
iscsi_flush_cmd_after_reset(uint32_t cmd_sn,uint16_t lun_num,iscsi_conn_t * icp)35959780SBing.Zhao@Sun.COM iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num,
35969780SBing.Zhao@Sun.COM iscsi_conn_t *icp)
35979780SBing.Zhao@Sun.COM {
35989780SBing.Zhao@Sun.COM iscsi_cmd_t *t_icmdp = NULL;
35999780SBing.Zhao@Sun.COM iscsi_cmd_t *next_icmdp = NULL;
36009780SBing.Zhao@Sun.COM
36019780SBing.Zhao@Sun.COM ASSERT(icp != NULL);
36029780SBing.Zhao@Sun.COM
36039780SBing.Zhao@Sun.COM t_icmdp = icp->conn_queue_active.head;
36049780SBing.Zhao@Sun.COM while (t_icmdp != NULL) {
36059780SBing.Zhao@Sun.COM next_icmdp = t_icmdp->cmd_next;
36069780SBing.Zhao@Sun.COM mutex_enter(&t_icmdp->cmd_mutex);
36079780SBing.Zhao@Sun.COM /*
36089780SBing.Zhao@Sun.COM * We will flush the commands whose cmdsn is less than the one
36099780SBing.Zhao@Sun.COM * got Unit Attention.
36109780SBing.Zhao@Sun.COM * Here we will check for wrap by subtracting and compare to
36119780SBing.Zhao@Sun.COM * 1/2 of a 32 bit number, if greater then we wrapped.
36129780SBing.Zhao@Sun.COM */
36139780SBing.Zhao@Sun.COM if ((t_icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_SENT) &&
36149780SBing.Zhao@Sun.COM ((cmd_sn > t_icmdp->cmd_sn) ||
36159780SBing.Zhao@Sun.COM ((t_icmdp->cmd_sn - cmd_sn) >
36169780SBing.Zhao@Sun.COM ISCSI_CMD_SN_WRAP))) {
361711272SMilos.Muzik@Sun.COM /*
361811272SMilos.Muzik@Sun.COM * Internally generated SCSI commands do not have
361911272SMilos.Muzik@Sun.COM * t_icmdp->cmd_lun set, but the LUN can be retrieved
362011272SMilos.Muzik@Sun.COM * from t_icmdp->cmd_un.scsi.lun.
362111272SMilos.Muzik@Sun.COM */
362211272SMilos.Muzik@Sun.COM if ((t_icmdp->cmd_lun != NULL &&
362311272SMilos.Muzik@Sun.COM t_icmdp->cmd_lun->lun_num == lun_num) ||
362411272SMilos.Muzik@Sun.COM (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI &&
362511272SMilos.Muzik@Sun.COM (t_icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK) ==
362611272SMilos.Muzik@Sun.COM lun_num)) {
36279780SBing.Zhao@Sun.COM t_icmdp->cmd_misc_flags |=
36289780SBing.Zhao@Sun.COM ISCSI_CMD_MISCFLAG_FLUSH;
36299780SBing.Zhao@Sun.COM if (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
36309780SBing.Zhao@Sun.COM t_icmdp->cmd_un.scsi.pkt_stat |=
36319780SBing.Zhao@Sun.COM STAT_BUS_RESET;
36329780SBing.Zhao@Sun.COM }
36339780SBing.Zhao@Sun.COM }
36349780SBing.Zhao@Sun.COM }
36359780SBing.Zhao@Sun.COM mutex_exit(&t_icmdp->cmd_mutex);
36369780SBing.Zhao@Sun.COM t_icmdp = next_icmdp;
36379780SBing.Zhao@Sun.COM }
36389780SBing.Zhao@Sun.COM }
36399780SBing.Zhao@Sun.COM
36409780SBing.Zhao@Sun.COM /*
36419780SBing.Zhao@Sun.COM * iscsi_decode_sense - decode the sense data in the cmd response
3642*12161SJack.Meng@Sun.COM * and take proper actions
36439780SBing.Zhao@Sun.COM */
36449780SBing.Zhao@Sun.COM static boolean_t
iscsi_decode_sense(uint8_t * sense_data,iscsi_cmd_t * icmdp)3645*12161SJack.Meng@Sun.COM iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp)
36469780SBing.Zhao@Sun.COM {
3647*12161SJack.Meng@Sun.COM uint8_t sense_key = 0;
3648*12161SJack.Meng@Sun.COM uint8_t asc = 0;
3649*12161SJack.Meng@Sun.COM uint8_t ascq = 0;
3650*12161SJack.Meng@Sun.COM boolean_t flush_io = B_FALSE;
3651*12161SJack.Meng@Sun.COM boolean_t reconfig_lun = B_FALSE;
3652*12161SJack.Meng@Sun.COM iscsi_sess_t *isp = NULL;
36539780SBing.Zhao@Sun.COM
36549780SBing.Zhao@Sun.COM ASSERT(sense_data != NULL);
36559780SBing.Zhao@Sun.COM
3656*12161SJack.Meng@Sun.COM isp = icmdp->cmd_conn->conn_sess;
3657*12161SJack.Meng@Sun.COM
36589780SBing.Zhao@Sun.COM sense_key = scsi_sense_key(sense_data);
36599780SBing.Zhao@Sun.COM switch (sense_key) {
36609780SBing.Zhao@Sun.COM case KEY_UNIT_ATTENTION:
36619780SBing.Zhao@Sun.COM asc = scsi_sense_asc(sense_data);
36629780SBing.Zhao@Sun.COM switch (asc) {
36639780SBing.Zhao@Sun.COM case ISCSI_SCSI_RESET_SENSE_CODE:
36649780SBing.Zhao@Sun.COM /*
36659780SBing.Zhao@Sun.COM * POWER ON, RESET, OR BUS_DEVICE RESET
36669780SBing.Zhao@Sun.COM * OCCURRED
36679780SBing.Zhao@Sun.COM */
3668*12161SJack.Meng@Sun.COM flush_io = B_TRUE;
36699780SBing.Zhao@Sun.COM break;
3670*12161SJack.Meng@Sun.COM case ISCSI_SCSI_LUNCHANGED_CODE:
3671*12161SJack.Meng@Sun.COM ascq = scsi_sense_ascq(sense_data);
3672*12161SJack.Meng@Sun.COM if (ascq == ISCSI_SCSI_LUNCHANGED_ASCQ)
3673*12161SJack.Meng@Sun.COM reconfig_lun = B_TRUE;
36749780SBing.Zhao@Sun.COM default:
36759780SBing.Zhao@Sun.COM break;
36769780SBing.Zhao@Sun.COM }
36779780SBing.Zhao@Sun.COM break;
36789780SBing.Zhao@Sun.COM default:
36799780SBing.Zhao@Sun.COM /*
36809780SBing.Zhao@Sun.COM * Currently we don't care
36819780SBing.Zhao@Sun.COM * about other sense key.
36829780SBing.Zhao@Sun.COM */
36839780SBing.Zhao@Sun.COM break;
36849780SBing.Zhao@Sun.COM }
3685*12161SJack.Meng@Sun.COM
3686*12161SJack.Meng@Sun.COM if (reconfig_lun == B_TRUE) {
3687*12161SJack.Meng@Sun.COM rw_enter(&isp->sess_state_rwlock, RW_READER);
3688*12161SJack.Meng@Sun.COM if ((isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) &&
3689*12161SJack.Meng@Sun.COM (iscsi_sess_enum_request(isp, B_FALSE,
3690*12161SJack.Meng@Sun.COM isp->sess_state_event_count) !=
3691*12161SJack.Meng@Sun.COM ISCSI_SESS_ENUM_SUBMITTED)) {
3692*12161SJack.Meng@Sun.COM cmn_err(CE_WARN, "Unable to commit re-enumeration for"
3693*12161SJack.Meng@Sun.COM " session(%u) %s", isp->sess_oid, isp->sess_name);
3694*12161SJack.Meng@Sun.COM }
3695*12161SJack.Meng@Sun.COM rw_exit(&isp->sess_state_rwlock);
3696*12161SJack.Meng@Sun.COM }
3697*12161SJack.Meng@Sun.COM
3698*12161SJack.Meng@Sun.COM return (flush_io);
36999780SBing.Zhao@Sun.COM }
3700