1fcf3ce44SJohn Forte /* 2fcf3ce44SJohn Forte * CDDL HEADER START 3fcf3ce44SJohn Forte * 4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7fcf3ce44SJohn Forte * 8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11fcf3ce44SJohn Forte * and limitations under the License. 12fcf3ce44SJohn Forte * 13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18fcf3ce44SJohn Forte * 19fcf3ce44SJohn Forte * CDDL HEADER END 20fcf3ce44SJohn Forte */ 21fcf3ce44SJohn Forte /* 22fcf3ce44SJohn Forte * Copyright 2000 by Cisco Systems, Inc. All rights reserved. 23904e51f6SJack Meng * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24d72ea40eSDan McDonald * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25fcf3ce44SJohn Forte * 26fcf3ce44SJohn Forte * iSCSI Pseudo HBA Driver 27fcf3ce44SJohn Forte */ 28fcf3ce44SJohn Forte 29fcf3ce44SJohn Forte #include <sys/socket.h> /* networking stuff */ 30fcf3ce44SJohn Forte #include <sys/t_kuser.h> /* networking stuff */ 31fcf3ce44SJohn Forte #include <sys/tihdr.h> /* networking stuff */ 32fcf3ce44SJohn Forte #include <sys/strsubr.h> /* networking stuff */ 33fcf3ce44SJohn Forte #include <netinet/tcp.h> /* TCP_NODELAY */ 34fcf3ce44SJohn Forte #include <sys/socketvar.h> /* _ALLOC_SLEEP */ 35fcf3ce44SJohn Forte #include <sys/strsun.h> /* DB_TYPE() */ 362b79d384Sbing zhao - Sun Microsystems - Beijing China #include <sys/scsi/generic/sense.h> 37fcf3ce44SJohn Forte 38fcf3ce44SJohn Forte #include "iscsi.h" /* iscsi driver */ 391a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h> /* iscsi protocol */ 40fcf3ce44SJohn Forte 4130e7468fSPeter Dunlap #define ISCSI_INI_TASK_TTT 0xffffffff 42aff4bce5Syi zhang - Sun Microsystems - Beijing China #define ISCSI_CONN_TIEMOUT_DETECT 20 4330e7468fSPeter Dunlap 4430e7468fSPeter Dunlap boolean_t iscsi_io_logging = B_FALSE; 4530e7468fSPeter Dunlap 4630e7468fSPeter Dunlap #define ISCSI_CHECK_SCSI_READ(ICHK_CMD, ICHK_HDR, ICHK_LEN, ICHK_TYPE) \ 4730e7468fSPeter Dunlap if (idm_pattern_checking) { \ 4830e7468fSPeter Dunlap struct scsi_pkt *pkt = (ICHK_CMD)->cmd_un.scsi.pkt; \ 49*811eca55SToomas Soome if (((ICHK_HDR)->response == 0) && \ 5030e7468fSPeter Dunlap ((ICHK_HDR)->cmd_status == 0) && \ 5130e7468fSPeter Dunlap ((pkt->pkt_cdbp[0] == SCMD_READ_G1) || \ 52*811eca55SToomas Soome (pkt->pkt_cdbp[0] == SCMD_READ_G4) || \ 53*811eca55SToomas Soome (pkt->pkt_cdbp[0] == SCMD_READ) || \ 5430e7468fSPeter Dunlap (pkt->pkt_cdbp[0] == SCMD_READ_G5))) { \ 5530e7468fSPeter Dunlap idm_buf_t *idb = (ICHK_CMD)->cmd_un.scsi.ibp_ibuf; \ 5630e7468fSPeter Dunlap IDM_BUFPAT_CHECK(idb, ICHK_LEN, ICHK_TYPE); \ 5730e7468fSPeter Dunlap } \ 5830e7468fSPeter Dunlap } 5930e7468fSPeter Dunlap 60146832dbSMilos Muzik /* Size of structure scsi_arq_status without sense data. */ 61146832dbSMilos Muzik #define ISCSI_ARQ_STATUS_NOSENSE_LEN (sizeof (struct scsi_arq_status) - \ 62146832dbSMilos Muzik sizeof (struct scsi_extended_sense)) 63146832dbSMilos Muzik 64fcf3ce44SJohn Forte /* generic io helpers */ 65fcf3ce44SJohn Forte static uint32_t n2h24(uchar_t *ptr); 66fcf3ce44SJohn Forte static int iscsi_sna_lt(uint32_t n1, uint32_t n2); 6730e7468fSPeter Dunlap void iscsi_update_flow_control(iscsi_sess_t *isp, 68fcf3ce44SJohn Forte uint32_t max, uint32_t exp); 6930e7468fSPeter Dunlap static iscsi_status_t iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp, 7030e7468fSPeter Dunlap idm_conn_t *ic, iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp); 71fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, 72fcf3ce44SJohn Forte iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp); 7330e7468fSPeter Dunlap static void iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp, 7430e7468fSPeter Dunlap idm_status_t status); 7530e7468fSPeter Dunlap static void iscsi_drop_conn_cleanup(iscsi_conn_t *icp); 76aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp); 7730e7468fSPeter Dunlap /* callbacks from idm */ 7830e7468fSPeter Dunlap static idm_pdu_cb_t iscsi_tx_done; 7930e7468fSPeter Dunlap 8030e7468fSPeter Dunlap /* receivers */ 8130e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu); 8230e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_data_rsp(idm_conn_t *ic, 8330e7468fSPeter Dunlap idm_pdu_t *pdu); 8430e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu); 8530e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_reject_rsp(idm_conn_t *ic, 8630e7468fSPeter Dunlap idm_pdu_t *pdu); 8730e7468fSPeter Dunlap 8830e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic, 8930e7468fSPeter Dunlap iscsi_hdr_t *old_ihp); 9030e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic, 9130e7468fSPeter Dunlap idm_pdu_t *pdu); 9230e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_logout_rsp(idm_conn_t *ic, 9330e7468fSPeter Dunlap idm_pdu_t *pdu); 9430e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_async_rsp(idm_conn_t *ic, 9530e7468fSPeter Dunlap idm_pdu_t *pdu); 9630e7468fSPeter Dunlap static idm_status_t iscsi_rx_process_text_rsp(idm_conn_t *ic, 9730e7468fSPeter Dunlap idm_pdu_t *pdu); 98fcf3ce44SJohn Forte 99fcf3ce44SJohn Forte /* senders */ 100fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 101fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 102fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 103fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 104fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 105fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 106fcf3ce44SJohn Forte 107fcf3ce44SJohn Forte 108fcf3ce44SJohn Forte /* helpers */ 10930e7468fSPeter Dunlap static void iscsi_logout_start(void *arg); 110fcf3ce44SJohn Forte static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt); 111fcf3ce44SJohn Forte static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt); 112fcf3ce44SJohn Forte 113fcf3ce44SJohn Forte static void iscsi_timeout_checks(iscsi_sess_t *isp); 114fcf3ce44SJohn Forte static void iscsi_nop_checks(iscsi_sess_t *isp); 115904e51f6SJack Meng static boolean_t iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp); 1162b79d384Sbing zhao - Sun Microsystems - Beijing China static void iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num, 1172b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_conn_t *icp); 118fcf3ce44SJohn Forte 119fcf3ce44SJohn Forte /* 120fcf3ce44SJohn Forte * This file contains the main guts of the iSCSI protocol layer. 121fcf3ce44SJohn Forte * It's broken into 5 sections; Basic helper functions, RX IO path, 122fcf3ce44SJohn Forte * TX IO path, Completion (IC) IO path, and watchdog (WD) routines. 123fcf3ce44SJohn Forte * 124fcf3ce44SJohn Forte * The IO flow model is similiar to the below diagram. The 125fcf3ce44SJohn Forte * iscsi session, connection and command state machines are used 126fcf3ce44SJohn Forte * to drive IO through this flow diagram. Reference those files 127fcf3ce44SJohn Forte * to get a detailed description of their respective state models 128fcf3ce44SJohn Forte * prior to their xxx_state_machine_function(). 129fcf3ce44SJohn Forte * 130fcf3ce44SJohn Forte * tran_start() -> CMD_E1 TX_THREAD RX_THREAD 131fcf3ce44SJohn Forte * | T T 132fcf3ce44SJohn Forte * V T T 133fcf3ce44SJohn Forte * PENDING_Q --CMD_E2--> ACTIVE_Q - --CMD_E3--+ 134fcf3ce44SJohn Forte * T \ C T | 135fcf3ce44SJohn Forte * T \M T | 136fcf3ce44SJohn Forte * D T | 137fcf3ce44SJohn Forte * WD_THREAD TT|TT T | 138fcf3ce44SJohn Forte * /E T | 139fcf3ce44SJohn Forte * / 6 T | 140fcf3ce44SJohn Forte * ABORTING_Q<- --CMD_E3--+ 141fcf3ce44SJohn Forte * T | 142fcf3ce44SJohn Forte * T T | 143fcf3ce44SJohn Forte * T | 144fcf3ce44SJohn Forte * callback() <--CMD_E#-- COMPLETION_Q <------------+ 145fcf3ce44SJohn Forte * T 146fcf3ce44SJohn Forte * T 147fcf3ce44SJohn Forte * IC_THREAD 148fcf3ce44SJohn Forte * 149fcf3ce44SJohn Forte * External and internal command are ran thru this same state 150fcf3ce44SJohn Forte * machine. All commands enter the state machine by receiving an 151fcf3ce44SJohn Forte * ISCSI_CMD_EVENT_E1. This event places the command into the 152fcf3ce44SJohn Forte * PENDING_Q. Next when resources are available the TX_THREAD 153fcf3ce44SJohn Forte * issues a E2 event on the command. This sends the command 154fcf3ce44SJohn Forte * to the TCP stack and places the command on the ACTIVE_Q. While 155fcf3ce44SJohn Forte * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the 156fcf3ce44SJohn Forte * WD_THREAD to ensure the pkt_time has not elapsed. If elapsed the 157fcf3ce44SJohn Forte * command is issued an E6(timeout) event which moves either (if pending) 158fcf3ce44SJohn Forte * completed the command or (if active) moves the command to the 159fcf3ce44SJohn Forte * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command 160fcf3ce44SJohn Forte * to cancel the IO request. If the original command is completed 161fcf3ce44SJohn Forte * or the TASK MANAGEMENT command completes the command is moved 162fcf3ce44SJohn Forte * to the COMPLETION_Q via a E3 event. The IC_THREAD then processes 163fcf3ce44SJohn Forte * the COMPLETION_Q and issues the scsi_pkt callback. This 164fcf3ce44SJohn Forte * callback can not be processed directly from the RX_THREAD 165fcf3ce44SJohn Forte * because the callback might call back into the iscsi driver 166fcf3ce44SJohn Forte * causing a deadlock condition. 167fcf3ce44SJohn Forte * 168fcf3ce44SJohn Forte * For more details on the complete CMD state machine reference 169fcf3ce44SJohn Forte * the state machine diagram in iscsi_cmd.c. The connection state 170fcf3ce44SJohn Forte * machine is driven via IO events in this file. Then session 171fcf3ce44SJohn Forte * events are driven by the connection events. For complete 172fcf3ce44SJohn Forte * details on these state machines reference iscsi_sess.c and 173fcf3ce44SJohn Forte * iscsi_conn.c 174fcf3ce44SJohn Forte */ 175fcf3ce44SJohn Forte 176fcf3ce44SJohn Forte 177fcf3ce44SJohn Forte /* 178fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 179fcf3ce44SJohn Forte * | io helper routines | 180fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 181fcf3ce44SJohn Forte */ 182fcf3ce44SJohn Forte 183fcf3ce44SJohn Forte /* 184fcf3ce44SJohn Forte * n2h24 - native to host 24 bit integer translation. 185fcf3ce44SJohn Forte */ 186fcf3ce44SJohn Forte static uint32_t 187fcf3ce44SJohn Forte n2h24(uchar_t *ptr) 188fcf3ce44SJohn Forte { 189fcf3ce44SJohn Forte uint32_t idx; 190fcf3ce44SJohn Forte bcopy(ptr, &idx, 3); 191fcf3ce44SJohn Forte return (ntohl(idx) >> 8); 192fcf3ce44SJohn Forte } 193fcf3ce44SJohn Forte 194fcf3ce44SJohn Forte /* 195fcf3ce44SJohn Forte * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982 196fcf3ce44SJohn Forte */ 197fcf3ce44SJohn Forte static int 198fcf3ce44SJohn Forte iscsi_sna_lt(uint32_t n1, uint32_t n2) 199fcf3ce44SJohn Forte { 200fcf3ce44SJohn Forte return ((n1 != n2) && 201fcf3ce44SJohn Forte (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) || 202fcf3ce44SJohn Forte ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK)))); 203fcf3ce44SJohn Forte } 204fcf3ce44SJohn Forte 205fcf3ce44SJohn Forte /* 206fcf3ce44SJohn Forte * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal, 207fcf3ce44SJohn Forte * RFC1982 208fcf3ce44SJohn Forte */ 209fcf3ce44SJohn Forte int 210fcf3ce44SJohn Forte iscsi_sna_lte(uint32_t n1, uint32_t n2) 211fcf3ce44SJohn Forte { 212fcf3ce44SJohn Forte return ((n1 == n2) || 213fcf3ce44SJohn Forte (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) || 214fcf3ce44SJohn Forte ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK)))); 215fcf3ce44SJohn Forte } 216fcf3ce44SJohn Forte 217fcf3ce44SJohn Forte /* 218fcf3ce44SJohn Forte * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI 219fcf3ce44SJohn Forte * flow control information for a session 220fcf3ce44SJohn Forte */ 22130e7468fSPeter Dunlap void 222fcf3ce44SJohn Forte iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp) 223fcf3ce44SJohn Forte { 224fcf3ce44SJohn Forte ASSERT(isp != NULL); 225fcf3ce44SJohn Forte ASSERT(mutex_owned(&isp->sess_cmdsn_mutex)); 226fcf3ce44SJohn Forte 227fcf3ce44SJohn Forte if (!iscsi_sna_lt(max, (exp - 1))) { 228fcf3ce44SJohn Forte 229fcf3ce44SJohn Forte if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) { 230fcf3ce44SJohn Forte isp->sess_expcmdsn = exp; 231fcf3ce44SJohn Forte } 232fcf3ce44SJohn Forte 233fcf3ce44SJohn Forte if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) { 234fcf3ce44SJohn Forte isp->sess_maxcmdsn = max; 235fcf3ce44SJohn Forte if (iscsi_sna_lte(isp->sess_cmdsn, 236fcf3ce44SJohn Forte isp->sess_maxcmdsn)) { 237fcf3ce44SJohn Forte /* 238fcf3ce44SJohn Forte * the window is open again - schedule 239fcf3ce44SJohn Forte * to send any held tasks soon 240fcf3ce44SJohn Forte */ 241fcf3ce44SJohn Forte iscsi_sess_redrive_io(isp); 242fcf3ce44SJohn Forte } 243fcf3ce44SJohn Forte } 244fcf3ce44SJohn Forte } 245fcf3ce44SJohn Forte } 246fcf3ce44SJohn Forte 247fcf3ce44SJohn Forte 248fcf3ce44SJohn Forte /* 249fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 250fcf3ce44SJohn Forte * | io receive and processing routines | 251fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 252fcf3ce44SJohn Forte */ 253fcf3ce44SJohn Forte 254fcf3ce44SJohn Forte /* 25530e7468fSPeter Dunlap * iscsi_rx_scsi_rsp - called from idm 25630e7468fSPeter Dunlap * For each opcode type fan out the processing. 257fcf3ce44SJohn Forte */ 258fcf3ce44SJohn Forte void 25930e7468fSPeter Dunlap iscsi_rx_scsi_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 260fcf3ce44SJohn Forte { 26130e7468fSPeter Dunlap iscsi_conn_t *icp; 26230e7468fSPeter Dunlap iscsi_sess_t *isp; 26330e7468fSPeter Dunlap iscsi_hdr_t *ihp; 26430e7468fSPeter Dunlap idm_status_t status; 265fcf3ce44SJohn Forte 26630e7468fSPeter Dunlap ASSERT(ic != NULL); 26730e7468fSPeter Dunlap ASSERT(pdu != NULL); 26830e7468fSPeter Dunlap icp = ic->ic_handle; 269fcf3ce44SJohn Forte ASSERT(icp != NULL); 27030e7468fSPeter Dunlap ihp = (iscsi_hdr_t *)pdu->isp_hdr; 271fcf3ce44SJohn Forte ASSERT(ihp != NULL); 27230e7468fSPeter Dunlap isp = icp->conn_sess; 273fcf3ce44SJohn Forte ASSERT(isp != NULL); 274fcf3ce44SJohn Forte 27530e7468fSPeter Dunlap /* reset the session timer when we receive the response */ 27630e7468fSPeter Dunlap isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt(); 277fcf3ce44SJohn Forte 278fcf3ce44SJohn Forte /* fan out the hdr processing */ 279fcf3ce44SJohn Forte switch (ihp->opcode & ISCSI_OPCODE_MASK) { 280fcf3ce44SJohn Forte case ISCSI_OP_SCSI_DATA_RSP: 28130e7468fSPeter Dunlap status = iscsi_rx_process_data_rsp(ic, pdu); 282fcf3ce44SJohn Forte break; 283fcf3ce44SJohn Forte case ISCSI_OP_SCSI_RSP: 28430e7468fSPeter Dunlap status = iscsi_rx_process_cmd_rsp(ic, pdu); 28530e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 286fcf3ce44SJohn Forte break; 287fcf3ce44SJohn Forte default: 288fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 28930e7468fSPeter Dunlap "received pdu with unsupported opcode 0x%02x", 290fcf3ce44SJohn Forte icp->conn_oid, ihp->opcode); 29130e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 292fcf3ce44SJohn Forte } 29330e7468fSPeter Dunlap iscsi_process_rsp_status(isp, icp, status); 294fcf3ce44SJohn Forte } 295fcf3ce44SJohn Forte 29630e7468fSPeter Dunlap void 29730e7468fSPeter Dunlap iscsi_task_cleanup(int opcode, iscsi_cmd_t *icmdp) 298fcf3ce44SJohn Forte { 299*811eca55SToomas Soome struct buf *bp; 30030e7468fSPeter Dunlap idm_buf_t *ibp, *obp; 30130e7468fSPeter Dunlap idm_task_t *itp; 302fcf3ce44SJohn Forte 30330e7468fSPeter Dunlap itp = icmdp->cmd_itp; 30430e7468fSPeter Dunlap ASSERT(itp != NULL); 30530e7468fSPeter Dunlap ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) || 30630e7468fSPeter Dunlap (opcode == ISCSI_OP_SCSI_RSP)); 307fcf3ce44SJohn Forte 30830e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp; 30930e7468fSPeter Dunlap ibp = icmdp->cmd_un.scsi.ibp_ibuf; 31030e7468fSPeter Dunlap obp = icmdp->cmd_un.scsi.ibp_obuf; 31130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: task_cleanup: itp: %p opcode: %d " 31230e7468fSPeter Dunlap "icmdp: %p bp: %p ibp: %p", (void *)itp, opcode, 31330e7468fSPeter Dunlap (void *)icmdp, (void *)bp, (void *)ibp); 31430e7468fSPeter Dunlap if (bp && bp->b_bcount) { 31530e7468fSPeter Dunlap if (ibp != NULL && bp->b_flags & B_READ) { 31630e7468fSPeter Dunlap idm_buf_unbind_in(itp, ibp); 31730e7468fSPeter Dunlap idm_buf_free(ibp); 31830e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_ibuf = NULL; 31930e7468fSPeter Dunlap } else if (obp != NULL && !(bp->b_flags & B_READ)) { 32030e7468fSPeter Dunlap idm_buf_unbind_out(itp, obp); 32130e7468fSPeter Dunlap idm_buf_free(obp); 32230e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_obuf = NULL; 323fcf3ce44SJohn Forte } 324fcf3ce44SJohn Forte } 325fcf3ce44SJohn Forte 32630e7468fSPeter Dunlap idm_task_done(itp); 32730e7468fSPeter Dunlap } 32830e7468fSPeter Dunlap 32930e7468fSPeter Dunlap idm_status_t 33030e7468fSPeter Dunlap iscsi_rx_chk(iscsi_conn_t *icp, iscsi_sess_t *isp, 33130e7468fSPeter Dunlap iscsi_scsi_rsp_hdr_t *irhp, iscsi_cmd_t **icmdp) 33230e7468fSPeter Dunlap { 33330e7468fSPeter Dunlap iscsi_status_t rval; 33430e7468fSPeter Dunlap 335fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 33630e7468fSPeter Dunlap 33730e7468fSPeter Dunlap if (icp->conn_expstatsn == ntohl(irhp->statsn)) { 33830e7468fSPeter Dunlap icp->conn_expstatsn++; 33930e7468fSPeter Dunlap } else { 34030e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - " 34130e7468fSPeter Dunlap "received status out of order itt:0x%x statsn:0x%x " 34230e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, irhp->opcode, 34330e7468fSPeter Dunlap irhp->itt, ntohl(irhp->statsn), icp->conn_expstatsn); 344fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 34530e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 34630e7468fSPeter Dunlap } 34730e7468fSPeter Dunlap 34830e7468fSPeter Dunlap /* get icmdp so we can cleanup on error */ 34930e7468fSPeter Dunlap if ((irhp->opcode == ISCSI_OP_SCSI_DATA_RSP) || 35030e7468fSPeter Dunlap (irhp->opcode == ISCSI_OP_SCSI_RSP)) { 35130e7468fSPeter Dunlap rval = iscsi_rx_process_scsi_itt_to_icmdp(isp, icp->conn_ic, 35230e7468fSPeter Dunlap irhp, icmdp); 35330e7468fSPeter Dunlap } else { 35430e7468fSPeter Dunlap rval = iscsi_rx_process_itt_to_icmdp(isp, 35530e7468fSPeter Dunlap (iscsi_hdr_t *)irhp, icmdp); 35630e7468fSPeter Dunlap } 35730e7468fSPeter Dunlap 35830e7468fSPeter Dunlap if (!ISCSI_SUCCESS(rval)) { 35930e7468fSPeter Dunlap mutex_exit(&isp->sess_cmdsn_mutex); 36030e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 361fcf3ce44SJohn Forte } 362fcf3ce44SJohn Forte 363fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 36430e7468fSPeter Dunlap iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn), 36530e7468fSPeter Dunlap ntohl(irhp->expcmdsn)); 366fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 36730e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 36830e7468fSPeter Dunlap } 369fcf3ce44SJohn Forte 37030e7468fSPeter Dunlap static void 37130e7468fSPeter Dunlap iscsi_cmd_rsp_chk(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp) 37230e7468fSPeter Dunlap { 37330e7468fSPeter Dunlap struct scsi_pkt *pkt; 37430e7468fSPeter Dunlap size_t data_transferred; 375fcf3ce44SJohn Forte 37630e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 37730e7468fSPeter Dunlap pkt->pkt_resid = 0; 37830e7468fSPeter Dunlap data_transferred = icmdp->cmd_un.scsi.data_transferred; 37930e7468fSPeter Dunlap /* Check the residual count */ 38030e7468fSPeter Dunlap if ((icmdp->cmd_un.scsi.bp) && 38130e7468fSPeter Dunlap (data_transferred != icmdp->cmd_un.scsi.bp->b_bcount)) { 382fcf3ce44SJohn Forte /* 38330e7468fSPeter Dunlap * We didn't xfer the expected amount of data - 38430e7468fSPeter Dunlap * the residual_count in the header is only 38530e7468fSPeter Dunlap * valid if the underflow flag is set. 386fcf3ce44SJohn Forte */ 38730e7468fSPeter Dunlap if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) { 38830e7468fSPeter Dunlap pkt->pkt_resid = ntohl(issrhp->residual_count); 38930e7468fSPeter Dunlap } else { 39030e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.bp->b_bcount > 39130e7468fSPeter Dunlap data_transferred) { 39230e7468fSPeter Dunlap /* 39330e7468fSPeter Dunlap * Some data fell on the floor 39430e7468fSPeter Dunlap * somehow - probably a CRC error 39530e7468fSPeter Dunlap */ 39630e7468fSPeter Dunlap pkt->pkt_resid = 39730e7468fSPeter Dunlap icmdp->cmd_un.scsi.bp->b_bcount - 39830e7468fSPeter Dunlap data_transferred; 39930e7468fSPeter Dunlap } 400fcf3ce44SJohn Forte } 40130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 40230e7468fSPeter Dunlap "DEBUG: iscsi_rx_cmd_rsp_chk: itt: %u" 40330e7468fSPeter Dunlap "data_trans != b_count data_transferred: %lu " 40430e7468fSPeter Dunlap "b_count: %lu cmd_status: %d flags: %d resid: %lu", 40530e7468fSPeter Dunlap issrhp->itt, data_transferred, 40630e7468fSPeter Dunlap icmdp->cmd_un.scsi.bp->b_bcount, 40730e7468fSPeter Dunlap issrhp->cmd_status & STATUS_MASK, 40830e7468fSPeter Dunlap issrhp->flags, pkt->pkt_resid); 40930e7468fSPeter Dunlap } 41030e7468fSPeter Dunlap /* set flags that tell SCSA that the command is complete */ 41130e7468fSPeter Dunlap if (icmdp->cmd_crc_error_seen == B_FALSE) { 41230e7468fSPeter Dunlap /* Set successful completion */ 41330e7468fSPeter Dunlap pkt->pkt_reason = CMD_CMPLT; 41430e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.bp) { 41530e7468fSPeter Dunlap pkt->pkt_state |= (STATE_XFERRED_DATA | 41630e7468fSPeter Dunlap STATE_GOT_STATUS); 41730e7468fSPeter Dunlap } else { 41830e7468fSPeter Dunlap pkt->pkt_state |= STATE_GOT_STATUS; 41930e7468fSPeter Dunlap } 42030e7468fSPeter Dunlap } else { 421fcf3ce44SJohn Forte /* 42230e7468fSPeter Dunlap * Some of the data was found to have an incorrect 42330e7468fSPeter Dunlap * error at the protocol error. 424fcf3ce44SJohn Forte */ 42530e7468fSPeter Dunlap pkt->pkt_reason = CMD_PER_FAIL; 42630e7468fSPeter Dunlap pkt->pkt_statistics |= STAT_PERR; 42730e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.bp) { 42830e7468fSPeter Dunlap pkt->pkt_resid = 42930e7468fSPeter Dunlap icmdp->cmd_un.scsi.bp->b_bcount; 430fcf3ce44SJohn Forte } else { 43130e7468fSPeter Dunlap pkt->pkt_resid = 0; 432fcf3ce44SJohn Forte } 433fcf3ce44SJohn Forte } 43430e7468fSPeter Dunlap } 43530e7468fSPeter Dunlap 4362b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t 43730e7468fSPeter Dunlap iscsi_cmd_rsp_cmd_status(iscsi_cmd_t *icmdp, iscsi_scsi_rsp_hdr_t *issrhp, 43830e7468fSPeter Dunlap uint8_t *data) 43930e7468fSPeter Dunlap { 440146832dbSMilos Muzik int32_t dlength; 441146832dbSMilos Muzik struct scsi_arq_status *arqstat; 442146832dbSMilos Muzik size_t senselen; 443146832dbSMilos Muzik int32_t statuslen; 444146832dbSMilos Muzik int32_t sensebuf_len; 44530e7468fSPeter Dunlap struct scsi_pkt *pkt; 446146832dbSMilos Muzik boolean_t affect = B_FALSE; 447146832dbSMilos Muzik int32_t senselen_to_copy; 44830e7468fSPeter Dunlap 44930e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 45030e7468fSPeter Dunlap dlength = n2h24(issrhp->dlength); 451fcf3ce44SJohn Forte 452fcf3ce44SJohn Forte /* 45330e7468fSPeter Dunlap * Process iSCSI Cmd Response Status 45430e7468fSPeter Dunlap * RFC 3720 Sectionn 10.4.2. 455fcf3ce44SJohn Forte */ 45630e7468fSPeter Dunlap switch (issrhp->cmd_status & STATUS_MASK) { 45730e7468fSPeter Dunlap case STATUS_GOOD: 45830e7468fSPeter Dunlap /* pass SCSI status up stack */ 45930e7468fSPeter Dunlap if (pkt->pkt_scbp) { 46030e7468fSPeter Dunlap pkt->pkt_scbp[0] = issrhp->cmd_status; 46130e7468fSPeter Dunlap } 46230e7468fSPeter Dunlap break; 46330e7468fSPeter Dunlap case STATUS_CHECK: 46430e7468fSPeter Dunlap /* 46530e7468fSPeter Dunlap * Verify we received a sense buffer and 46630e7468fSPeter Dunlap * that there is the correct amount of 46730e7468fSPeter Dunlap * request sense space to copy it to. 46830e7468fSPeter Dunlap */ 46930e7468fSPeter Dunlap if ((dlength > 1) && 47030e7468fSPeter Dunlap (pkt->pkt_scbp != NULL) && 47130e7468fSPeter Dunlap (icmdp->cmd_un.scsi.statuslen >= 47230e7468fSPeter Dunlap sizeof (struct scsi_arq_status))) { 473fcf3ce44SJohn Forte /* 47430e7468fSPeter Dunlap * If a bad command status is received we 47530e7468fSPeter Dunlap * need to reset the pkt_resid to zero. 47630e7468fSPeter Dunlap * The target driver compares its value 47730e7468fSPeter Dunlap * before checking other error flags. 47830e7468fSPeter Dunlap * (ex. check conditions) 479fcf3ce44SJohn Forte */ 48030e7468fSPeter Dunlap pkt->pkt_resid = 0; 48130e7468fSPeter Dunlap 48230e7468fSPeter Dunlap /* get sense length from first 2 bytes */ 48330e7468fSPeter Dunlap senselen = ((data[0] << 8) | data[1]) & 48430e7468fSPeter Dunlap (size_t)0xFFFF; 48530e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 48630e7468fSPeter Dunlap "DEBUG: iscsi_rx_cmd_rsp_cmd_status status_check: " 48730e7468fSPeter Dunlap "dlen: %d scbp: %p statuslen: %d arq: %d senselen:" 48830e7468fSPeter Dunlap " %lu", dlength, (void *)pkt->pkt_scbp, 48930e7468fSPeter Dunlap icmdp->cmd_un.scsi.statuslen, 49030e7468fSPeter Dunlap (int)sizeof (struct scsi_arq_status), 49130e7468fSPeter Dunlap senselen); 49230e7468fSPeter Dunlap 49330e7468fSPeter Dunlap /* Sanity-check on the sense length */ 49430e7468fSPeter Dunlap if ((senselen + 2) > dlength) { 49530e7468fSPeter Dunlap senselen = dlength - 2; 496fcf3ce44SJohn Forte } 497fcf3ce44SJohn Forte 49830e7468fSPeter Dunlap /* 49930e7468fSPeter Dunlap * If there was a Data Digest error then 50030e7468fSPeter Dunlap * the sense data cannot be trusted. 50130e7468fSPeter Dunlap */ 50230e7468fSPeter Dunlap if (icmdp->cmd_crc_error_seen) { 50330e7468fSPeter Dunlap senselen = 0; 50430e7468fSPeter Dunlap } 505fcf3ce44SJohn Forte 50630e7468fSPeter Dunlap /* automatic request sense */ 50730e7468fSPeter Dunlap arqstat = 50830e7468fSPeter Dunlap (struct scsi_arq_status *)pkt->pkt_scbp; 50930e7468fSPeter Dunlap 51030e7468fSPeter Dunlap /* pass SCSI status up stack */ 51130e7468fSPeter Dunlap *((uchar_t *)&arqstat->sts_status) = 51230e7468fSPeter Dunlap issrhp->cmd_status; 513fcf3ce44SJohn Forte 514fcf3ce44SJohn Forte /* 51530e7468fSPeter Dunlap * Set the status for the automatic 51630e7468fSPeter Dunlap * request sense command 517fcf3ce44SJohn Forte */ 51830e7468fSPeter Dunlap arqstat->sts_rqpkt_state = (STATE_GOT_BUS | 51930e7468fSPeter Dunlap STATE_GOT_TARGET | STATE_SENT_CMD | 52030e7468fSPeter Dunlap STATE_XFERRED_DATA | STATE_GOT_STATUS | 52130e7468fSPeter Dunlap STATE_ARQ_DONE); 522fcf3ce44SJohn Forte 52330e7468fSPeter Dunlap *((uchar_t *)&arqstat->sts_rqpkt_status) = 52430e7468fSPeter Dunlap STATUS_GOOD; 525fcf3ce44SJohn Forte 52630e7468fSPeter Dunlap arqstat->sts_rqpkt_reason = CMD_CMPLT; 52730e7468fSPeter Dunlap statuslen = icmdp->cmd_un.scsi.statuslen; 528fcf3ce44SJohn Forte 52930e7468fSPeter Dunlap if (senselen == 0) { 53030e7468fSPeter Dunlap /* auto request sense failed */ 53130e7468fSPeter Dunlap arqstat->sts_rqpkt_status.sts_chk = 1; 53230e7468fSPeter Dunlap arqstat->sts_rqpkt_resid = statuslen; 53330e7468fSPeter Dunlap } else if (senselen < statuslen) { 53430e7468fSPeter Dunlap /* auto request sense short */ 53530e7468fSPeter Dunlap arqstat->sts_rqpkt_resid = statuslen - senselen; 53630e7468fSPeter Dunlap } else { 53730e7468fSPeter Dunlap /* auto request sense complete */ 53830e7468fSPeter Dunlap arqstat->sts_rqpkt_resid = 0; 53930e7468fSPeter Dunlap } 54030e7468fSPeter Dunlap arqstat->sts_rqpkt_statistics = 0; 54130e7468fSPeter Dunlap pkt->pkt_state |= STATE_ARQ_DONE; 542fcf3ce44SJohn Forte 54330e7468fSPeter Dunlap if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_XARQ) { 54430e7468fSPeter Dunlap pkt->pkt_state |= STATE_XARQ_DONE; 54530e7468fSPeter Dunlap } 54630e7468fSPeter Dunlap 547146832dbSMilos Muzik /* 548146832dbSMilos Muzik * Calculate size of space reserved for sense data in 549146832dbSMilos Muzik * pkt->pkt_scbp. 550146832dbSMilos Muzik */ 551146832dbSMilos Muzik sensebuf_len = statuslen - ISCSI_ARQ_STATUS_NOSENSE_LEN; 5525279807dSJack Meng 55330e7468fSPeter Dunlap /* copy auto request sense */ 554146832dbSMilos Muzik senselen_to_copy = min(senselen, sensebuf_len); 555146832dbSMilos Muzik if (senselen_to_copy > 0) { 55630e7468fSPeter Dunlap bcopy(&data[2], (uchar_t *)&arqstat-> 557146832dbSMilos Muzik sts_sensedata, senselen_to_copy); 5582b79d384Sbing zhao - Sun Microsystems - Beijing China 5592b79d384Sbing zhao - Sun Microsystems - Beijing China affect = iscsi_decode_sense( 560904e51f6SJack Meng (uint8_t *)&arqstat->sts_sensedata, icmdp); 56130e7468fSPeter Dunlap } 562146832dbSMilos Muzik arqstat->sts_rqpkt_resid = sensebuf_len - 563146832dbSMilos Muzik senselen_to_copy; 564146832dbSMilos Muzik ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_cmd_rsp_cmd_status:" 565146832dbSMilos Muzik " sts_rqpkt_resid: %d pkt_scblen: %d senselen: %lu" 566146832dbSMilos Muzik " sensebuf_len: %d senselen_to_copy: %d affect: %d", 567146832dbSMilos Muzik arqstat->sts_rqpkt_resid, pkt->pkt_scblen, senselen, 568146832dbSMilos Muzik sensebuf_len, senselen_to_copy, affect); 56930e7468fSPeter Dunlap break; 570fcf3ce44SJohn Forte } 57130e7468fSPeter Dunlap /* FALLTHRU */ 57230e7468fSPeter Dunlap case STATUS_BUSY: 57330e7468fSPeter Dunlap case STATUS_RESERVATION_CONFLICT: 57430e7468fSPeter Dunlap case STATUS_QFULL: 57530e7468fSPeter Dunlap case STATUS_ACA_ACTIVE: 57630e7468fSPeter Dunlap default: 57730e7468fSPeter Dunlap /* 57830e7468fSPeter Dunlap * If a bad command status is received we need to 57930e7468fSPeter Dunlap * reset the pkt_resid to zero. The target driver 58030e7468fSPeter Dunlap * compares its value before checking other error 58130e7468fSPeter Dunlap * flags. (ex. check conditions) 58230e7468fSPeter Dunlap */ 58330e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 58430e7468fSPeter Dunlap "DEBUG: iscsi_rx_cmd_rsp_cmd_status: status: " 58530e7468fSPeter Dunlap "%d cmd_status: %d dlen: %u scbp: %p statuslen: %d " 58630e7468fSPeter Dunlap "arg_len: %d", issrhp->cmd_status & STATUS_MASK, 58730e7468fSPeter Dunlap issrhp->cmd_status, dlength, (void *)pkt->pkt_scbp, 58830e7468fSPeter Dunlap icmdp->cmd_un.scsi.statuslen, 58930e7468fSPeter Dunlap (int)sizeof (struct scsi_arq_status)); 59030e7468fSPeter Dunlap pkt->pkt_resid = 0; 59130e7468fSPeter Dunlap /* pass SCSI status up stack */ 59230e7468fSPeter Dunlap if (pkt->pkt_scbp) { 59330e7468fSPeter Dunlap pkt->pkt_scbp[0] = issrhp->cmd_status; 59430e7468fSPeter Dunlap } 59530e7468fSPeter Dunlap } 5962b79d384Sbing zhao - Sun Microsystems - Beijing China 5972b79d384Sbing zhao - Sun Microsystems - Beijing China return (affect); 59830e7468fSPeter Dunlap } 599fcf3ce44SJohn Forte 60030e7468fSPeter Dunlap /* 60130e7468fSPeter Dunlap * iscsi_rx_process_login_pdup - Process login response PDU. This function 60230e7468fSPeter Dunlap * copies the data into the connection context so that the login code can 60330e7468fSPeter Dunlap * interpret it. 60430e7468fSPeter Dunlap */ 60530e7468fSPeter Dunlap 60630e7468fSPeter Dunlap idm_status_t 60730e7468fSPeter Dunlap iscsi_rx_process_login_pdu(idm_conn_t *ic, idm_pdu_t *pdu) 60830e7468fSPeter Dunlap { 609*811eca55SToomas Soome iscsi_conn_t *icp; 61030e7468fSPeter Dunlap 61130e7468fSPeter Dunlap icp = ic->ic_handle; 61230e7468fSPeter Dunlap 61330e7468fSPeter Dunlap /* 61430e7468fSPeter Dunlap * Copy header and data into connection structure so iscsi_login() 61530e7468fSPeter Dunlap * can process it. 61630e7468fSPeter Dunlap */ 61730e7468fSPeter Dunlap mutex_enter(&icp->conn_login_mutex); 61830e7468fSPeter Dunlap /* 61930e7468fSPeter Dunlap * If conn_login_state != LOGIN_TX then we are not ready to handle 62030e7468fSPeter Dunlap * this login response and we should just drop it. 62130e7468fSPeter Dunlap */ 62230e7468fSPeter Dunlap if (icp->conn_login_state == LOGIN_TX) { 62330e7468fSPeter Dunlap icp->conn_login_datalen = pdu->isp_datalen; 62430e7468fSPeter Dunlap bcopy(pdu->isp_hdr, &icp->conn_login_resp_hdr, 62530e7468fSPeter Dunlap sizeof (iscsi_hdr_t)); 62630e7468fSPeter Dunlap /* 62730e7468fSPeter Dunlap * Login code is sloppy with it's NULL handling so make sure 62830e7468fSPeter Dunlap * we don't leave any stale data in there. 62930e7468fSPeter Dunlap */ 63030e7468fSPeter Dunlap bzero(icp->conn_login_data, icp->conn_login_max_data_length); 63130e7468fSPeter Dunlap bcopy(pdu->isp_data, icp->conn_login_data, 63230e7468fSPeter Dunlap MIN(pdu->isp_datalen, icp->conn_login_max_data_length)); 63330e7468fSPeter Dunlap iscsi_login_update_state_locked(icp, LOGIN_RX); 634fcf3ce44SJohn Forte } 63530e7468fSPeter Dunlap mutex_exit(&icp->conn_login_mutex); 636fcf3ce44SJohn Forte 63730e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 638fcf3ce44SJohn Forte } 639fcf3ce44SJohn Forte 640fcf3ce44SJohn Forte /* 641fcf3ce44SJohn Forte * iscsi_rx_process_cmd_rsp - Process received scsi command response. This 642fcf3ce44SJohn Forte * will contain sense data if the command was not successful. This data needs 643fcf3ce44SJohn Forte * to be copied into the scsi_pkt. Otherwise we just complete the IO. 644fcf3ce44SJohn Forte */ 64530e7468fSPeter Dunlap static idm_status_t 64630e7468fSPeter Dunlap iscsi_rx_process_cmd_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 647fcf3ce44SJohn Forte { 64830e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 64930e7468fSPeter Dunlap iscsi_sess_t *isp = icp->conn_sess; 65030e7468fSPeter Dunlap iscsi_scsi_rsp_hdr_t *issrhp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr; 65130e7468fSPeter Dunlap uint8_t *data = pdu->isp_data; 65230e7468fSPeter Dunlap iscsi_cmd_t *icmdp = NULL; 65330e7468fSPeter Dunlap struct scsi_pkt *pkt = NULL; 65430e7468fSPeter Dunlap idm_status_t rval; 65530e7468fSPeter Dunlap struct buf *bp; 6562b79d384Sbing zhao - Sun Microsystems - Beijing China boolean_t flush = B_FALSE; 6572b79d384Sbing zhao - Sun Microsystems - Beijing China uint32_t cmd_sn = 0; 6582b79d384Sbing zhao - Sun Microsystems - Beijing China uint16_t lun_num = 0; 659fcf3ce44SJohn Forte 660fcf3ce44SJohn Forte /* make sure we get status in order */ 66130e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex); 66230e7468fSPeter Dunlap 66330e7468fSPeter Dunlap if ((rval = iscsi_rx_chk(icp, isp, issrhp, 66430e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) { 66530e7468fSPeter Dunlap if (icmdp != NULL) { 66630e7468fSPeter Dunlap iscsi_task_cleanup(issrhp->opcode, icmdp); 66730e7468fSPeter Dunlap } 66830e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 66930e7468fSPeter Dunlap return (rval); 670fcf3ce44SJohn Forte } 671fcf3ce44SJohn Forte 67230e7468fSPeter Dunlap /* 67330e7468fSPeter Dunlap * If we are in "idm aborting" state then we shouldn't continue 67430e7468fSPeter Dunlap * to process this command. By definition this command is no longer 67530e7468fSPeter Dunlap * on the active queue so we shouldn't try to remove it either. 67630e7468fSPeter Dunlap */ 67730e7468fSPeter Dunlap mutex_enter(&icmdp->cmd_mutex); 67830e7468fSPeter Dunlap if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) { 67930e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex); 680fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 68130e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 682fcf3ce44SJohn Forte } 68330e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex); 684fcf3ce44SJohn Forte 68530e7468fSPeter Dunlap /* Get the IDM buffer and bytes transferred */ 68630e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp; 68730e7468fSPeter Dunlap if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) { 68830e7468fSPeter Dunlap /* Transport tracks bytes transferred so use those counts */ 68930e7468fSPeter Dunlap if (bp && (bp->b_flags & B_READ)) { 69030e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred += 69130e7468fSPeter Dunlap icmdp->cmd_itp->idt_rx_bytes; 69230e7468fSPeter Dunlap } else { 69330e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred += 69430e7468fSPeter Dunlap icmdp->cmd_itp->idt_tx_bytes; 69530e7468fSPeter Dunlap } 69630e7468fSPeter Dunlap } else { 69730e7468fSPeter Dunlap /* 69830e7468fSPeter Dunlap * Some transports cannot track the bytes transferred on 69930e7468fSPeter Dunlap * the initiator side (like iSER) so we have to use the 70030e7468fSPeter Dunlap * status info. If the response field indicates that 70130e7468fSPeter Dunlap * the command actually completed then we will assume 70230e7468fSPeter Dunlap * the data_transferred value represents the entire buffer 70330e7468fSPeter Dunlap * unless the resid field says otherwise. This is a bit 70430e7468fSPeter Dunlap * unintuitive but it's really impossible to know what 70530e7468fSPeter Dunlap * has been transferred without detailed consideration 70630e7468fSPeter Dunlap * of the SCSI status and sense key and that is outside 70730e7468fSPeter Dunlap * the scope of the transport. Instead the target/class driver 70830e7468fSPeter Dunlap * can consider these values along with the resid and figure 70930e7468fSPeter Dunlap * it out. The data_transferred concept is just belt and 71030e7468fSPeter Dunlap * suspenders anyway -- RFC 3720 actually explicitly rejects 71130e7468fSPeter Dunlap * scoreboarding ("Initiators SHOULD NOT keep track of the 71230e7468fSPeter Dunlap * data transferred to or from the target (scoreboarding)") 71330e7468fSPeter Dunlap * perhaps for this very reason. 71430e7468fSPeter Dunlap */ 71530e7468fSPeter Dunlap if (issrhp->response != 0) { 71630e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = 0; 71730e7468fSPeter Dunlap } else { 71830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = 71930e7468fSPeter Dunlap (bp == NULL) ? 0 : bp->b_bcount; 72030e7468fSPeter Dunlap if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) { 72130e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred -= 72230e7468fSPeter Dunlap ntohl(issrhp->residual_count); 72330e7468fSPeter Dunlap } 72430e7468fSPeter Dunlap } 72530e7468fSPeter Dunlap } 726fcf3ce44SJohn Forte 72730e7468fSPeter Dunlap ISCSI_CHECK_SCSI_READ(icmdp, issrhp, 72830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred, 72930e7468fSPeter Dunlap BP_CHECK_THOROUGH); 73030e7468fSPeter Dunlap 73130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu: %p itt:" 73230e7468fSPeter Dunlap " %x expcmdsn: %x sess_cmd: %x sess_expcmdsn: %x data_transfered:" 73330e7468fSPeter Dunlap " %lu ibp: %p obp: %p", (void *)ic, (void *)pdu, issrhp->itt, 73430e7468fSPeter Dunlap issrhp->expcmdsn, isp->sess_cmdsn, isp->sess_expcmdsn, 73530e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred, 73630e7468fSPeter Dunlap (void *)icmdp->cmd_un.scsi.ibp_ibuf, 73730e7468fSPeter Dunlap (void *)icmdp->cmd_un.scsi.ibp_obuf); 73830e7468fSPeter Dunlap 73930e7468fSPeter Dunlap iscsi_task_cleanup(issrhp->opcode, icmdp); 740fcf3ce44SJohn Forte 741fcf3ce44SJohn Forte if (issrhp->response) { 742fcf3ce44SJohn Forte /* The target failed the command. */ 74330e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_cmd_rsp: ic: %p pdu:" 74430e7468fSPeter Dunlap " %p response: %d bcount: %lu", (void *)ic, (void *)pdu, 74530e7468fSPeter Dunlap issrhp->response, icmdp->cmd_un.scsi.bp->b_bcount); 74630e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 747fcf3ce44SJohn Forte pkt->pkt_reason = CMD_TRAN_ERR; 748fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp) { 749fcf3ce44SJohn Forte pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount; 750fcf3ce44SJohn Forte } else { 751fcf3ce44SJohn Forte pkt->pkt_resid = 0; 752fcf3ce44SJohn Forte } 753fcf3ce44SJohn Forte } else { 754fcf3ce44SJohn Forte /* success */ 75530e7468fSPeter Dunlap iscsi_cmd_rsp_chk(icmdp, issrhp); 7562b79d384Sbing zhao - Sun Microsystems - Beijing China flush = iscsi_cmd_rsp_cmd_status(icmdp, issrhp, data); 757b97c1f92SMilos Muzik 758b97c1f92SMilos Muzik ASSERT(icmdp->cmd_lun == NULL || icmdp->cmd_lun->lun_num == 759b97c1f92SMilos Muzik (icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK)); 760b97c1f92SMilos Muzik 7612b79d384Sbing zhao - Sun Microsystems - Beijing China if (flush == B_TRUE) { 7622b79d384Sbing zhao - Sun Microsystems - Beijing China cmd_sn = icmdp->cmd_sn; 763b97c1f92SMilos Muzik lun_num = icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK; 7642b79d384Sbing zhao - Sun Microsystems - Beijing China } 76530e7468fSPeter Dunlap } 766fcf3ce44SJohn Forte 76730e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 7682b79d384Sbing zhao - Sun Microsystems - Beijing China if (flush == B_TRUE) { 7692b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_flush_cmd_after_reset(cmd_sn, lun_num, icp); 7702b79d384Sbing zhao - Sun Microsystems - Beijing China } 77130e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 77230e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 77330e7468fSPeter Dunlap } 774fcf3ce44SJohn Forte 77530e7468fSPeter Dunlap static void 77630e7468fSPeter Dunlap iscsi_data_rsp_pkt(iscsi_cmd_t *icmdp, iscsi_data_rsp_hdr_t *idrhp) 77730e7468fSPeter Dunlap { 77830e7468fSPeter Dunlap struct buf *bp = NULL; 77930e7468fSPeter Dunlap size_t data_transferred; 78030e7468fSPeter Dunlap struct scsi_pkt *pkt; 781fcf3ce44SJohn Forte 78230e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp; 78330e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 78430e7468fSPeter Dunlap data_transferred = icmdp->cmd_un.scsi.data_transferred; 78530e7468fSPeter Dunlap /* 78630e7468fSPeter Dunlap * The command* must be completed now, since we won't get a command 78730e7468fSPeter Dunlap * response PDU. The cmd_status and residual_count are 78830e7468fSPeter Dunlap * not meaningful unless status_present is set. 78930e7468fSPeter Dunlap */ 79030e7468fSPeter Dunlap pkt->pkt_resid = 0; 79130e7468fSPeter Dunlap /* Check the residual count */ 79230e7468fSPeter Dunlap if (bp && (data_transferred != bp->b_bcount)) { 793fcf3ce44SJohn Forte /* 79430e7468fSPeter Dunlap * We didn't xfer the expected amount of data - 79530e7468fSPeter Dunlap * the residual_count in the header is only valid 79630e7468fSPeter Dunlap * if the underflow flag is set. 797fcf3ce44SJohn Forte */ 79830e7468fSPeter Dunlap if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) { 79930e7468fSPeter Dunlap pkt->pkt_resid = ntohl(idrhp->residual_count); 80030e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: " 80130e7468fSPeter Dunlap "underflow: itt: %d " 80230e7468fSPeter Dunlap "transferred: %lu count: %lu", idrhp->itt, 80330e7468fSPeter Dunlap data_transferred, bp->b_bcount); 80430e7468fSPeter Dunlap } else { 80530e7468fSPeter Dunlap if (bp->b_bcount > data_transferred) { 80630e7468fSPeter Dunlap /* Some data fell on the floor somehw */ 80730e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: " 80830e7468fSPeter Dunlap "iscsi_data_rsp_pkt: data fell: itt: %d " 80930e7468fSPeter Dunlap "transferred: %lu count: %lu", idrhp->itt, 81030e7468fSPeter Dunlap data_transferred, bp->b_bcount); 81130e7468fSPeter Dunlap pkt->pkt_resid = 81230e7468fSPeter Dunlap bp->b_bcount - data_transferred; 813fcf3ce44SJohn Forte } 81430e7468fSPeter Dunlap } 81530e7468fSPeter Dunlap } 816fcf3ce44SJohn Forte 81730e7468fSPeter Dunlap pkt->pkt_reason = CMD_CMPLT; 81830e7468fSPeter Dunlap pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS); 819fcf3ce44SJohn Forte 82030e7468fSPeter Dunlap if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) && 82130e7468fSPeter Dunlap (icmdp->cmd_un.scsi.statuslen >= 82230e7468fSPeter Dunlap sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) { 823fcf3ce44SJohn Forte 82430e7468fSPeter Dunlap /* 82530e7468fSPeter Dunlap * Not supposed to get exception status here! 82630e7468fSPeter Dunlap * We have no request sense data so just do the 82730e7468fSPeter Dunlap * best we can 82830e7468fSPeter Dunlap */ 82930e7468fSPeter Dunlap struct scsi_arq_status *arqstat = 83030e7468fSPeter Dunlap (struct scsi_arq_status *)pkt->pkt_scbp; 831fcf3ce44SJohn Forte 832fcf3ce44SJohn Forte 83330e7468fSPeter Dunlap bzero(arqstat, sizeof (struct scsi_arq_status)); 834fcf3ce44SJohn Forte 83530e7468fSPeter Dunlap *((uchar_t *)&arqstat->sts_status) = 83630e7468fSPeter Dunlap idrhp->cmd_status; 837fcf3ce44SJohn Forte 838146832dbSMilos Muzik /* sense residual is set to whole size of sense buffer */ 839146832dbSMilos Muzik arqstat->sts_rqpkt_resid = icmdp->cmd_un.scsi.statuslen - 840146832dbSMilos Muzik ISCSI_ARQ_STATUS_NOSENSE_LEN; 84130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_data_rsp_pkt: " 84230e7468fSPeter Dunlap "exception status: itt: %d resid: %d", 84330e7468fSPeter Dunlap idrhp->itt, arqstat->sts_rqpkt_resid); 844b4243054SSheng-Liang Eric Zhang 84530e7468fSPeter Dunlap } else if (pkt->pkt_scbp) { 84630e7468fSPeter Dunlap /* just pass along the status we got */ 84730e7468fSPeter Dunlap pkt->pkt_scbp[0] = idrhp->cmd_status; 848fcf3ce44SJohn Forte } 849fcf3ce44SJohn Forte } 850fcf3ce44SJohn Forte 851fcf3ce44SJohn Forte /* 85230e7468fSPeter Dunlap * iscsi_rx_process_data_rsp - 85330e7468fSPeter Dunlap * This currently processes the final data sequence denoted by the data response 85430e7468fSPeter Dunlap * PDU Status bit being set. We will not receive the SCSI response. 85530e7468fSPeter Dunlap * This bit denotes that the PDU is the successful completion of the 85630e7468fSPeter Dunlap * command. 857fcf3ce44SJohn Forte */ 85830e7468fSPeter Dunlap static idm_status_t 85930e7468fSPeter Dunlap iscsi_rx_process_data_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 860fcf3ce44SJohn Forte { 86130e7468fSPeter Dunlap iscsi_sess_t *isp = NULL; 86230e7468fSPeter Dunlap iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)pdu->isp_hdr; 86330e7468fSPeter Dunlap iscsi_cmd_t *icmdp = NULL; 86430e7468fSPeter Dunlap struct buf *bp = NULL; 86530e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 86630e7468fSPeter Dunlap idm_buf_t *ibp; 86730e7468fSPeter Dunlap idm_status_t rval; 868fcf3ce44SJohn Forte 869fcf3ce44SJohn Forte 87030e7468fSPeter Dunlap /* should only call this when the data rsp contains final rsp */ 87130e7468fSPeter Dunlap ASSERT(idrhp->flags & ISCSI_FLAG_DATA_STATUS); 87230e7468fSPeter Dunlap isp = icp->conn_sess; 87330e7468fSPeter Dunlap 874fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 87530e7468fSPeter Dunlap if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)idrhp, 87630e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) { 87730e7468fSPeter Dunlap if (icmdp != NULL) { 87830e7468fSPeter Dunlap iscsi_task_cleanup(idrhp->opcode, icmdp); 87930e7468fSPeter Dunlap } 880fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 88130e7468fSPeter Dunlap return (rval); 882fcf3ce44SJohn Forte } 883fcf3ce44SJohn Forte 88430e7468fSPeter Dunlap /* 88530e7468fSPeter Dunlap * If we are in "idm aborting" state then we shouldn't continue 88630e7468fSPeter Dunlap * to process this command. By definition this command is no longer 88730e7468fSPeter Dunlap * on the active queue so we shouldn't try to remove it either. 88830e7468fSPeter Dunlap */ 889fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 89030e7468fSPeter Dunlap if (icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING) { 89130e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex); 89230e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 89330e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 89430e7468fSPeter Dunlap } 89530e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex); 89630e7468fSPeter Dunlap 89730e7468fSPeter Dunlap /* 89830e7468fSPeter Dunlap * Holding the pending/active queue locks across the 89930e7468fSPeter Dunlap * iscsi_rx_data call later in this function may cause 90030e7468fSPeter Dunlap * deadlock during fault injections. Instead remove 90130e7468fSPeter Dunlap * the cmd from the active queue and release the locks. 90230e7468fSPeter Dunlap * Then before returning or completing the command 90330e7468fSPeter Dunlap * return the cmd to the active queue and reacquire 90430e7468fSPeter Dunlap * the locks. 90530e7468fSPeter Dunlap */ 90630e7468fSPeter Dunlap iscsi_dequeue_active_cmd(icp, icmdp); 90730e7468fSPeter Dunlap 90830e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 909fcf3ce44SJohn Forte 91030e7468fSPeter Dunlap /* shorthand some values */ 911fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 912fcf3ce44SJohn Forte 91330e7468fSPeter Dunlap /* 91430e7468fSPeter Dunlap * some poorly behaved targets have been observed 91530e7468fSPeter Dunlap * sending data-in pdu's during a write operation 91630e7468fSPeter Dunlap */ 91730e7468fSPeter Dunlap if (bp != NULL) { 91830e7468fSPeter Dunlap if (!(bp->b_flags & B_READ)) { 91930e7468fSPeter Dunlap cmn_err(CE_WARN, 92030e7468fSPeter Dunlap "iscsi connection(%u) protocol error - " 92130e7468fSPeter Dunlap "received data response during write operation " 92230e7468fSPeter Dunlap "itt:0x%x", 92330e7468fSPeter Dunlap icp->conn_oid, idrhp->itt); 92430e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex); 92530e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp); 92630e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 92730e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 92830e7468fSPeter Dunlap } 92930e7468fSPeter Dunlap } 93030e7468fSPeter Dunlap 93130e7468fSPeter Dunlap ibp = icmdp->cmd_un.scsi.ibp_ibuf; 93230e7468fSPeter Dunlap if (ibp == NULL) { 93330e7468fSPeter Dunlap /* 93430e7468fSPeter Dunlap * After the check of bp above we *should* have a corresponding 93530e7468fSPeter Dunlap * idm_buf_t (ibp). It's possible that the original call 93630e7468fSPeter Dunlap * to idm_buf_alloc failed due to a pending connection state 93730e7468fSPeter Dunlap * transition in which case this value can be NULL. It's 93830e7468fSPeter Dunlap * highly unlikely that the connection would be shutting down 93930e7468fSPeter Dunlap * *and* we manage to process a data response and get to this 94030e7468fSPeter Dunlap * point in the code but just in case we should check for it. 94130e7468fSPeter Dunlap * This isn't really a protocol error -- we are almost certainly 94230e7468fSPeter Dunlap * closing the connection anyway so just return a generic error. 94330e7468fSPeter Dunlap */ 94430e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex); 94530e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp); 94630e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 94730e7468fSPeter Dunlap return (IDM_STATUS_FAIL); 94830e7468fSPeter Dunlap } 94930e7468fSPeter Dunlap 95030e7468fSPeter Dunlap if (ic->ic_conn_flags & IDM_CONN_USE_SCOREBOARD) { 95130e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = 95230e7468fSPeter Dunlap icmdp->cmd_itp->idt_rx_bytes; 953fcf3ce44SJohn Forte } else { 95430e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = bp->b_bcount; 95530e7468fSPeter Dunlap if (idrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) { 95630e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred -= 95730e7468fSPeter Dunlap ntohl(idrhp->residual_count); 95830e7468fSPeter Dunlap } 959fcf3ce44SJohn Forte } 960fcf3ce44SJohn Forte 96130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: rx_process_data_rsp: icp: %p pdu: %p " 96230e7468fSPeter Dunlap "itt: %d ibp: %p icmdp: %p xfer_len: %lu transferred: %lu dlen: %u", 96330e7468fSPeter Dunlap (void *)icp, (void *)pdu, idrhp->itt, (void *)bp, (void *)icmdp, 96430e7468fSPeter Dunlap (ibp == NULL) ? 0 : ibp->idb_xfer_len, 96530e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred, 96630e7468fSPeter Dunlap n2h24(idrhp->dlength)); 96730e7468fSPeter Dunlap 96830e7468fSPeter Dunlap iscsi_task_cleanup(idrhp->opcode, icmdp); 96930e7468fSPeter Dunlap 97030e7468fSPeter Dunlap iscsi_data_rsp_pkt(icmdp, idrhp); 97130e7468fSPeter Dunlap 97230e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex); 97330e7468fSPeter Dunlap iscsi_enqueue_active_cmd(icp, icmdp); 97430e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 975fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 976fcf3ce44SJohn Forte 97730e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 978fcf3ce44SJohn Forte } 979fcf3ce44SJohn Forte 980fcf3ce44SJohn Forte /* 981fcf3ce44SJohn Forte * iscsi_rx_process_nop - Process a received nop. If nop is in response 982fcf3ce44SJohn Forte * to a ping we sent update stats. If initiated by the target we need 983fcf3ce44SJohn Forte * to response back to the target with a nop. Schedule the response. 984fcf3ce44SJohn Forte */ 985fcf3ce44SJohn Forte /* ARGSUSED */ 98630e7468fSPeter Dunlap static idm_status_t 98730e7468fSPeter Dunlap iscsi_rx_process_nop(idm_conn_t *ic, idm_pdu_t *pdu) 988fcf3ce44SJohn Forte { 989fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 99030e7468fSPeter Dunlap iscsi_nop_in_hdr_t *inihp = (iscsi_nop_in_hdr_t *)pdu->isp_hdr; 991fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 99230e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 993fcf3ce44SJohn Forte 994fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(inihp->statsn)) { 99530e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - " 996fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 99730e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, inihp->opcode, inihp->itt, 998fcf3ce44SJohn Forte ntohl(inihp->statsn), icp->conn_expstatsn); 99930e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1000fcf3ce44SJohn Forte } 100130e7468fSPeter Dunlap isp = icp->conn_sess; 100230e7468fSPeter Dunlap ASSERT(isp != NULL); 1003fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 1004fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1005fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1006fcf3ce44SJohn Forte if (inihp->itt != ISCSI_RSVD_TASK_TAG) { 1007fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 100830e7468fSPeter Dunlap isp, (iscsi_hdr_t *)inihp, &icmdp))) { 100930e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u) protocol error " 101030e7468fSPeter Dunlap "- can not find cmd for itt:0x%x", 101130e7468fSPeter Dunlap icp->conn_oid, inihp->itt); 1012fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1013fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1014fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 101530e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1016fcf3ce44SJohn Forte } 1017fcf3ce44SJohn Forte } 1018fcf3ce44SJohn Forte 1019fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 1020fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn), 1021fcf3ce44SJohn Forte ntohl(inihp->expcmdsn)); 1022fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1023fcf3ce44SJohn Forte 1024fcf3ce44SJohn Forte if ((inihp->itt != ISCSI_RSVD_TASK_TAG) && 1025fcf3ce44SJohn Forte (inihp->ttt == ISCSI_RSVD_TASK_TAG)) { 1026fcf3ce44SJohn Forte /* This is the only type of nop that incs. the expstatsn */ 1027fcf3ce44SJohn Forte icp->conn_expstatsn++; 1028fcf3ce44SJohn Forte 1029fcf3ce44SJohn Forte /* 1030fcf3ce44SJohn Forte * This is a targets response to our nop 1031fcf3ce44SJohn Forte */ 1032fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1033fcf3ce44SJohn Forte } else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) { 1034fcf3ce44SJohn Forte /* 1035fcf3ce44SJohn Forte * Target requested a nop. Send one. 1036fcf3ce44SJohn Forte */ 1037fcf3ce44SJohn Forte iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt); 1038fcf3ce44SJohn Forte } else { 1039fcf3ce44SJohn Forte /* 1040fcf3ce44SJohn Forte * This is a target-initiated ping that doesn't expect 1041fcf3ce44SJohn Forte * a response; nothing to do except update our flow control 1042fcf3ce44SJohn Forte * (which we do in all cases above). 1043fcf3ce44SJohn Forte */ 1044fcf3ce44SJohn Forte /* EMPTY */ 1045fcf3ce44SJohn Forte } 1046fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1047fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 1048fcf3ce44SJohn Forte 104930e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 1050fcf3ce44SJohn Forte } 1051fcf3ce44SJohn Forte 1052fcf3ce44SJohn Forte 1053fcf3ce44SJohn Forte /* 1054fcf3ce44SJohn Forte * iscsi_rx_process_reject_rsp - The server rejected a PDU 1055fcf3ce44SJohn Forte */ 105630e7468fSPeter Dunlap static idm_status_t 105730e7468fSPeter Dunlap iscsi_rx_process_reject_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 1058fcf3ce44SJohn Forte { 105930e7468fSPeter Dunlap iscsi_reject_rsp_hdr_t *irrhp = (iscsi_reject_rsp_hdr_t *)pdu->isp_hdr; 106030e7468fSPeter Dunlap iscsi_sess_t *isp = NULL; 106130e7468fSPeter Dunlap uint32_t dlength = 0; 106230e7468fSPeter Dunlap iscsi_hdr_t *old_ihp = NULL; 106330e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 1064*811eca55SToomas Soome uint8_t *data = pdu->isp_data; 1065aefdd131Sbing zhao - Sun Microsystems - Beijing China idm_status_t status = IDM_STATUS_SUCCESS; 1066aefdd131Sbing zhao - Sun Microsystems - Beijing China int i = 0; 1067fcf3ce44SJohn Forte 1068fcf3ce44SJohn Forte ASSERT(data != NULL); 106930e7468fSPeter Dunlap isp = icp->conn_sess; 107030e7468fSPeter Dunlap ASSERT(isp != NULL); 1071fcf3ce44SJohn Forte 1072aefdd131Sbing zhao - Sun Microsystems - Beijing China /* 1073aefdd131Sbing zhao - Sun Microsystems - Beijing China * In RFC3720 section 10.17, this 4 bytes should be all 0xff. 1074aefdd131Sbing zhao - Sun Microsystems - Beijing China */ 1075aefdd131Sbing zhao - Sun Microsystems - Beijing China for (i = 0; i < 4; i++) { 1076aefdd131Sbing zhao - Sun Microsystems - Beijing China if (irrhp->must_be_ff[i] != 0xff) { 1077aefdd131Sbing zhao - Sun Microsystems - Beijing China return (IDM_STATUS_PROTOCOL_ERROR); 1078aefdd131Sbing zhao - Sun Microsystems - Beijing China } 1079aefdd131Sbing zhao - Sun Microsystems - Beijing China } 1080aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_cmdsn_mutex); 1081aefdd131Sbing zhao - Sun Microsystems - Beijing China 1082aefdd131Sbing zhao - Sun Microsystems - Beijing China if (icp->conn_expstatsn == ntohl(irrhp->statsn)) { 1083aefdd131Sbing zhao - Sun Microsystems - Beijing China icp->conn_expstatsn++; 1084aefdd131Sbing zhao - Sun Microsystems - Beijing China } else { 1085aefdd131Sbing zhao - Sun Microsystems - Beijing China cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - " 1086aefdd131Sbing zhao - Sun Microsystems - Beijing China "received status out of order statsn:0x%x " 1087aefdd131Sbing zhao - Sun Microsystems - Beijing China "expstatsn:0x%x", icp->conn_oid, irrhp->opcode, 1088aefdd131Sbing zhao - Sun Microsystems - Beijing China ntohl(irrhp->statsn), icp->conn_expstatsn); 1089aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_cmdsn_mutex); 1090aefdd131Sbing zhao - Sun Microsystems - Beijing China return (IDM_STATUS_PROTOCOL_ERROR); 1091fcf3ce44SJohn Forte } 1092aefdd131Sbing zhao - Sun Microsystems - Beijing China /* update expcmdsn and maxcmdsn */ 1093aefdd131Sbing zhao - Sun Microsystems - Beijing China iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn), 1094aefdd131Sbing zhao - Sun Microsystems - Beijing China ntohl(irrhp->expcmdsn)); 1095aefdd131Sbing zhao - Sun Microsystems - Beijing China 1096aefdd131Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_cmdsn_mutex); 1097fcf3ce44SJohn Forte 1098fcf3ce44SJohn Forte /* If we don't have the rejected header we can't do anything */ 1099fcf3ce44SJohn Forte dlength = n2h24(irrhp->dlength); 1100fcf3ce44SJohn Forte if (dlength < sizeof (iscsi_hdr_t)) { 110130e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1102fcf3ce44SJohn Forte } 1103fcf3ce44SJohn Forte 1104fcf3ce44SJohn Forte /* map old ihp */ 1105fcf3ce44SJohn Forte old_ihp = (iscsi_hdr_t *)data; 1106fcf3ce44SJohn Forte 1107fcf3ce44SJohn Forte switch (irrhp->reason) { 1108fcf3ce44SJohn Forte /* 1109fcf3ce44SJohn Forte * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject 1110fcf3ce44SJohn Forte * too many immediate commands (original cmd can be resent) 1111fcf3ce44SJohn Forte */ 1112fcf3ce44SJohn Forte case ISCSI_REJECT_IMM_CMD_REJECT: 1113fcf3ce44SJohn Forte /* 1114fcf3ce44SJohn Forte * We have exceeded the server's capacity for outstanding 1115fcf3ce44SJohn Forte * immediate commands. This must be a task management 1116fcf3ce44SJohn Forte * command so try to find it in the abortingqueue and 1117fcf3ce44SJohn Forte * complete it. 1118fcf3ce44SJohn Forte */ 1119fcf3ce44SJohn Forte if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) { 1120fcf3ce44SJohn Forte /* Rejecting IMM but old old_hdr wasn't IMM */ 112130e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1122fcf3ce44SJohn Forte } 1123fcf3ce44SJohn Forte 1124fcf3ce44SJohn Forte /* 1125fcf3ce44SJohn Forte * We only send NOP and TASK_MGT as IMM. All other 1126fcf3ce44SJohn Forte * cases should be considered as a protocol error. 1127fcf3ce44SJohn Forte */ 1128fcf3ce44SJohn Forte switch (old_ihp->opcode & ISCSI_OPCODE_MASK) { 1129fcf3ce44SJohn Forte case ISCSI_OP_NOOP_OUT: 1130fcf3ce44SJohn Forte /* 1131fcf3ce44SJohn Forte * A ping was rejected - treat this like 1132fcf3ce44SJohn Forte * ping response. The down side is we 1133fcf3ce44SJohn Forte * didn't get an updated MaxCmdSn. 1134fcf3ce44SJohn Forte */ 1135fcf3ce44SJohn Forte break; 1136fcf3ce44SJohn Forte case ISCSI_OP_SCSI_TASK_MGT_MSG: 1137aefdd131Sbing zhao - Sun Microsystems - Beijing China status = 1138aefdd131Sbing zhao - Sun Microsystems - Beijing China iscsi_rx_process_rejected_tsk_mgt(ic, old_ihp); 1139fcf3ce44SJohn Forte break; 1140fcf3ce44SJohn Forte default: 1141fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error " 1142fcf3ce44SJohn Forte "- received a reject for a command(0x%02x) not " 1143fcf3ce44SJohn Forte "sent as an immediate", icp->conn_oid, 1144fcf3ce44SJohn Forte old_ihp->opcode); 114530e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 114630e7468fSPeter Dunlap break; 1147fcf3ce44SJohn Forte } 1148fcf3ce44SJohn Forte break; 1149fcf3ce44SJohn Forte 1150fcf3ce44SJohn Forte /* 1151fcf3ce44SJohn Forte * For the rest of the reject cases just use the general 1152fcf3ce44SJohn Forte * hammer of dis/reconnecting. This will resolve all 1153fcf3ce44SJohn Forte * noted issues although could be more graceful. 1154fcf3ce44SJohn Forte */ 1155fcf3ce44SJohn Forte case ISCSI_REJECT_DATA_DIGEST_ERROR: 1156fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_BEFORE_LOGIN: 1157fcf3ce44SJohn Forte case ISCSI_REJECT_SNACK_REJECT: 1158fcf3ce44SJohn Forte case ISCSI_REJECT_PROTOCOL_ERROR: 1159fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_NOT_SUPPORTED: 1160fcf3ce44SJohn Forte case ISCSI_REJECT_TASK_IN_PROGRESS: 1161fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_DATA_ACK: 1162fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_PDU_FIELD: 1163fcf3ce44SJohn Forte case ISCSI_REJECT_LONG_OPERATION_REJECT: 1164fcf3ce44SJohn Forte case ISCSI_REJECT_NEGOTIATION_RESET: 1165fcf3ce44SJohn Forte default: 1166aefdd131Sbing zhao - Sun Microsystems - Beijing China cmn_err(CE_WARN, "iscsi connection(%u/%x) closing connection - " 1167aefdd131Sbing zhao - Sun Microsystems - Beijing China "target requested reason:0x%x", 1168aefdd131Sbing zhao - Sun Microsystems - Beijing China icp->conn_oid, irrhp->opcode, irrhp->reason); 116930e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 117030e7468fSPeter Dunlap break; 1171fcf3ce44SJohn Forte } 1172fcf3ce44SJohn Forte 1173aefdd131Sbing zhao - Sun Microsystems - Beijing China return (status); 1174fcf3ce44SJohn Forte } 1175fcf3ce44SJohn Forte 1176fcf3ce44SJohn Forte 1177fcf3ce44SJohn Forte /* 1178fcf3ce44SJohn Forte * iscsi_rx_process_rejected_tsk_mgt - 1179fcf3ce44SJohn Forte */ 118030e7468fSPeter Dunlap /* ARGSUSED */ 118130e7468fSPeter Dunlap static idm_status_t 118230e7468fSPeter Dunlap iscsi_rx_process_rejected_tsk_mgt(idm_conn_t *ic, iscsi_hdr_t *old_ihp) 1183fcf3ce44SJohn Forte { 118430e7468fSPeter Dunlap iscsi_sess_t *isp = NULL; 118530e7468fSPeter Dunlap iscsi_cmd_t *icmdp = NULL; 1186*811eca55SToomas Soome iscsi_conn_t *icp = ic->ic_handle; 1187fcf3ce44SJohn Forte 1188fcf3ce44SJohn Forte isp = icp->conn_sess; 1189fcf3ce44SJohn Forte ASSERT(old_ihp != NULL); 119030e7468fSPeter Dunlap ASSERT(isp != NULL); 1191fcf3ce44SJohn Forte 1192fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1193fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1194fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 1195fcf3ce44SJohn Forte isp, old_ihp, &icmdp))) { 1196fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1197fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 119830e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1199fcf3ce44SJohn Forte } 1200fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1201fcf3ce44SJohn Forte 1202fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1203fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1204fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1205fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, 1206fcf3ce44SJohn Forte icp->conn_sess); 1207fcf3ce44SJohn Forte break; 1208fcf3ce44SJohn Forte /* We don't send any other task mgr types */ 1209fcf3ce44SJohn Forte default: 1210fcf3ce44SJohn Forte ASSERT(B_FALSE); 1211fcf3ce44SJohn Forte break; 1212fcf3ce44SJohn Forte } 1213fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1214fcf3ce44SJohn Forte 121530e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 1216fcf3ce44SJohn Forte } 1217fcf3ce44SJohn Forte 1218fcf3ce44SJohn Forte 1219fcf3ce44SJohn Forte /* 1220fcf3ce44SJohn Forte * iscsi_rx_process_task_mgt_rsp - 1221fcf3ce44SJohn Forte */ 1222fcf3ce44SJohn Forte /* ARGSUSED */ 122330e7468fSPeter Dunlap static idm_status_t 122430e7468fSPeter Dunlap iscsi_rx_process_task_mgt_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 1225fcf3ce44SJohn Forte { 1226fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1227fcf3ce44SJohn Forte iscsi_scsi_task_mgt_rsp_hdr_t *istmrhp = NULL; 1228fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 122930e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 123030e7468fSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 1231fcf3ce44SJohn Forte 1232fcf3ce44SJohn Forte isp = icp->conn_sess; 123330e7468fSPeter Dunlap istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr; 1234fcf3ce44SJohn Forte 1235fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 123630e7468fSPeter Dunlap if ((status = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)istmrhp, 123730e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) { 1238fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 123930e7468fSPeter Dunlap return (status); 1240fcf3ce44SJohn Forte } 1241fcf3ce44SJohn Forte 1242fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1243fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1244fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1245fcf3ce44SJohn Forte switch (istmrhp->response) { 1246fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_COMPLETE: 1247fcf3ce44SJohn Forte /* success */ 1248fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, 1249fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E3, isp); 1250fcf3ce44SJohn Forte break; 1251fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_TASK: 1252fcf3ce44SJohn Forte /* 1253fcf3ce44SJohn Forte * If the array no longer knows about 1254fcf3ce44SJohn Forte * an ABORT RTT and we no longer have 1255fcf3ce44SJohn Forte * a parent SCSI command it was just 1256fcf3ce44SJohn Forte * completed, free this ABORT resource. 1257fcf3ce44SJohn Forte * Otherwise FALLTHRU this will flag a 1258fcf3ce44SJohn Forte * protocol problem. 1259fcf3ce44SJohn Forte */ 1260fcf3ce44SJohn Forte if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) && 1261fcf3ce44SJohn Forte (icmdp->cmd_un.abort.icmdp == NULL)) { 1262fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, 1263fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E4, isp); 1264fcf3ce44SJohn Forte break; 1265fcf3ce44SJohn Forte } 1266fcf3ce44SJohn Forte /* FALLTHRU */ 12672b79d384Sbing zhao - Sun Microsystems - Beijing China case SCSI_TCP_TM_RESP_REJECTED: 12682b79d384Sbing zhao - Sun Microsystems - Beijing China /* 12692b79d384Sbing zhao - Sun Microsystems - Beijing China * If the target rejects our reset task, 12702b79d384Sbing zhao - Sun Microsystems - Beijing China * we should record the response and complete 12712b79d384Sbing zhao - Sun Microsystems - Beijing China * this command with the result. 12722b79d384Sbing zhao - Sun Microsystems - Beijing China */ 12732b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET) { 12742b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_un.reset.response = 12752b79d384Sbing zhao - Sun Microsystems - Beijing China istmrhp->response; 12762b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp, 12772b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E3, isp); 12782b79d384Sbing zhao - Sun Microsystems - Beijing China break; 12792b79d384Sbing zhao - Sun Microsystems - Beijing China } 12802b79d384Sbing zhao - Sun Microsystems - Beijing China /* FALLTHRU */ 1281fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_LUN: 1282fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_TASK_ALLEGIANT: 1283fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_FAILOVER: 1284fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_IN_PRGRESS: 1285fcf3ce44SJohn Forte default: 1286fcf3ce44SJohn Forte /* 1287fcf3ce44SJohn Forte * Something is out of sync. Flush 1288fcf3ce44SJohn Forte * active queues and resync the 1289fcf3ce44SJohn Forte * the connection to try and recover 1290fcf3ce44SJohn Forte * to a known state. 1291fcf3ce44SJohn Forte */ 129230e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 1293fcf3ce44SJohn Forte } 1294fcf3ce44SJohn Forte break; 1295fcf3ce44SJohn Forte 1296fcf3ce44SJohn Forte default: 1297fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1298fcf3ce44SJohn Forte "received a task mgt response for a non-task mgt " 1299fcf3ce44SJohn Forte "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt, 1300fcf3ce44SJohn Forte icmdp->cmd_type); 130130e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 130230e7468fSPeter Dunlap break; 1303fcf3ce44SJohn Forte } 1304fcf3ce44SJohn Forte 1305fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 130630e7468fSPeter Dunlap return (status); 1307fcf3ce44SJohn Forte } 1308fcf3ce44SJohn Forte 1309fcf3ce44SJohn Forte 1310fcf3ce44SJohn Forte /* 131130e7468fSPeter Dunlap * iscsi_rx_process_logout_rsp - 1312fcf3ce44SJohn Forte * 1313fcf3ce44SJohn Forte */ 1314fcf3ce44SJohn Forte /* ARGSUSED */ 131530e7468fSPeter Dunlap idm_status_t 131630e7468fSPeter Dunlap iscsi_rx_process_logout_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 1317fcf3ce44SJohn Forte { 131830e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 131930e7468fSPeter Dunlap iscsi_logout_rsp_hdr_t *ilrhp = 132030e7468fSPeter Dunlap (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr; 1321fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 132230e7468fSPeter Dunlap iscsi_sess_t *isp; 132330e7468fSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 1324fcf3ce44SJohn Forte 1325fcf3ce44SJohn Forte isp = icp->conn_sess; 1326fcf3ce44SJohn Forte 1327fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) { 132830e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u/%x) protocol error - " 1329fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 133030e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, ilrhp->opcode, ilrhp->itt, 1331fcf3ce44SJohn Forte ntohl(ilrhp->statsn), icp->conn_expstatsn); 133230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1333fcf3ce44SJohn Forte } 1334fcf3ce44SJohn Forte 1335fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1336fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1337fcf3ce44SJohn Forte if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) { 1338fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 133930e7468fSPeter Dunlap isp, (iscsi_hdr_t *)ilrhp, &icmdp))) { 1340fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1341fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 134230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1343fcf3ce44SJohn Forte } 1344fcf3ce44SJohn Forte } 1345fcf3ce44SJohn Forte 1346fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 1347fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn), 1348fcf3ce44SJohn Forte ntohl(ilrhp->expcmdsn)); 1349fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1350fcf3ce44SJohn Forte 135130e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 135230e7468fSPeter Dunlap "DEBUG: iscsi_rx_process_logout_rsp: response: %d", 135330e7468fSPeter Dunlap ilrhp->response); 1354fcf3ce44SJohn Forte switch (ilrhp->response) { 1355fcf3ce44SJohn Forte case ISCSI_LOGOUT_CID_NOT_FOUND: 1356fcf3ce44SJohn Forte /* 1357fcf3ce44SJohn Forte * If the target doesn't know about our connection 1358fcf3ce44SJohn Forte * then we can consider our self disconnected. 1359fcf3ce44SJohn Forte */ 1360fcf3ce44SJohn Forte /* FALLTHRU */ 1361fcf3ce44SJohn Forte case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED: 1362fcf3ce44SJohn Forte /* 1363fcf3ce44SJohn Forte * We don't support ErrorRecovery levels above 0 1364fcf3ce44SJohn Forte * currently so consider this success. 1365fcf3ce44SJohn Forte */ 1366fcf3ce44SJohn Forte /* FALLTHRU */ 1367fcf3ce44SJohn Forte case ISCSI_LOGOUT_CLEANUP_FAILED: 1368fcf3ce44SJohn Forte /* 1369fcf3ce44SJohn Forte * per spec. "cleanup failed for various reasons." 1370fcf3ce44SJohn Forte * Although those various reasons are undefined. 1371fcf3ce44SJohn Forte * Not sure what to do here. So fake success, 1372fcf3ce44SJohn Forte * which will disconnect the connection. 1373fcf3ce44SJohn Forte */ 1374fcf3ce44SJohn Forte /* FALLTHRU */ 1375fcf3ce44SJohn Forte case ISCSI_LOGOUT_SUCCESS: 1376fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1377fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 137830e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp); 1379fcf3ce44SJohn Forte break; 1380fcf3ce44SJohn Forte default: 1381fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 138230e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 138330e7468fSPeter Dunlap break; 1384fcf3ce44SJohn Forte 138530e7468fSPeter Dunlap } 138630e7468fSPeter Dunlap return (status); 1387fcf3ce44SJohn Forte } 1388fcf3ce44SJohn Forte 1389fcf3ce44SJohn Forte /* 139030e7468fSPeter Dunlap * iscsi_rx_process_async_rsp 1391fcf3ce44SJohn Forte * 1392fcf3ce44SJohn Forte */ 1393fcf3ce44SJohn Forte /* ARGSUSED */ 139430e7468fSPeter Dunlap static idm_status_t 139530e7468fSPeter Dunlap iscsi_rx_process_async_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 1396fcf3ce44SJohn Forte { 139730e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 139830e7468fSPeter Dunlap iscsi_sess_t *isp = icp->conn_sess; 139930e7468fSPeter Dunlap idm_status_t rval = IDM_STATUS_SUCCESS; 140030e7468fSPeter Dunlap iscsi_task_t *itp; 140130e7468fSPeter Dunlap iscsi_async_evt_hdr_t *iaehp = 140230e7468fSPeter Dunlap (iscsi_async_evt_hdr_t *)pdu->isp_hdr; 1403fcf3ce44SJohn Forte 1404fcf3ce44SJohn Forte ASSERT(icp != NULL); 140530e7468fSPeter Dunlap ASSERT(pdu != NULL); 140630e7468fSPeter Dunlap ASSERT(isp != NULL); 1407fcf3ce44SJohn Forte 140830e7468fSPeter Dunlap mutex_enter(&isp->sess_cmdsn_mutex); 140930e7468fSPeter Dunlap if (icp->conn_expstatsn == ntohl(iaehp->statsn)) { 141030e7468fSPeter Dunlap icp->conn_expstatsn++; 141130e7468fSPeter Dunlap } else { 1412fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 141330e7468fSPeter Dunlap "received status out of order statsn:0x%x " 141430e7468fSPeter Dunlap "expstatsn:0x%x", icp->conn_oid, 1415fcf3ce44SJohn Forte ntohl(iaehp->statsn), icp->conn_expstatsn); 141630e7468fSPeter Dunlap mutex_exit(&isp->sess_cmdsn_mutex); 141730e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1418fcf3ce44SJohn Forte } 141930e7468fSPeter Dunlap mutex_exit(&isp->sess_cmdsn_mutex); 1420fcf3ce44SJohn Forte 1421fcf3ce44SJohn Forte switch (iaehp->async_event) { 1422fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1423fcf3ce44SJohn Forte /* 1424fcf3ce44SJohn Forte * SCSI asynchronous event is reported in 1425fcf3ce44SJohn Forte * the sense data. Sense data that accompanies 1426fcf3ce44SJohn Forte * the report in the data segment identifies the 1427fcf3ce44SJohn Forte * condition. If the target supports SCSI 1428fcf3ce44SJohn Forte * asynchronous events reporting (see [SAM2]) 1429fcf3ce44SJohn Forte * as indicated in the stardard INQUIRY data 1430fcf3ce44SJohn Forte * (see [SPC3]), its use may be enabled by 1431fcf3ce44SJohn Forte * parameters in the SCSI control mode page 1432fcf3ce44SJohn Forte * (see [SPC3]). 1433fcf3ce44SJohn Forte * 1434fcf3ce44SJohn Forte * T-10 has removed SCSI asunchronous events 1435fcf3ce44SJohn Forte * from the standard. Although we have seen 1436fcf3ce44SJohn Forte * a couple targets still spending these requests. 1437fcf3ce44SJohn Forte * Those targets were specifically sending them 1438fcf3ce44SJohn Forte * for notification of a LUN/Volume change 1439904e51f6SJack Meng * (ex. LUN addition/removal). Fire the enumeration 1440904e51f6SJack Meng * to handle the change. 1441fcf3ce44SJohn Forte */ 1442904e51f6SJack Meng if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 1443904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 1444904e51f6SJack Meng if (isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) { 1445904e51f6SJack Meng (void) iscsi_sess_enum_request(isp, B_FALSE, 1446904e51f6SJack Meng isp->sess_state_event_count); 1447904e51f6SJack Meng } 1448904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 1449904e51f6SJack Meng } 1450fcf3ce44SJohn Forte break; 1451fcf3ce44SJohn Forte 1452fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 145330e7468fSPeter Dunlap /* 145430e7468fSPeter Dunlap * We've been asked to logout by the target -- 145530e7468fSPeter Dunlap * we need to treat this differently from a normal logout 145630e7468fSPeter Dunlap * due to a discovery failure. Normal logouts result in 145730e7468fSPeter Dunlap * an N3 event to the session state machine and an offline 145830e7468fSPeter Dunlap * of the lun. In this case we want to put the connection 145930e7468fSPeter Dunlap * into "failed" state and generate N5 to the session state 146030e7468fSPeter Dunlap * machine since the initiator logged out at the target's 146130e7468fSPeter Dunlap * request. To track this we set a flag indicating we 146230e7468fSPeter Dunlap * received this async logout request from the tharget 146330e7468fSPeter Dunlap */ 1464fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 146530e7468fSPeter Dunlap icp->conn_async_logout = B_TRUE; 1466fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 146730e7468fSPeter Dunlap 146892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Hold is released in iscsi_handle_logout. */ 146992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_hold(ic); 147092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 147130e7468fSPeter Dunlap /* Target has requested this connection to logout. */ 147230e7468fSPeter Dunlap itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 147330e7468fSPeter Dunlap itp->t_arg = icp; 147430e7468fSPeter Dunlap itp->t_blocking = B_FALSE; 1475904e51f6SJack Meng if (ddi_taskq_dispatch(isp->sess_login_taskq, 147630e7468fSPeter Dunlap (void(*)())iscsi_logout_start, itp, DDI_SLEEP) != 147730e7468fSPeter Dunlap DDI_SUCCESS) { 147892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic); 147930e7468fSPeter Dunlap /* Disconnect if we couldn't dispatch the task */ 148030e7468fSPeter Dunlap idm_ini_conn_disconnect(ic); 148130e7468fSPeter Dunlap } 1482fcf3ce44SJohn Forte break; 1483fcf3ce44SJohn Forte 1484fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 1485fcf3ce44SJohn Forte /* 1486fcf3ce44SJohn Forte * Target is going to drop our connection. 1487fcf3ce44SJohn Forte * param1 - CID which will be dropped. 1488fcf3ce44SJohn Forte * param2 - Min time to reconnect. 1489fcf3ce44SJohn Forte * param3 - Max time to reconnect. 1490fcf3ce44SJohn Forte * 1491fcf3ce44SJohn Forte * For now just let fail as another disconnect. 1492fcf3ce44SJohn Forte * 1493fcf3ce44SJohn Forte * MC/S Once we support > 1 connections then 1494fcf3ce44SJohn Forte * we need to check the CID and drop that 1495fcf3ce44SJohn Forte * specific connection. 1496fcf3ce44SJohn Forte */ 149730e7468fSPeter Dunlap iscsi_conn_set_login_min_max(icp, iaehp->param2, 149830e7468fSPeter Dunlap iaehp->param3); 149930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic); 1500fcf3ce44SJohn Forte break; 1501fcf3ce44SJohn Forte 1502fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1503fcf3ce44SJohn Forte /* 1504fcf3ce44SJohn Forte * Target is going to drop ALL connections. 1505fcf3ce44SJohn Forte * param2 - Min time to reconnect. 1506fcf3ce44SJohn Forte * param3 - Max time to reconnect. 1507fcf3ce44SJohn Forte * 1508fcf3ce44SJohn Forte * For now just let fail as anyother disconnect. 1509fcf3ce44SJohn Forte * 1510fcf3ce44SJohn Forte * MC/S Once we support more than > 1 connections 1511fcf3ce44SJohn Forte * then we need to drop all connections on the 1512fcf3ce44SJohn Forte * session. 1513fcf3ce44SJohn Forte */ 151430e7468fSPeter Dunlap iscsi_conn_set_login_min_max(icp, iaehp->param2, 151530e7468fSPeter Dunlap iaehp->param3); 151630e7468fSPeter Dunlap idm_ini_conn_disconnect(ic); 1517fcf3ce44SJohn Forte break; 1518fcf3ce44SJohn Forte 1519fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1520fcf3ce44SJohn Forte /* 1521fcf3ce44SJohn Forte * Target requests parameter negotiation 1522fcf3ce44SJohn Forte * on this connection. 1523fcf3ce44SJohn Forte * 1524fcf3ce44SJohn Forte * The initiator must honor this request. For 1525fcf3ce44SJohn Forte * now we will request a logout. We can't 1526fcf3ce44SJohn Forte * just ignore this or it might force corruption? 1527fcf3ce44SJohn Forte */ 152892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 152992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Hold is released in iscsi_handle_logout */ 153092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_hold(ic); 153130e7468fSPeter Dunlap itp = kmem_zalloc(sizeof (iscsi_task_t), KM_SLEEP); 153230e7468fSPeter Dunlap itp->t_arg = icp; 153330e7468fSPeter Dunlap itp->t_blocking = B_FALSE; 1534904e51f6SJack Meng if (ddi_taskq_dispatch(isp->sess_login_taskq, 153530e7468fSPeter Dunlap (void(*)())iscsi_logout_start, itp, DDI_SLEEP) != 153630e7468fSPeter Dunlap DDI_SUCCESS) { 153730e7468fSPeter Dunlap /* Disconnect if we couldn't dispatch the task */ 153892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic); 153930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic); 154030e7468fSPeter Dunlap } 1541fcf3ce44SJohn Forte break; 1542fcf3ce44SJohn Forte 1543fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC: 1544fcf3ce44SJohn Forte /* 1545fcf3ce44SJohn Forte * We currently don't handle any vendor 1546fcf3ce44SJohn Forte * specific async events. So just ignore 1547fcf3ce44SJohn Forte * the request. 1548fcf3ce44SJohn Forte */ 154930e7468fSPeter Dunlap idm_ini_conn_disconnect(ic); 1550fcf3ce44SJohn Forte break; 1551fcf3ce44SJohn Forte default: 155230e7468fSPeter Dunlap rval = IDM_STATUS_PROTOCOL_ERROR; 1553fcf3ce44SJohn Forte } 1554fcf3ce44SJohn Forte 1555fcf3ce44SJohn Forte return (rval); 1556fcf3ce44SJohn Forte } 1557fcf3ce44SJohn Forte 1558fcf3ce44SJohn Forte /* 1559fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp - processes iSCSI text response. It sets 1560fcf3ce44SJohn Forte * the cmd_result field of the command data structure with the actual 1561fcf3ce44SJohn Forte * status value instead of returning the status value. The return value 1562fcf3ce44SJohn Forte * is SUCCESS in order to let iscsi_handle_text control the operation of 1563fcf3ce44SJohn Forte * a text request. 156430e7468fSPeter Dunlap * Text requests are a handled a little different than other types of 1565fcf3ce44SJohn Forte * iSCSI commands because the initiator sends additional empty text requests 1566fcf3ce44SJohn Forte * in order to obtain the remaining responses required to complete the 1567fcf3ce44SJohn Forte * request. iscsi_handle_text controls the operation of text request, while 1568fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp just process the current response. 1569fcf3ce44SJohn Forte */ 157030e7468fSPeter Dunlap static idm_status_t 157130e7468fSPeter Dunlap iscsi_rx_process_text_rsp(idm_conn_t *ic, idm_pdu_t *pdu) 1572fcf3ce44SJohn Forte { 1573fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 157430e7468fSPeter Dunlap iscsi_text_rsp_hdr_t *ithp = 157530e7468fSPeter Dunlap (iscsi_text_rsp_hdr_t *)pdu->isp_hdr; 157630e7468fSPeter Dunlap iscsi_conn_t *icp = ic->ic_handle; 1577fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1578fcf3ce44SJohn Forte boolean_t final = B_FALSE; 1579fcf3ce44SJohn Forte uint32_t data_len; 158030e7468fSPeter Dunlap uint8_t *data = pdu->isp_data; 158130e7468fSPeter Dunlap idm_status_t rval; 1582fcf3ce44SJohn Forte 1583fcf3ce44SJohn Forte isp = icp->conn_sess; 1584fcf3ce44SJohn Forte 1585fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 158630e7468fSPeter Dunlap if ((rval = iscsi_rx_chk(icp, isp, (iscsi_scsi_rsp_hdr_t *)ithp, 158730e7468fSPeter Dunlap &icmdp)) != IDM_STATUS_SUCCESS) { 1588fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 158930e7468fSPeter Dunlap return (rval); 1590fcf3ce44SJohn Forte } 1591fcf3ce44SJohn Forte 1592fcf3ce44SJohn Forte /* update local final response flag */ 1593fcf3ce44SJohn Forte if (ithp->flags & ISCSI_FLAG_FINAL) { 1594fcf3ce44SJohn Forte final = B_TRUE; 1595fcf3ce44SJohn Forte } 1596fcf3ce44SJohn Forte 1597fcf3ce44SJohn Forte /* 1598fcf3ce44SJohn Forte * validate received TTT value. RFC3720 specifies the following: 1599fcf3ce44SJohn Forte * - F bit set to 1 MUST have a reserved TTT value 0xffffffff 1600fcf3ce44SJohn Forte * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff 1601fcf3ce44SJohn Forte * In addition, the received TTT value must not change between 1602fcf3ce44SJohn Forte * responses of a long text response 1603fcf3ce44SJohn Forte */ 1604fcf3ce44SJohn Forte if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) || 1605fcf3ce44SJohn Forte ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) { 1606fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR; 1607fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1608fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1609fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1610fcf3ce44SJohn Forte "received text response with invalid flags:0x%x or " 1611fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt); 161230e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1613fcf3ce44SJohn Forte } 1614fcf3ce44SJohn Forte 1615fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) && 1616fcf3ce44SJohn Forte (ithp->ttt == ISCSI_RSVD_TASK_TAG) && 1617fcf3ce44SJohn Forte (final == B_FALSE)) { 1618fcf3ce44SJohn Forte /* TTT should have matched reserved value */ 1619fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR; 1620fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1621fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1622fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol " 1623fcf3ce44SJohn Forte "error - received text response with invalid " 1624fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->ttt); 162530e7468fSPeter Dunlap return (IDM_STATUS_PROTOCOL_ERROR); 1626fcf3ce44SJohn Forte } 1627fcf3ce44SJohn Forte 1628fcf3ce44SJohn Forte /* 1629fcf3ce44SJohn Forte * If this is first response, save away TTT value for later use 1630fcf3ce44SJohn Forte * in a long text request/response sequence 1631fcf3ce44SJohn Forte */ 1632fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) { 1633fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ithp->ttt; 1634fcf3ce44SJohn Forte } 1635fcf3ce44SJohn Forte 1636fcf3ce44SJohn Forte data_len = ntoh24(ithp->dlength); 1637fcf3ce44SJohn Forte 1638fcf3ce44SJohn Forte /* check whether enough buffer available to copy data */ 1639fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.total_rx_len + data_len) > 1640fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len) { 1641fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len; 1642fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW; 1643fcf3ce44SJohn Forte /* 1644fcf3ce44SJohn Forte * DATA_OVERFLOW will result in a SUCCESS return so that 1645fcf3ce44SJohn Forte * iscsi_handle_text can continue to obtain the remaining 1646fcf3ce44SJohn Forte * text response if needed. 1647fcf3ce44SJohn Forte */ 1648fcf3ce44SJohn Forte } else { 1649fcf3ce44SJohn Forte char *buf_data = (icmdp->cmd_un.text.buf + 1650fcf3ce44SJohn Forte icmdp->cmd_un.text.offset); 1651fcf3ce44SJohn Forte 1652fcf3ce44SJohn Forte bcopy(data, buf_data, data_len); 1653fcf3ce44SJohn Forte icmdp->cmd_un.text.offset += data_len; 1654fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len; 1655fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 1656fcf3ce44SJohn Forte bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun, 1657fcf3ce44SJohn Forte sizeof (icmdp->cmd_un.text.lun)); 1658fcf3ce44SJohn Forte } 1659fcf3ce44SJohn Forte 1660fcf3ce44SJohn Forte /* update stage */ 1661fcf3ce44SJohn Forte if (final == B_TRUE) { 1662fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1663fcf3ce44SJohn Forte } else { 1664fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION; 1665fcf3ce44SJohn Forte } 1666fcf3ce44SJohn Forte 1667fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1668fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 166930e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 167030e7468fSPeter Dunlap } 167130e7468fSPeter Dunlap 167230e7468fSPeter Dunlap /* 167330e7468fSPeter Dunlap * iscsi_rx_process_scsi_itt_to_icmdp - Lookup itt using IDM to find matching 167430e7468fSPeter Dunlap * icmdp. Verify itt in hdr and icmdp are the same. 167530e7468fSPeter Dunlap */ 167630e7468fSPeter Dunlap static iscsi_status_t 167730e7468fSPeter Dunlap iscsi_rx_process_scsi_itt_to_icmdp(iscsi_sess_t *isp, idm_conn_t *ic, 167830e7468fSPeter Dunlap iscsi_scsi_rsp_hdr_t *ihp, iscsi_cmd_t **icmdp) 167930e7468fSPeter Dunlap { 168030e7468fSPeter Dunlap idm_task_t *itp; 168130e7468fSPeter Dunlap 168230e7468fSPeter Dunlap ASSERT(isp != NULL); 168330e7468fSPeter Dunlap ASSERT(ihp != NULL); 168430e7468fSPeter Dunlap ASSERT(icmdp != NULL); 168530e7468fSPeter Dunlap ASSERT(mutex_owned(&isp->sess_cmdsn_mutex)); 168630e7468fSPeter Dunlap itp = idm_task_find_and_complete(ic, ihp->itt, ISCSI_INI_TASK_TTT); 168730e7468fSPeter Dunlap if (itp == NULL) { 168830e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi session(%u) protocol error - " 168930e7468fSPeter Dunlap "received unknown itt:0x%x - protocol error", 169030e7468fSPeter Dunlap isp->sess_oid, ihp->itt); 169130e7468fSPeter Dunlap return (ISCSI_STATUS_INTERNAL_ERROR); 169230e7468fSPeter Dunlap } 169330e7468fSPeter Dunlap *icmdp = itp->idt_private; 169430e7468fSPeter Dunlap 169530e7468fSPeter Dunlap idm_task_rele(itp); 169630e7468fSPeter Dunlap 1697fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 169830e7468fSPeter Dunlap 1699fcf3ce44SJohn Forte } 1700fcf3ce44SJohn Forte 1701fcf3ce44SJohn Forte /* 1702fcf3ce44SJohn Forte * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's 1703fcf3ce44SJohn Forte * cmd table to find matching icmdp. Verify itt in hdr and 1704fcf3ce44SJohn Forte * icmdp are the same. 1705fcf3ce44SJohn Forte */ 1706fcf3ce44SJohn Forte static iscsi_status_t 1707fcf3ce44SJohn Forte iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp, 1708fcf3ce44SJohn Forte iscsi_cmd_t **icmdp) 1709fcf3ce44SJohn Forte { 1710fcf3ce44SJohn Forte int cmd_table_idx = 0; 1711fcf3ce44SJohn Forte 1712fcf3ce44SJohn Forte ASSERT(isp != NULL); 1713fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1714fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 1715fcf3ce44SJohn Forte ASSERT(mutex_owned(&isp->sess_cmdsn_mutex)); 1716fcf3ce44SJohn Forte 1717fcf3ce44SJohn Forte /* try to find an associated iscsi_pkt */ 171830e7468fSPeter Dunlap cmd_table_idx = (ihp->itt - IDM_TASKIDS_MAX) % ISCSI_CMD_TABLE_SIZE; 1719fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx] == NULL) { 1720fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) protocol error - " 1721fcf3ce44SJohn Forte "received unknown itt:0x%x - protocol error", 1722fcf3ce44SJohn Forte isp->sess_oid, ihp->itt); 1723fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 1724fcf3ce44SJohn Forte } 1725fcf3ce44SJohn Forte 1726fcf3ce44SJohn Forte /* verify itt */ 1727fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) { 1728fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x " 1729fcf3ce44SJohn Forte " which is out of sync with itt:0x%x", isp->sess_oid, 1730fcf3ce44SJohn Forte ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt); 1731fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 1732fcf3ce44SJohn Forte } 1733fcf3ce44SJohn Forte 173429e23f3fSandrew.rutz@sun.com /* ensure that icmdp is still in Active state */ 173529e23f3fSandrew.rutz@sun.com if (isp->sess_cmd_table[cmd_table_idx]->cmd_state != 173629e23f3fSandrew.rutz@sun.com ISCSI_CMD_STATE_ACTIVE) { 173729e23f3fSandrew.rutz@sun.com cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x " 173829e23f3fSandrew.rutz@sun.com "but icmdp (%p) is not in active state", 173929e23f3fSandrew.rutz@sun.com isp->sess_oid, ihp->itt, 174029e23f3fSandrew.rutz@sun.com (void *)isp->sess_cmd_table[cmd_table_idx]); 174129e23f3fSandrew.rutz@sun.com return (ISCSI_STATUS_INTERNAL_ERROR); 174229e23f3fSandrew.rutz@sun.com } 174329e23f3fSandrew.rutz@sun.com 1744fcf3ce44SJohn Forte /* make sure this is a SCSI cmd */ 1745fcf3ce44SJohn Forte *icmdp = isp->sess_cmd_table[cmd_table_idx]; 1746fcf3ce44SJohn Forte 1747fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1748fcf3ce44SJohn Forte } 1749fcf3ce44SJohn Forte 1750fcf3ce44SJohn Forte /* 1751fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1752fcf3ce44SJohn Forte * | End of protocol receive routines | 1753fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1754fcf3ce44SJohn Forte */ 1755fcf3ce44SJohn Forte 1756fcf3ce44SJohn Forte /* 1757fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1758fcf3ce44SJohn Forte * | Beginning of protocol send routines | 1759fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1760fcf3ce44SJohn Forte */ 1761fcf3ce44SJohn Forte 1762fcf3ce44SJohn Forte 1763fcf3ce44SJohn Forte /* 1764fcf3ce44SJohn Forte * iscsi_tx_thread - This thread is the driving point for all 176530e7468fSPeter Dunlap * iSCSI PDUs after login. No PDUs should call idm_pdu_tx() 1766fcf3ce44SJohn Forte * directly they should be funneled through iscsi_tx_thread. 1767fcf3ce44SJohn Forte */ 1768fcf3ce44SJohn Forte void 1769fcf3ce44SJohn Forte iscsi_tx_thread(iscsi_thread_t *thread, void *arg) 1770fcf3ce44SJohn Forte { 1771fcf3ce44SJohn Forte iscsi_conn_t *icp = (iscsi_conn_t *)arg; 1772fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1773fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1774fcf3ce44SJohn Forte clock_t tout; 1775fcf3ce44SJohn Forte int ret = 1; 1776fcf3ce44SJohn Forte 1777fcf3ce44SJohn Forte ASSERT(icp != NULL); 1778fcf3ce44SJohn Forte isp = icp->conn_sess; 1779fcf3ce44SJohn Forte ASSERT(isp != NULL); 1780fcf3ce44SJohn Forte ASSERT(thread != NULL); 1781fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD); 1782fcf3ce44SJohn Forte 1783fcf3ce44SJohn Forte tout = SEC_TO_TICK(1); 1784fcf3ce44SJohn Forte /* 1785fcf3ce44SJohn Forte * Transfer icmdps until shutdown by owning session. 1786fcf3ce44SJohn Forte */ 1787fcf3ce44SJohn Forte while (ret != 0) { 1788fcf3ce44SJohn Forte 1789fcf3ce44SJohn Forte isp->sess_window_open = B_TRUE; 1790fcf3ce44SJohn Forte /* 1791fcf3ce44SJohn Forte * While the window is open, there are commands available 1792fcf3ce44SJohn Forte * to send and the session state allows those commands to 1793fcf3ce44SJohn Forte * be sent try to transfer them. 1794fcf3ce44SJohn Forte */ 1795fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 1796fcf3ce44SJohn Forte while ((isp->sess_window_open == B_TRUE) && 1797904e51f6SJack Meng ((icmdp = isp->sess_queue_pending.head) != NULL)) { 1798904e51f6SJack Meng if (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) && 1799904e51f6SJack Meng (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) || 1800904e51f6SJack Meng (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN)) { 1801904e51f6SJack Meng 1802904e51f6SJack Meng /* update command with this connection info */ 1803904e51f6SJack Meng icmdp->cmd_conn = icp; 1804904e51f6SJack Meng /* attempt to send this command */ 1805904e51f6SJack Meng iscsi_cmd_state_machine(icmdp, 1806904e51f6SJack Meng ISCSI_CMD_EVENT_E2, isp); 1807fcf3ce44SJohn Forte 1808904e51f6SJack Meng ASSERT(!mutex_owned( 1809904e51f6SJack Meng &isp->sess_queue_pending.mutex)); 1810904e51f6SJack Meng mutex_enter(&isp->sess_queue_pending.mutex); 1811904e51f6SJack Meng } else { 1812904e51f6SJack Meng while (icmdp != NULL) { 1813904e51f6SJack Meng if ((icmdp->cmd_type != 1814904e51f6SJack Meng ISCSI_CMD_TYPE_SCSI) && 1815904e51f6SJack Meng (ISCSI_CONN_STATE_FULL_FEATURE 1816904e51f6SJack Meng (icp->conn_state) != B_TRUE)) { 1817904e51f6SJack Meng icmdp->cmd_misc_flags |= 1818904e51f6SJack Meng ISCSI_CMD_MISCFLAG_STUCK; 1819904e51f6SJack Meng } else if (icp->conn_state != 1820904e51f6SJack Meng ISCSI_CONN_STATE_LOGGED_IN) { 1821904e51f6SJack Meng icmdp->cmd_misc_flags |= 1822904e51f6SJack Meng ISCSI_CMD_MISCFLAG_STUCK; 1823904e51f6SJack Meng } 1824904e51f6SJack Meng icmdp = icmdp->cmd_next; 1825904e51f6SJack Meng } 1826904e51f6SJack Meng break; 1827904e51f6SJack Meng } 1828fcf3ce44SJohn Forte } 1829fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 1830fcf3ce44SJohn Forte 1831fcf3ce44SJohn Forte /* 1832fcf3ce44SJohn Forte * Go to sleep until there is something new 1833fcf3ce44SJohn Forte * to process (awoken via cv_boardcast). 1834fcf3ce44SJohn Forte * Or the timer goes off. 1835fcf3ce44SJohn Forte */ 1836fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, tout); 1837fcf3ce44SJohn Forte } 1838fcf3ce44SJohn Forte 1839fcf3ce44SJohn Forte } 1840fcf3ce44SJohn Forte 1841fcf3ce44SJohn Forte 1842fcf3ce44SJohn Forte /* 1843fcf3ce44SJohn Forte * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu 1844fcf3ce44SJohn Forte * 1845fcf3ce44SJohn Forte * Just prior to sending the command to the networking layer the 1846fcf3ce44SJohn Forte * pending queue lock will be dropped. At this point only local 1847fcf3ce44SJohn Forte * resources will be used, not the icmdp. Holding the queue lock 1848fcf3ce44SJohn Forte * across the networking call can lead to a hang. (This is due 1849fcf3ce44SJohn Forte * to the the target driver and networking layers competing use 1850fcf3ce44SJohn Forte * of the timeout() resources and the queue lock being held for 1851fcf3ce44SJohn Forte * both sides.) Upon the completion of this command the lock 1852fcf3ce44SJohn Forte * will have been re-acquired. 1853fcf3ce44SJohn Forte */ 1854fcf3ce44SJohn Forte iscsi_status_t 1855fcf3ce44SJohn Forte iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 1856fcf3ce44SJohn Forte { 1857fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR; 1858fcf3ce44SJohn Forte 1859fcf3ce44SJohn Forte ASSERT(isp != NULL); 1860fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 1861fcf3ce44SJohn Forte 1862fcf3ce44SJohn Forte /* transfer specific command type */ 1863fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1864fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_SCSI: 1865fcf3ce44SJohn Forte rval = iscsi_tx_scsi(isp, icmdp); 1866fcf3ce44SJohn Forte break; 1867fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_NOP: 1868fcf3ce44SJohn Forte rval = iscsi_tx_nop(isp, icmdp); 1869fcf3ce44SJohn Forte break; 1870fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1871fcf3ce44SJohn Forte rval = iscsi_tx_abort(isp, icmdp); 1872fcf3ce44SJohn Forte break; 1873fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1874fcf3ce44SJohn Forte rval = iscsi_tx_reset(isp, icmdp); 1875fcf3ce44SJohn Forte break; 1876fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_LOGOUT: 1877fcf3ce44SJohn Forte rval = iscsi_tx_logout(isp, icmdp); 1878fcf3ce44SJohn Forte break; 1879fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_TEXT: 1880fcf3ce44SJohn Forte rval = iscsi_tx_text(isp, icmdp); 1881fcf3ce44SJohn Forte break; 1882fcf3ce44SJohn Forte default: 188330e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi_tx_cmd: invalid cmdtype: %d", 188430e7468fSPeter Dunlap icmdp->cmd_type); 1885fcf3ce44SJohn Forte ASSERT(FALSE); 1886fcf3ce44SJohn Forte } 1887fcf3ce44SJohn Forte 1888fcf3ce44SJohn Forte ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex)); 1889fcf3ce44SJohn Forte return (rval); 1890fcf3ce44SJohn Forte } 1891fcf3ce44SJohn Forte 1892fcf3ce44SJohn Forte /* 1893fcf3ce44SJohn Forte * a variable length cdb can be up to 16K, but we obviously don't want 1894fcf3ce44SJohn Forte * to put that on the stack; go with 200 bytes; if we get something 1895fcf3ce44SJohn Forte * bigger than that we will kmem_alloc a buffer 1896fcf3ce44SJohn Forte */ 1897fcf3ce44SJohn Forte #define DEF_CDB_LEN 200 1898fcf3ce44SJohn Forte 1899fcf3ce44SJohn Forte /* 1900fcf3ce44SJohn Forte * given the size of the cdb, return how many bytes the header takes, 1901fcf3ce44SJohn Forte * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes 1902fcf3ce44SJohn Forte * stored in the basic header, minus sizeof (ahs_extscb) 1903fcf3ce44SJohn Forte */ 1904fcf3ce44SJohn Forte #define ADDLHDRSZ(x) (sizeof (iscsi_addl_hdr_t) + (x) - \ 1905fcf3ce44SJohn Forte 16 - 4) 1906fcf3ce44SJohn Forte 190730e7468fSPeter Dunlap static void 190830e7468fSPeter Dunlap iscsi_tx_init_hdr(iscsi_sess_t *isp, iscsi_conn_t *icp, 19092b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_text_hdr_t *ihp, int opcode, iscsi_cmd_t *icmdp) 1910fcf3ce44SJohn Forte { 191130e7468fSPeter Dunlap ihp->opcode = opcode; 19122b79d384Sbing zhao - Sun Microsystems - Beijing China ihp->itt = icmdp->cmd_itt; 1913fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 19142b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn; 1915fcf3ce44SJohn Forte ihp->cmdsn = htonl(isp->sess_cmdsn); 1916fcf3ce44SJohn Forte isp->sess_cmdsn++; 1917fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1918fcf3ce44SJohn Forte ihp->expstatsn = htonl(icp->conn_expstatsn); 1919fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 192030e7468fSPeter Dunlap } 1921fcf3ce44SJohn Forte 1922fcf3ce44SJohn Forte 192330e7468fSPeter Dunlap static void 192430e7468fSPeter Dunlap iscsi_tx_scsi_data(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp, 192530e7468fSPeter Dunlap iscsi_conn_t *icp, idm_pdu_t *pdu) 192630e7468fSPeter Dunlap { 192730e7468fSPeter Dunlap struct buf *bp = NULL; 192830e7468fSPeter Dunlap size_t buflen = 0; 192930e7468fSPeter Dunlap uint32_t first_burst_length = 0; 193030e7468fSPeter Dunlap struct scsi_pkt *pkt; 193130e7468fSPeter Dunlap 193230e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 1933fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 1934fcf3ce44SJohn Forte if ((bp != NULL) && bp->b_bcount) { 1935fcf3ce44SJohn Forte buflen = bp->b_bcount; 193630e7468fSPeter Dunlap first_burst_length = 193730e7468fSPeter Dunlap icp->conn_params.first_burst_length; 1938fcf3ce44SJohn Forte 1939fcf3ce44SJohn Forte if (bp->b_flags & B_READ) { 1940fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL; 1941fcf3ce44SJohn Forte /* 1942fcf3ce44SJohn Forte * fix problem where OS sends bp (B_READ & 1943fcf3ce44SJohn Forte * b_bcount!=0) for a TUR or START_STOP. 1944fcf3ce44SJohn Forte * (comment came from cisco code.) 1945fcf3ce44SJohn Forte */ 1946fcf3ce44SJohn Forte if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) && 1947fcf3ce44SJohn Forte (pkt->pkt_cdbp[0] != SCMD_START_STOP)) { 1948fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_CMD_READ; 1949fcf3ce44SJohn Forte ihp->data_length = htonl(buflen); 1950fcf3ce44SJohn Forte } 1951fcf3ce44SJohn Forte } else { 1952fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_CMD_WRITE; 1953fcf3ce44SJohn Forte /* 1954fcf3ce44SJohn Forte * FinalBit on the the iSCSI PDU denotes this 1955fcf3ce44SJohn Forte * is the last PDU in the sequence. 1956fcf3ce44SJohn Forte * 1957fcf3ce44SJohn Forte * initial_r2t = true means R2T is required 1958fcf3ce44SJohn Forte * for additional PDU, so there will be no more 1959fcf3ce44SJohn Forte * unsolicited PDUs following 1960fcf3ce44SJohn Forte */ 1961fcf3ce44SJohn Forte if (icp->conn_params.initial_r2t) { 1962fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL; 1963fcf3ce44SJohn Forte } 1964fcf3ce44SJohn Forte 1965fcf3ce44SJohn Forte /* Check if we should send ImmediateData */ 1966fcf3ce44SJohn Forte if (icp->conn_params.immediate_data) { 196730e7468fSPeter Dunlap pdu->isp_data = 196830e7468fSPeter Dunlap (uint8_t *)icmdp-> 196930e7468fSPeter Dunlap cmd_un.scsi.bp->b_un.b_addr; 197030e7468fSPeter Dunlap 197130e7468fSPeter Dunlap pdu->isp_datalen = MIN(MIN(buflen, 1972fcf3ce44SJohn Forte first_burst_length), 1973fcf3ce44SJohn Forte icmdp->cmd_conn->conn_params. 1974fcf3ce44SJohn Forte max_xmit_data_seg_len); 1975fcf3ce44SJohn Forte 1976fcf3ce44SJohn Forte /* 1977fcf3ce44SJohn Forte * if everything fits immediate, or 1978fcf3ce44SJohn Forte * we can send all burst data immediate 1979fcf3ce44SJohn Forte * (not unsol), set F 1980fcf3ce44SJohn Forte */ 198130e7468fSPeter Dunlap /* 198230e7468fSPeter Dunlap * XXX This doesn't look right -- it's not 198330e7468fSPeter Dunlap * clear how we can handle transmitting 198430e7468fSPeter Dunlap * any unsolicited data. It looks like 198530e7468fSPeter Dunlap * we only support immediate data. So what 198630e7468fSPeter Dunlap * happens if we don't set ISCSI_FLAG_FINAL? 198730e7468fSPeter Dunlap * 198830e7468fSPeter Dunlap * Unless there's magic code somewhere that 198930e7468fSPeter Dunlap * is sending the remaining PDU's we should 199030e7468fSPeter Dunlap * simply set ISCSI_FLAG_FINAL and forget 199130e7468fSPeter Dunlap * about sending unsolicited data. The big 199230e7468fSPeter Dunlap * win is the immediate data anyway for small 199330e7468fSPeter Dunlap * PDU's. 199430e7468fSPeter Dunlap */ 199530e7468fSPeter Dunlap if ((pdu->isp_datalen == buflen) || 199630e7468fSPeter Dunlap (pdu->isp_datalen == first_burst_length)) { 1997fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL; 1998fcf3ce44SJohn Forte } 1999fcf3ce44SJohn Forte 200030e7468fSPeter Dunlap hton24(ihp->dlength, pdu->isp_datalen); 2001fcf3ce44SJohn Forte } 2002fcf3ce44SJohn Forte /* total data transfer length */ 2003fcf3ce44SJohn Forte ihp->data_length = htonl(buflen); 2004fcf3ce44SJohn Forte } 2005fcf3ce44SJohn Forte } else { 2006fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL; 2007fcf3ce44SJohn Forte } 200830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred += pdu->isp_datalen; 200930e7468fSPeter Dunlap /* XXX How is this different from the code above? */ 201030e7468fSPeter Dunlap /* will idm send the next data command up to burst length? */ 201130e7468fSPeter Dunlap /* send the burstlen if we haven't sent immediate data */ 201230e7468fSPeter Dunlap /* CRM: should idm send difference min(buflen, first_burst) and imm? */ 201330e7468fSPeter Dunlap /* (MIN(first_burst_length, buflen) - imdata > 0) */ 201430e7468fSPeter Dunlap /* CRM_LATER: change this to generate unsolicited pdu */ 201530e7468fSPeter Dunlap if ((buflen > 0) && 201630e7468fSPeter Dunlap ((bp->b_flags & B_READ) == 0) && 201730e7468fSPeter Dunlap (icp->conn_params.initial_r2t == 0) && 201830e7468fSPeter Dunlap pdu->isp_datalen == 0) { 201930e7468fSPeter Dunlap 202030e7468fSPeter Dunlap pdu->isp_datalen = MIN(first_burst_length, buflen); 202130e7468fSPeter Dunlap if ((pdu->isp_datalen == buflen) || 202230e7468fSPeter Dunlap (pdu->isp_datalen == first_burst_length)) { 202330e7468fSPeter Dunlap ihp->flags |= ISCSI_FLAG_FINAL; 202430e7468fSPeter Dunlap } 202530e7468fSPeter Dunlap pdu->isp_data = (uint8_t *)icmdp->cmd_un.scsi.bp->b_un.b_addr; 202630e7468fSPeter Dunlap hton24(ihp->dlength, pdu->isp_datalen); 202730e7468fSPeter Dunlap } 202830e7468fSPeter Dunlap } 202930e7468fSPeter Dunlap 203030e7468fSPeter Dunlap static void 203130e7468fSPeter Dunlap iscsi_tx_scsi_init_pkt(iscsi_cmd_t *icmdp, iscsi_scsi_cmd_hdr_t *ihp) 203230e7468fSPeter Dunlap { 203330e7468fSPeter Dunlap struct scsi_pkt *pkt; 203430e7468fSPeter Dunlap 203530e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 203630e7468fSPeter Dunlap pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET); 203730e7468fSPeter Dunlap pkt->pkt_reason = CMD_INCOMPLETE; 2038fcf3ce44SJohn Forte 2039fcf3ce44SJohn Forte /* tagged queuing */ 2040fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_HTAG) { 2041fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE; 2042fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_OTAG) { 2043fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_ORDERED; 2044fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_STAG) { 2045fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_SIMPLE; 2046fcf3ce44SJohn Forte } else { 2047fcf3ce44SJohn Forte /* ihp->flags |= ISCSI_ATTR_UNTAGGED; */ 2048fcf3ce44SJohn Forte /* EMPTY */ 2049fcf3ce44SJohn Forte } 2050fcf3ce44SJohn Forte 2051fcf3ce44SJohn Forte /* iscsi states lun is based on spc.2 */ 2052fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun); 2053fcf3ce44SJohn Forte 2054fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.cmdlen <= 16) { 2055fcf3ce44SJohn Forte /* copy the SCSI Command Block into the PDU */ 2056fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb, 2057fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen); 2058fcf3ce44SJohn Forte } else { 2059fcf3ce44SJohn Forte iscsi_addl_hdr_t *iahp; 2060fcf3ce44SJohn Forte 2061fcf3ce44SJohn Forte iahp = (iscsi_addl_hdr_t *)ihp; 2062fcf3ce44SJohn Forte 2063fcf3ce44SJohn Forte ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) - 2064fcf3ce44SJohn Forte sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4; 2065fcf3ce44SJohn Forte iahp->ahs_hlen_hi = 0; 2066fcf3ce44SJohn Forte iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15); 2067fcf3ce44SJohn Forte iahp->ahs_key = 0x01; 2068fcf3ce44SJohn Forte iahp->ahs_resv = 0; 2069fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb, 16); 207030e7468fSPeter Dunlap bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0], 207130e7468fSPeter Dunlap icmdp->cmd_un.scsi.cmdlen); 2072fcf3ce44SJohn Forte } 2073fcf3ce44SJohn Forte 207430e7468fSPeter Dunlap /* 207530e7468fSPeter Dunlap * Update all values before transfering. 207630e7468fSPeter Dunlap * We should never touch the icmdp after 207730e7468fSPeter Dunlap * transfering if there is no more data 207830e7468fSPeter Dunlap * to send. The only case the idm_pdu_tx() 207930e7468fSPeter Dunlap * will fail is a on a connection disconnect 208030e7468fSPeter Dunlap * in that case the command will be flushed. 208130e7468fSPeter Dunlap */ 208230e7468fSPeter Dunlap pkt->pkt_state |= STATE_SENT_CMD; 2083fcf3ce44SJohn Forte } 2084fcf3ce44SJohn Forte 208530e7468fSPeter Dunlap static void 208630e7468fSPeter Dunlap iscsi_tx_scsi_init_task(iscsi_cmd_t *icmdp, iscsi_conn_t *icp, 208730e7468fSPeter Dunlap iscsi_scsi_cmd_hdr_t *ihp) 2088fcf3ce44SJohn Forte { 208930e7468fSPeter Dunlap idm_task_t *itp; 209030e7468fSPeter Dunlap struct buf *bp = NULL; 209130e7468fSPeter Dunlap uint32_t data_length; 2092fcf3ce44SJohn Forte 209330e7468fSPeter Dunlap bp = icmdp->cmd_un.scsi.bp; 2094fcf3ce44SJohn Forte 209530e7468fSPeter Dunlap itp = icmdp->cmd_itp; 209630e7468fSPeter Dunlap ASSERT(itp != NULL); 209730e7468fSPeter Dunlap data_length = ntohl(ihp->data_length); 209830e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 209930e7468fSPeter Dunlap "DEBUG: iscsi_tx_init_task: task_start: %p idt_tt: %x cmdsn: %x " 210030e7468fSPeter Dunlap "sess_cmdsn: %x cmd: %p " 210130e7468fSPeter Dunlap "cmdtype: %d datalen: %u", 210230e7468fSPeter Dunlap (void *)itp, itp->idt_tt, ihp->cmdsn, icp->conn_sess->sess_cmdsn, 210330e7468fSPeter Dunlap (void *)icmdp, icmdp->cmd_type, data_length); 210430e7468fSPeter Dunlap if (data_length > 0) { 210530e7468fSPeter Dunlap if (bp->b_flags & B_READ) { 210630e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_ibuf = 210730e7468fSPeter Dunlap idm_buf_alloc(icp->conn_ic, 210830e7468fSPeter Dunlap bp->b_un.b_addr, bp->b_bcount); 210930e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.ibp_ibuf) 211030e7468fSPeter Dunlap idm_buf_bind_in(itp, 211130e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_ibuf); 211230e7468fSPeter Dunlap } else { 211330e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_obuf = 211430e7468fSPeter Dunlap idm_buf_alloc(icp->conn_ic, 211530e7468fSPeter Dunlap bp->b_un.b_addr, bp->b_bcount); 211630e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.ibp_obuf) 211730e7468fSPeter Dunlap idm_buf_bind_out(itp, 211830e7468fSPeter Dunlap icmdp->cmd_un.scsi.ibp_obuf); 211930e7468fSPeter Dunlap } 212030e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, 212130e7468fSPeter Dunlap "DEBUG: pdu_tx: task_start(%s): %p ic: %p idt_tt: %x " 212230e7468fSPeter Dunlap "cmdsn: %x sess_cmdsn: %x sess_expcmdsn: %x obuf: %p " 212330e7468fSPeter Dunlap "cmdp: %p cmdtype: %d " 212430e7468fSPeter Dunlap "buflen: %lu " "bpaddr: %p datalen: %u ", 212530e7468fSPeter Dunlap bp->b_flags & B_READ ? "B_READ" : "B_WRITE", 212630e7468fSPeter Dunlap (void *)itp, (void *)icp->conn_ic, 212730e7468fSPeter Dunlap itp->idt_tt, ihp->cmdsn, 212830e7468fSPeter Dunlap icp->conn_sess->sess_cmdsn, 212930e7468fSPeter Dunlap icp->conn_sess->sess_expcmdsn, 213030e7468fSPeter Dunlap (void *)icmdp->cmd_un.scsi.ibp_ibuf, 213130e7468fSPeter Dunlap (void *)icmdp, icmdp->cmd_type, bp->b_bcount, 213230e7468fSPeter Dunlap (void *)bp->b_un.b_addr, 213330e7468fSPeter Dunlap data_length); 213430e7468fSPeter Dunlap } 2135fcf3ce44SJohn Forte 2136fcf3ce44SJohn Forte /* 213730e7468fSPeter Dunlap * Task is now active 2138fcf3ce44SJohn Forte */ 213930e7468fSPeter Dunlap idm_task_start(itp, ISCSI_INI_TASK_TTT); 2140fcf3ce44SJohn Forte } 2141fcf3ce44SJohn Forte 2142fcf3ce44SJohn Forte /* 214330e7468fSPeter Dunlap * iscsi_tx_scsi - 214430e7468fSPeter Dunlap * 2145fcf3ce44SJohn Forte */ 2146fcf3ce44SJohn Forte static iscsi_status_t 214730e7468fSPeter Dunlap iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2148fcf3ce44SJohn Forte { 2149fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 215030e7468fSPeter Dunlap iscsi_conn_t *icp = NULL; 215130e7468fSPeter Dunlap struct scsi_pkt *pkt = NULL; 215230e7468fSPeter Dunlap iscsi_scsi_cmd_hdr_t *ihp = NULL; 215330e7468fSPeter Dunlap int cdblen = 0; 215430e7468fSPeter Dunlap idm_pdu_t *pdu; 215530e7468fSPeter Dunlap int len; 2156fcf3ce44SJohn Forte 2157fcf3ce44SJohn Forte ASSERT(isp != NULL); 2158fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2159fcf3ce44SJohn Forte 216030e7468fSPeter Dunlap pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP); 216130e7468fSPeter Dunlap 216230e7468fSPeter Dunlap pkt = icmdp->cmd_un.scsi.pkt; 216330e7468fSPeter Dunlap ASSERT(pkt != NULL); 216430e7468fSPeter Dunlap icp = icmdp->cmd_conn; 216530e7468fSPeter Dunlap ASSERT(icp != NULL); 216630e7468fSPeter Dunlap 216730e7468fSPeter Dunlap /* Reset counts in case we are on a retry */ 216830e7468fSPeter Dunlap icmdp->cmd_un.scsi.data_transferred = 0; 216930e7468fSPeter Dunlap 217030e7468fSPeter Dunlap if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) { 217130e7468fSPeter Dunlap cdblen = icmdp->cmd_un.scsi.cmdlen; 217230e7468fSPeter Dunlap ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP); 217330e7468fSPeter Dunlap len = ADDLHDRSZ(cdblen); 217430e7468fSPeter Dunlap } else { 217530e7468fSPeter Dunlap /* 217630e7468fSPeter Dunlap * only bzero the basic header; the additional header 217730e7468fSPeter Dunlap * will be set up correctly later, if needed 217830e7468fSPeter Dunlap */ 217930e7468fSPeter Dunlap ihp = kmem_zalloc(sizeof (iscsi_scsi_cmd_hdr_t), KM_SLEEP); 218030e7468fSPeter Dunlap len = sizeof (iscsi_scsi_cmd_hdr_t); 2181fcf3ce44SJohn Forte } 2182fcf3ce44SJohn Forte 218330e7468fSPeter Dunlap iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ihp, 21842b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_OP_SCSI_CMD, icmdp); 218530e7468fSPeter Dunlap 218630e7468fSPeter Dunlap idm_pdu_init(pdu, icp->conn_ic, (void *)icmdp, &iscsi_tx_done); 218730e7468fSPeter Dunlap idm_pdu_init_hdr(pdu, (uint8_t *)ihp, len); 218830e7468fSPeter Dunlap pdu->isp_data = NULL; 218930e7468fSPeter Dunlap pdu->isp_datalen = 0; 2190fcf3ce44SJohn Forte 2191fcf3ce44SJohn Forte /* 219230e7468fSPeter Dunlap * Sestion 12.11 of the iSCSI specification has a good table 219330e7468fSPeter Dunlap * describing when uncolicited data and/or immediate data 219430e7468fSPeter Dunlap * should be sent. 2195fcf3ce44SJohn Forte */ 2196fcf3ce44SJohn Forte 219730e7468fSPeter Dunlap iscsi_tx_scsi_data(icmdp, ihp, icp, pdu); 219830e7468fSPeter Dunlap 219930e7468fSPeter Dunlap iscsi_tx_scsi_init_pkt(icmdp, ihp); 220030e7468fSPeter Dunlap 220130e7468fSPeter Dunlap /* Calls idm_task_start */ 220230e7468fSPeter Dunlap iscsi_tx_scsi_init_task(icmdp, icp, ihp); 220330e7468fSPeter Dunlap 2204fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2205fcf3ce44SJohn Forte 220630e7468fSPeter Dunlap idm_pdu_tx(pdu); 2207fcf3ce44SJohn Forte 22082b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT; 22092b79d384Sbing zhao - Sun Microsystems - Beijing China 221030e7468fSPeter Dunlap return (rval); 221130e7468fSPeter Dunlap } 2212fcf3ce44SJohn Forte 2213fcf3ce44SJohn Forte 221430e7468fSPeter Dunlap /* ARGSUSED */ 221530e7468fSPeter Dunlap static void 221630e7468fSPeter Dunlap iscsi_tx_done(idm_pdu_t *pdu, idm_status_t status) 221730e7468fSPeter Dunlap { 221830e7468fSPeter Dunlap kmem_free((iscsi_hdr_t *)pdu->isp_hdr, pdu->isp_hdrlen); 221930e7468fSPeter Dunlap kmem_free(pdu, sizeof (idm_pdu_t)); 222030e7468fSPeter Dunlap } 2221fcf3ce44SJohn Forte 2222fcf3ce44SJohn Forte 222330e7468fSPeter Dunlap static void 222430e7468fSPeter Dunlap iscsi_tx_pdu(iscsi_conn_t *icp, int opcode, void *hdr, int hdrlen, 222530e7468fSPeter Dunlap iscsi_cmd_t *icmdp) 222630e7468fSPeter Dunlap { 222730e7468fSPeter Dunlap idm_pdu_t *tx_pdu; 222830e7468fSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)hdr; 2229fcf3ce44SJohn Forte 223030e7468fSPeter Dunlap tx_pdu = kmem_zalloc(sizeof (idm_pdu_t), KM_SLEEP); 223130e7468fSPeter Dunlap ASSERT(tx_pdu != NULL); 2232fcf3ce44SJohn Forte 223330e7468fSPeter Dunlap idm_pdu_init(tx_pdu, icp->conn_ic, icmdp, &iscsi_tx_done); 223430e7468fSPeter Dunlap idm_pdu_init_hdr(tx_pdu, hdr, hdrlen); 223530e7468fSPeter Dunlap if (opcode == ISCSI_OP_TEXT_CMD) { 223630e7468fSPeter Dunlap idm_pdu_init_data(tx_pdu, 223730e7468fSPeter Dunlap (uint8_t *)icmdp->cmd_un.text.buf, 223830e7468fSPeter Dunlap ntoh24(ihp->dlength)); 2239fcf3ce44SJohn Forte } 2240fcf3ce44SJohn Forte 224130e7468fSPeter Dunlap mutex_exit(&icp->conn_sess->sess_queue_pending.mutex); 224230e7468fSPeter Dunlap idm_pdu_tx(tx_pdu); 22432b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_SENT; 2244fcf3ce44SJohn Forte } 2245fcf3ce44SJohn Forte 2246fcf3ce44SJohn Forte 2247fcf3ce44SJohn Forte /* 2248fcf3ce44SJohn Forte * iscsi_tx_nop - 2249fcf3ce44SJohn Forte * 2250fcf3ce44SJohn Forte */ 2251fcf3ce44SJohn Forte static iscsi_status_t 2252fcf3ce44SJohn Forte iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2253fcf3ce44SJohn Forte { 2254fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2255fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 225630e7468fSPeter Dunlap iscsi_nop_out_hdr_t *inohp; 2257fcf3ce44SJohn Forte 2258fcf3ce44SJohn Forte ASSERT(isp != NULL); 2259fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2260fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2261fcf3ce44SJohn Forte ASSERT(icp != NULL); 2262fcf3ce44SJohn Forte 226330e7468fSPeter Dunlap inohp = kmem_zalloc(sizeof (iscsi_nop_out_hdr_t), KM_SLEEP); 226430e7468fSPeter Dunlap ASSERT(inohp != NULL); 226530e7468fSPeter Dunlap 226630e7468fSPeter Dunlap inohp->opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; 226730e7468fSPeter Dunlap inohp->flags = ISCSI_FLAG_FINAL; 226830e7468fSPeter Dunlap inohp->itt = icmdp->cmd_itt; 226930e7468fSPeter Dunlap inohp->ttt = icmdp->cmd_ttt; 2270fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 22712b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn; 227230e7468fSPeter Dunlap inohp->cmdsn = htonl(isp->sess_cmdsn); 2273fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 227430e7468fSPeter Dunlap inohp->expstatsn = htonl(icp->conn_expstatsn); 2275fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 227630e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_NOOP_OUT, inohp, 227730e7468fSPeter Dunlap sizeof (iscsi_nop_out_hdr_t), icmdp); 2278fcf3ce44SJohn Forte return (rval); 2279fcf3ce44SJohn Forte } 2280fcf3ce44SJohn Forte 2281fcf3ce44SJohn Forte 2282fcf3ce44SJohn Forte /* 2283fcf3ce44SJohn Forte * iscsi_tx_abort - 2284fcf3ce44SJohn Forte * 2285fcf3ce44SJohn Forte */ 2286fcf3ce44SJohn Forte static iscsi_status_t 2287fcf3ce44SJohn Forte iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2288fcf3ce44SJohn Forte { 2289fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2290fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 229130e7468fSPeter Dunlap iscsi_scsi_task_mgt_hdr_t *istmh; 2292fcf3ce44SJohn Forte 2293fcf3ce44SJohn Forte ASSERT(isp != NULL); 2294fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2295fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2296fcf3ce44SJohn Forte ASSERT(icp != NULL); 2297fcf3ce44SJohn Forte 229830e7468fSPeter Dunlap istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP); 229930e7468fSPeter Dunlap ASSERT(istmh != NULL); 2300fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 23012b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn; 230230e7468fSPeter Dunlap istmh->cmdsn = htonl(isp->sess_cmdsn); 2303fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 230430e7468fSPeter Dunlap istmh->expstatsn = htonl(icp->conn_expstatsn); 2305fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 230630e7468fSPeter Dunlap istmh->itt = icmdp->cmd_itt; 230730e7468fSPeter Dunlap istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE; 230830e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK; 230930e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(istmh->lun, 2310fcf3ce44SJohn Forte icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun); 231130e7468fSPeter Dunlap istmh->rtt = icmdp->cmd_un.abort.icmdp->cmd_itt; 231230e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh, 231330e7468fSPeter Dunlap sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp); 2314fcf3ce44SJohn Forte 2315fcf3ce44SJohn Forte return (rval); 2316fcf3ce44SJohn Forte } 2317fcf3ce44SJohn Forte 2318fcf3ce44SJohn Forte 2319fcf3ce44SJohn Forte /* 2320fcf3ce44SJohn Forte * iscsi_tx_reset - 2321fcf3ce44SJohn Forte * 2322fcf3ce44SJohn Forte */ 2323fcf3ce44SJohn Forte static iscsi_status_t 2324fcf3ce44SJohn Forte iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2325fcf3ce44SJohn Forte { 2326fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2327fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 232830e7468fSPeter Dunlap iscsi_scsi_task_mgt_hdr_t *istmh; 2329fcf3ce44SJohn Forte 2330fcf3ce44SJohn Forte ASSERT(isp != NULL); 2331fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2332fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2333fcf3ce44SJohn Forte ASSERT(icp != NULL); 2334fcf3ce44SJohn Forte 233530e7468fSPeter Dunlap istmh = kmem_zalloc(sizeof (iscsi_scsi_task_mgt_hdr_t), KM_SLEEP); 233630e7468fSPeter Dunlap ASSERT(istmh != NULL); 233730e7468fSPeter Dunlap istmh->opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE; 2338fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 23392b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn; 234030e7468fSPeter Dunlap istmh->cmdsn = htonl(isp->sess_cmdsn); 2341fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 234230e7468fSPeter Dunlap istmh->expstatsn = htonl(icp->conn_expstatsn); 234330e7468fSPeter Dunlap istmh->itt = icmdp->cmd_itt; 2344fcf3ce44SJohn Forte 2345fcf3ce44SJohn Forte switch (icmdp->cmd_un.reset.level) { 2346fcf3ce44SJohn Forte case RESET_LUN: 234730e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL | 2348fcf3ce44SJohn Forte ISCSI_TM_FUNC_LOGICAL_UNIT_RESET; 234930e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(istmh->lun, icmdp->cmd_lun->lun_num); 2350fcf3ce44SJohn Forte break; 2351fcf3ce44SJohn Forte case RESET_TARGET: 2352fcf3ce44SJohn Forte case RESET_BUS: 235330e7468fSPeter Dunlap istmh->function = ISCSI_FLAG_FINAL | 2354fcf3ce44SJohn Forte ISCSI_TM_FUNC_TARGET_WARM_RESET; 2355fcf3ce44SJohn Forte break; 2356fcf3ce44SJohn Forte default: 2357fcf3ce44SJohn Forte /* unsupported / unknown level */ 2358fcf3ce44SJohn Forte ASSERT(FALSE); 2359fcf3ce44SJohn Forte break; 2360fcf3ce44SJohn Forte } 2361fcf3ce44SJohn Forte 236230e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_SCSI_TASK_MGT_MSG, istmh, 236330e7468fSPeter Dunlap sizeof (iscsi_scsi_task_mgt_hdr_t), icmdp); 2364fcf3ce44SJohn Forte 2365fcf3ce44SJohn Forte return (rval); 2366fcf3ce44SJohn Forte } 2367fcf3ce44SJohn Forte 2368fcf3ce44SJohn Forte 2369fcf3ce44SJohn Forte /* 2370fcf3ce44SJohn Forte * iscsi_tx_logout - 2371fcf3ce44SJohn Forte * 2372fcf3ce44SJohn Forte */ 2373fcf3ce44SJohn Forte static iscsi_status_t 2374fcf3ce44SJohn Forte iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2375fcf3ce44SJohn Forte { 2376fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2377fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 237830e7468fSPeter Dunlap iscsi_logout_hdr_t *ilh; 2379fcf3ce44SJohn Forte 2380fcf3ce44SJohn Forte ASSERT(isp != NULL); 2381fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2382fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2383fcf3ce44SJohn Forte ASSERT(icp != NULL); 2384fcf3ce44SJohn Forte 238530e7468fSPeter Dunlap ilh = kmem_zalloc(sizeof (iscsi_logout_hdr_t), KM_SLEEP); 238630e7468fSPeter Dunlap ilh->opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE; 238730e7468fSPeter Dunlap ilh->flags = ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION; 238830e7468fSPeter Dunlap ilh->itt = icmdp->cmd_itt; 238930e7468fSPeter Dunlap ilh->cid = icp->conn_cid; 2390fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 23912b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_sn = isp->sess_cmdsn; 239230e7468fSPeter Dunlap ilh->cmdsn = htonl(isp->sess_cmdsn); 2393fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 239430e7468fSPeter Dunlap ilh->expstatsn = htonl(icp->conn_expstatsn); 239530e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_LOGOUT_CMD, ilh, 239630e7468fSPeter Dunlap sizeof (iscsi_logout_hdr_t), icmdp); 2397fcf3ce44SJohn Forte 2398fcf3ce44SJohn Forte return (rval); 2399fcf3ce44SJohn Forte } 2400fcf3ce44SJohn Forte 2401fcf3ce44SJohn Forte /* 2402fcf3ce44SJohn Forte * iscsi_tx_text - setup iSCSI text request header and send PDU with 2403fcf3ce44SJohn Forte * data given in the buffer attached to the command. For a single 2404fcf3ce44SJohn Forte * text request, the target may need to send its response in multiple 2405fcf3ce44SJohn Forte * text response. In this case, empty text requests are sent after 2406fcf3ce44SJohn Forte * each received response to notify the target the initiator is ready 2407fcf3ce44SJohn Forte * for more response. For the initial request, the data_len field in 2408fcf3ce44SJohn Forte * the text specific portion of a command is set to the amount of data 2409fcf3ce44SJohn Forte * the initiator wants to send as part of the request. If additional 2410fcf3ce44SJohn Forte * empty text requests are required for long responses, the data_len 2411fcf3ce44SJohn Forte * field is set to 0 by the iscsi_handle_text function. 2412fcf3ce44SJohn Forte */ 2413fcf3ce44SJohn Forte static iscsi_status_t 2414fcf3ce44SJohn Forte iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2415fcf3ce44SJohn Forte { 2416fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2417fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 241830e7468fSPeter Dunlap iscsi_text_hdr_t *ith; 2419fcf3ce44SJohn Forte 2420fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2421fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2422fcf3ce44SJohn Forte ASSERT(icp != NULL); 2423fcf3ce44SJohn Forte 242430e7468fSPeter Dunlap ith = kmem_zalloc(sizeof (iscsi_text_hdr_t), KM_SLEEP); 242530e7468fSPeter Dunlap ASSERT(ith != NULL); 242630e7468fSPeter Dunlap ith->flags = ISCSI_FLAG_FINAL; 242730e7468fSPeter Dunlap hton24(ith->dlength, icmdp->cmd_un.text.data_len); 242830e7468fSPeter Dunlap ith->ttt = icmdp->cmd_un.text.ttt; 242930e7468fSPeter Dunlap iscsi_tx_init_hdr(isp, icp, (iscsi_text_hdr_t *)ith, 24302b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_OP_TEXT_CMD, icmdp); 243130e7468fSPeter Dunlap bcopy(icmdp->cmd_un.text.lun, ith->rsvd4, sizeof (ith->rsvd4)); 2432fcf3ce44SJohn Forte 243330e7468fSPeter Dunlap iscsi_tx_pdu(icp, ISCSI_OP_TEXT_CMD, ith, sizeof (iscsi_text_hdr_t), 243430e7468fSPeter Dunlap icmdp); 2435fcf3ce44SJohn Forte 2436fcf3ce44SJohn Forte return (rval); 2437fcf3ce44SJohn Forte } 2438fcf3ce44SJohn Forte 2439fcf3ce44SJohn Forte /* 2440fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2441fcf3ce44SJohn Forte * | End of protocol send routines | 2442fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2443fcf3ce44SJohn Forte */ 2444fcf3ce44SJohn Forte 2445fcf3ce44SJohn Forte /* 2446fcf3ce44SJohn Forte * iscsi_handle_abort - 2447fcf3ce44SJohn Forte * 2448fcf3ce44SJohn Forte */ 2449fcf3ce44SJohn Forte void 2450fcf3ce44SJohn Forte iscsi_handle_abort(void *arg) 2451fcf3ce44SJohn Forte { 2452fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 2453fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = (iscsi_cmd_t *)arg; 2454fcf3ce44SJohn Forte iscsi_cmd_t *new_icmdp; 2455fcf3ce44SJohn Forte iscsi_conn_t *icp; 2456fcf3ce44SJohn Forte 2457fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2458fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2459fcf3ce44SJohn Forte ASSERT(icp != NULL); 2460fcf3ce44SJohn Forte isp = icp->conn_sess; 2461fcf3ce44SJohn Forte ASSERT(isp != NULL); 2462fcf3ce44SJohn Forte 2463fcf3ce44SJohn Forte /* there should only be one abort */ 2464fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL); 2465fcf3ce44SJohn Forte 2466fcf3ce44SJohn Forte new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 24672b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_type = ISCSI_CMD_TYPE_ABORT; 24682b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_lun = icmdp->cmd_lun; 24692b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_un.abort.icmdp = icmdp; 24702b79d384Sbing zhao - Sun Microsystems - Beijing China new_icmdp->cmd_conn = icmdp->cmd_conn; 24712b79d384Sbing zhao - Sun Microsystems - Beijing China icmdp->cmd_un.scsi.abort_icmdp = new_icmdp; 2472fcf3ce44SJohn Forte 2473fcf3ce44SJohn Forte /* pending queue mutex is already held by timeout_checks */ 2474fcf3ce44SJohn Forte iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp); 2475fcf3ce44SJohn Forte } 2476fcf3ce44SJohn Forte 247730e7468fSPeter Dunlap /* 247830e7468fSPeter Dunlap * Callback from IDM indicating that the task has been suspended or aborted. 247930e7468fSPeter Dunlap */ 248030e7468fSPeter Dunlap void 248130e7468fSPeter Dunlap iscsi_task_aborted(idm_task_t *idt, idm_status_t status) 248230e7468fSPeter Dunlap { 248330e7468fSPeter Dunlap iscsi_cmd_t *icmdp = idt->idt_private; 248430e7468fSPeter Dunlap iscsi_conn_t *icp = icmdp->cmd_conn; 248530e7468fSPeter Dunlap iscsi_sess_t *isp = icp->conn_sess; 248630e7468fSPeter Dunlap 248730e7468fSPeter Dunlap ASSERT(icmdp->cmd_conn != NULL); 248830e7468fSPeter Dunlap 248930e7468fSPeter Dunlap switch (status) { 249030e7468fSPeter Dunlap case IDM_STATUS_SUSPENDED: 249130e7468fSPeter Dunlap /* 249230e7468fSPeter Dunlap * If the task is suspended, it may be aborted later, 249330e7468fSPeter Dunlap * so we can ignore this notification. 249430e7468fSPeter Dunlap */ 249530e7468fSPeter Dunlap break; 249630e7468fSPeter Dunlap 249730e7468fSPeter Dunlap case IDM_STATUS_ABORTED: 249830e7468fSPeter Dunlap mutex_enter(&icp->conn_queue_active.mutex); 249930e7468fSPeter Dunlap iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E9, isp); 250030e7468fSPeter Dunlap mutex_exit(&icp->conn_queue_active.mutex); 250130e7468fSPeter Dunlap break; 250230e7468fSPeter Dunlap 250330e7468fSPeter Dunlap default: 250430e7468fSPeter Dunlap /* 250530e7468fSPeter Dunlap * Unexpected status. 250630e7468fSPeter Dunlap */ 250730e7468fSPeter Dunlap ASSERT(0); 250830e7468fSPeter Dunlap } 250930e7468fSPeter Dunlap 251030e7468fSPeter Dunlap } 2511fcf3ce44SJohn Forte 2512fcf3ce44SJohn Forte /* 2513fcf3ce44SJohn Forte * iscsi_handle_nop - 2514fcf3ce44SJohn Forte * 2515fcf3ce44SJohn Forte */ 2516fcf3ce44SJohn Forte static void 2517fcf3ce44SJohn Forte iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt) 2518fcf3ce44SJohn Forte { 2519fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 2520fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 2521fcf3ce44SJohn Forte 2522fcf3ce44SJohn Forte ASSERT(icp != NULL); 2523fcf3ce44SJohn Forte isp = icp->conn_sess; 2524fcf3ce44SJohn Forte ASSERT(isp != NULL); 2525fcf3ce44SJohn Forte 2526fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP); 2527fcf3ce44SJohn Forte if (icmdp == NULL) { 2528fcf3ce44SJohn Forte return; 2529fcf3ce44SJohn Forte } 2530fcf3ce44SJohn Forte 2531fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_NOP; 2532fcf3ce44SJohn Forte icmdp->cmd_itt = itt; 2533fcf3ce44SJohn Forte icmdp->cmd_ttt = ttt; 2534fcf3ce44SJohn Forte icmdp->cmd_lun = NULL; 2535fcf3ce44SJohn Forte icp->conn_nop_lbolt = ddi_get_lbolt(); 2536fcf3ce44SJohn Forte 2537fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2538fcf3ce44SJohn Forte } 2539fcf3ce44SJohn Forte 2540fcf3ce44SJohn Forte /* 25412b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_handle_reset - send reset request to the target 2542fcf3ce44SJohn Forte * 2543fcf3ce44SJohn Forte */ 2544fcf3ce44SJohn Forte iscsi_status_t 2545fcf3ce44SJohn Forte iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp) 2546fcf3ce44SJohn Forte { 2547fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2548fcf3ce44SJohn Forte iscsi_conn_t *icp; 2549fcf3ce44SJohn Forte iscsi_cmd_t icmd; 2550fcf3ce44SJohn Forte 2551fcf3ce44SJohn Forte ASSERT(isp != NULL); 2552fcf3ce44SJohn Forte 25532b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) { 25542b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER); 25552b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(ilp != NULL); 25562b79d384Sbing zhao - Sun Microsystems - Beijing China if (ilp->lun_state & ISCSI_LUN_STATE_BUSY) { 25572b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock); 25582b79d384Sbing zhao - Sun Microsystems - Beijing China return (ISCSI_STATUS_SUCCESS); 25592b79d384Sbing zhao - Sun Microsystems - Beijing China } 25602b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state |= ISCSI_LUN_STATE_BUSY; 25612b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock); 25622b79d384Sbing zhao - Sun Microsystems - Beijing China } else { 25632b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex); 25642b79d384Sbing zhao - Sun Microsystems - Beijing China if (isp->sess_reset_in_progress == B_TRUE) { 25652b79d384Sbing zhao - Sun Microsystems - Beijing China /* 25662b79d384Sbing zhao - Sun Microsystems - Beijing China * If the reset is in progress, it is unnecessary 25672b79d384Sbing zhao - Sun Microsystems - Beijing China * to send reset to the target redunantly. 25682b79d384Sbing zhao - Sun Microsystems - Beijing China */ 25692b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex); 25702b79d384Sbing zhao - Sun Microsystems - Beijing China return (ISCSI_STATUS_SUCCESS); 25712b79d384Sbing zhao - Sun Microsystems - Beijing China } 25722b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_TRUE; 25732b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex); 25742b79d384Sbing zhao - Sun Microsystems - Beijing China } 25752b79d384Sbing zhao - Sun Microsystems - Beijing China 2576fcf3ce44SJohn Forte bzero(&icmd, sizeof (iscsi_cmd_t)); 2577fcf3ce44SJohn Forte icmd.cmd_sig = ISCSI_SIG_CMD; 2578fcf3ce44SJohn Forte icmd.cmd_state = ISCSI_CMD_STATE_FREE; 2579fcf3ce44SJohn Forte icmd.cmd_type = ISCSI_CMD_TYPE_RESET; 2580fcf3ce44SJohn Forte icmd.cmd_lun = ilp; 2581fcf3ce44SJohn Forte icmd.cmd_un.reset.level = level; 2582fcf3ce44SJohn Forte icmd.cmd_result = ISCSI_STATUS_SUCCESS; 2583fcf3ce44SJohn Forte icmd.cmd_completed = B_FALSE; 25842b79d384Sbing zhao - Sun Microsystems - Beijing China icmd.cmd_un.reset.response = SCSI_TCP_TM_RESP_COMPLETE; 25852b79d384Sbing zhao - Sun Microsystems - Beijing China 2586fcf3ce44SJohn Forte mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL); 2587fcf3ce44SJohn Forte cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL); 2588fcf3ce44SJohn Forte /* 2589fcf3ce44SJohn Forte * If we received an IO and we are not in the 2590fcf3ce44SJohn Forte * LOGGED_IN state we are in the process of 2591fcf3ce44SJohn Forte * failing. Just respond that we are BUSY. 2592fcf3ce44SJohn Forte */ 2593904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 2594fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 2595fcf3ce44SJohn Forte /* We aren't connected to the target fake success */ 2596904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 25972b79d384Sbing zhao - Sun Microsystems - Beijing China 25982b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) { 25992b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER); 26002b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY; 26012b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock); 26022b79d384Sbing zhao - Sun Microsystems - Beijing China } else { 26032b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex); 26042b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_FALSE; 26052b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex); 26062b79d384Sbing zhao - Sun Microsystems - Beijing China } 26072b79d384Sbing zhao - Sun Microsystems - Beijing China 2608fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 2609fcf3ce44SJohn Forte } 2610fcf3ce44SJohn Forte 2611fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2612fcf3ce44SJohn Forte iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp); 2613fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2614904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 2615fcf3ce44SJohn Forte 2616fcf3ce44SJohn Forte /* stall until completed */ 2617fcf3ce44SJohn Forte mutex_enter(&icmd.cmd_mutex); 2618fcf3ce44SJohn Forte while (icmd.cmd_completed == B_FALSE) { 2619fcf3ce44SJohn Forte cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex); 2620fcf3ce44SJohn Forte } 2621fcf3ce44SJohn Forte mutex_exit(&icmd.cmd_mutex); 2622fcf3ce44SJohn Forte 2623fcf3ce44SJohn Forte /* copy rval */ 2624fcf3ce44SJohn Forte rval = icmd.cmd_result; 2625fcf3ce44SJohn Forte 2626fcf3ce44SJohn Forte if (rval == ISCSI_STATUS_SUCCESS) { 2627fcf3ce44SJohn Forte /* 2628fcf3ce44SJohn Forte * Reset was successful. We need to flush 2629fcf3ce44SJohn Forte * all active IOs. 2630fcf3ce44SJohn Forte */ 2631fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 2632fcf3ce44SJohn Forte icp = isp->sess_conn_list; 2633fcf3ce44SJohn Forte while (icp != NULL) { 2634fcf3ce44SJohn Forte iscsi_cmd_t *t_icmdp = NULL; 26352b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *next_icmdp = NULL; 2636fcf3ce44SJohn Forte 2637fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 2638fcf3ce44SJohn Forte t_icmdp = icp->conn_queue_active.head; 2639fcf3ce44SJohn Forte while (t_icmdp != NULL) { 26402b79d384Sbing zhao - Sun Microsystems - Beijing China next_icmdp = t_icmdp->cmd_next; 26412b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&t_icmdp->cmd_mutex); 26422b79d384Sbing zhao - Sun Microsystems - Beijing China if (!(t_icmdp->cmd_misc_flags & 26432b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_SENT)) { 26442b79d384Sbing zhao - Sun Microsystems - Beijing China /* 26452b79d384Sbing zhao - Sun Microsystems - Beijing China * Although this command is in the 26462b79d384Sbing zhao - Sun Microsystems - Beijing China * active queue, it has not been sent. 26472b79d384Sbing zhao - Sun Microsystems - Beijing China * Skip it. 26482b79d384Sbing zhao - Sun Microsystems - Beijing China */ 26492b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 26502b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp; 26512b79d384Sbing zhao - Sun Microsystems - Beijing China continue; 26522b79d384Sbing zhao - Sun Microsystems - Beijing China } 26532b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) { 26542b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmd.cmd_lun == NULL || 26552b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_lun == NULL || 26562b79d384Sbing zhao - Sun Microsystems - Beijing China (icmd.cmd_lun->lun_num != 26572b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_lun->lun_num)) { 26582b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 26592b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp; 26602b79d384Sbing zhao - Sun Microsystems - Beijing China continue; 26612b79d384Sbing zhao - Sun Microsystems - Beijing China } 26622b79d384Sbing zhao - Sun Microsystems - Beijing China } 26632b79d384Sbing zhao - Sun Microsystems - Beijing China 26642b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmd.cmd_sn == t_icmdp->cmd_sn) { 26652b79d384Sbing zhao - Sun Microsystems - Beijing China /* 26662b79d384Sbing zhao - Sun Microsystems - Beijing China * This command may be replied with 26672b79d384Sbing zhao - Sun Microsystems - Beijing China * UA sense key later. So currently 26682b79d384Sbing zhao - Sun Microsystems - Beijing China * it is not a suitable time to flush 26692b79d384Sbing zhao - Sun Microsystems - Beijing China * it. Mark its flag with FLUSH. There 26702b79d384Sbing zhao - Sun Microsystems - Beijing China * is no harm to keep it for a while. 26712b79d384Sbing zhao - Sun Microsystems - Beijing China */ 26722b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_misc_flags |= 26732b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_FLUSH; 26742b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type == 26752b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_TYPE_SCSI) { 26762b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |= 26772b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET; 26782b79d384Sbing zhao - Sun Microsystems - Beijing China } 26792b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 26802b79d384Sbing zhao - Sun Microsystems - Beijing China } else if ((icmd.cmd_sn > t_icmdp->cmd_sn) || 26812b79d384Sbing zhao - Sun Microsystems - Beijing China ((t_icmdp->cmd_sn - icmd.cmd_sn) > 26822b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_SN_WRAP)) { 26832b79d384Sbing zhao - Sun Microsystems - Beijing China /* 26842b79d384Sbing zhao - Sun Microsystems - Beijing China * This reset request must act on all 26852b79d384Sbing zhao - Sun Microsystems - Beijing China * the commnds from the same session 26862b79d384Sbing zhao - Sun Microsystems - Beijing China * having a CmdSN lower than the task 26872b79d384Sbing zhao - Sun Microsystems - Beijing China * mangement CmdSN. So flush these 26882b79d384Sbing zhao - Sun Microsystems - Beijing China * commands here. 26892b79d384Sbing zhao - Sun Microsystems - Beijing China */ 26902b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type == 26912b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_TYPE_SCSI) { 26922b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |= 26932b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET; 26942b79d384Sbing zhao - Sun Microsystems - Beijing China } 26952b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 26962b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(t_icmdp, 26972b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E7, isp); 26982b79d384Sbing zhao - Sun Microsystems - Beijing China } else { 26992b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 27002b79d384Sbing zhao - Sun Microsystems - Beijing China } 27012b79d384Sbing zhao - Sun Microsystems - Beijing China 27022b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp; 2703fcf3ce44SJohn Forte } 2704fcf3ce44SJohn Forte 2705fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 2706fcf3ce44SJohn Forte icp = icp->conn_next; 2707fcf3ce44SJohn Forte } 2708fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 2709fcf3ce44SJohn Forte } 2710fcf3ce44SJohn Forte 2711fcf3ce44SJohn Forte /* clean up */ 2712fcf3ce44SJohn Forte cv_destroy(&icmd.cmd_completion); 2713fcf3ce44SJohn Forte mutex_destroy(&icmd.cmd_mutex); 2714fcf3ce44SJohn Forte 27152b79d384Sbing zhao - Sun Microsystems - Beijing China if (level == RESET_LUN) { 27162b79d384Sbing zhao - Sun Microsystems - Beijing China rw_enter(&isp->sess_lun_list_rwlock, RW_WRITER); 27172b79d384Sbing zhao - Sun Microsystems - Beijing China ilp->lun_state &= ~ISCSI_LUN_STATE_BUSY; 27182b79d384Sbing zhao - Sun Microsystems - Beijing China rw_exit(&isp->sess_lun_list_rwlock); 27192b79d384Sbing zhao - Sun Microsystems - Beijing China } else { 27202b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&isp->sess_reset_mutex); 27212b79d384Sbing zhao - Sun Microsystems - Beijing China isp->sess_reset_in_progress = B_FALSE; 27222b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&isp->sess_reset_mutex); 27232b79d384Sbing zhao - Sun Microsystems - Beijing China } 27242b79d384Sbing zhao - Sun Microsystems - Beijing China 2725fcf3ce44SJohn Forte return (rval); 2726fcf3ce44SJohn Forte } 2727fcf3ce44SJohn Forte 272830e7468fSPeter Dunlap /* 272992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * iscsi_logout_start - task handler for deferred logout 273092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Acquire a hold before call, released in iscsi_handle_logout 273130e7468fSPeter Dunlap */ 273230e7468fSPeter Dunlap static void 273330e7468fSPeter Dunlap iscsi_logout_start(void *arg) 273430e7468fSPeter Dunlap { 273530e7468fSPeter Dunlap iscsi_task_t *itp = (iscsi_task_t *)arg; 273630e7468fSPeter Dunlap iscsi_conn_t *icp; 273730e7468fSPeter Dunlap 273830e7468fSPeter Dunlap icp = (iscsi_conn_t *)itp->t_arg; 273930e7468fSPeter Dunlap 274030e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex); 274130e7468fSPeter Dunlap (void) iscsi_handle_logout(icp); 274230e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex); 274330e7468fSPeter Dunlap } 2744fcf3ce44SJohn Forte 2745fcf3ce44SJohn Forte /* 2746fcf3ce44SJohn Forte * iscsi_handle_logout - This function will issue a logout for 2747fcf3ce44SJohn Forte * the session from a specific connection. 274892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Acquire idm_conn_hold before call. Released internally. 2749fcf3ce44SJohn Forte */ 2750fcf3ce44SJohn Forte iscsi_status_t 2751fcf3ce44SJohn Forte iscsi_handle_logout(iscsi_conn_t *icp) 2752fcf3ce44SJohn Forte { 2753fcf3ce44SJohn Forte iscsi_sess_t *isp; 275430e7468fSPeter Dunlap idm_conn_t *ic; 2755fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 2756fcf3ce44SJohn Forte int rval; 2757fcf3ce44SJohn Forte 2758fcf3ce44SJohn Forte ASSERT(icp != NULL); 2759fcf3ce44SJohn Forte isp = icp->conn_sess; 276030e7468fSPeter Dunlap ic = icp->conn_ic; 2761fcf3ce44SJohn Forte ASSERT(isp != NULL); 2762fcf3ce44SJohn Forte ASSERT(isp->sess_hba != NULL); 276330e7468fSPeter Dunlap ASSERT(mutex_owned(&icp->conn_state_mutex)); 276430e7468fSPeter Dunlap 276530e7468fSPeter Dunlap /* 276692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * If the connection has already gone down (e.g. if the transport 276792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * failed between when this LOGOUT was generated and now) then we 276892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * can and must skip sending the LOGOUT. Check the same condition 276992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * we use below to determine that connection has "settled". 277030e7468fSPeter Dunlap */ 277192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States if ((icp->conn_state == ISCSI_CONN_STATE_FREE) || 277292adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States (icp->conn_state == ISCSI_CONN_STATE_FAILED) || 277392adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States (icp->conn_state == ISCSI_CONN_STATE_POLLING)) { 277492adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_conn_rele(ic); 277592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (0); 277692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2777fcf3ce44SJohn Forte 2778fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2779fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2780fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_LOGOUT; 2781fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2782fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2783fcf3ce44SJohn Forte 2784fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2785fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2786fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2787fcf3ce44SJohn Forte 2788fcf3ce44SJohn Forte /* 2789fcf3ce44SJohn Forte * release connection state mutex to avoid a deadlock. This 2790fcf3ce44SJohn Forte * function is called from within the connection state 2791fcf3ce44SJohn Forte * machine with the lock held. When the logout response is 2792fcf3ce44SJohn Forte * received another call to the connection state machine 2793fcf3ce44SJohn Forte * occurs which causes the deadlock 2794fcf3ce44SJohn Forte */ 2795fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 2796fcf3ce44SJohn Forte 2797fcf3ce44SJohn Forte /* stall until completed */ 2798fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2799fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 2800fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2801fcf3ce44SJohn Forte } 2802fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2803fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 2804fcf3ce44SJohn Forte 2805fcf3ce44SJohn Forte /* copy rval */ 2806fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2807fcf3ce44SJohn Forte 2808fcf3ce44SJohn Forte /* clean up */ 2809fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2810fcf3ce44SJohn Forte 281130e7468fSPeter Dunlap if (rval != 0) { 281230e7468fSPeter Dunlap /* If the logout failed then drop the connection */ 281330e7468fSPeter Dunlap idm_ini_conn_disconnect(icp->conn_ic); 281430e7468fSPeter Dunlap } 281530e7468fSPeter Dunlap 281630e7468fSPeter Dunlap /* stall until connection settles */ 281730e7468fSPeter Dunlap while ((icp->conn_state != ISCSI_CONN_STATE_FREE) && 281830e7468fSPeter Dunlap (icp->conn_state != ISCSI_CONN_STATE_FAILED) && 281930e7468fSPeter Dunlap (icp->conn_state != ISCSI_CONN_STATE_POLLING)) { 282030e7468fSPeter Dunlap /* wait for transition */ 282130e7468fSPeter Dunlap cv_wait(&icp->conn_state_change, &icp->conn_state_mutex); 282230e7468fSPeter Dunlap } 282330e7468fSPeter Dunlap 282430e7468fSPeter Dunlap idm_conn_rele(ic); 282530e7468fSPeter Dunlap 282630e7468fSPeter Dunlap /* 282730e7468fSPeter Dunlap * Return value reflects whether the logout command completed -- 282830e7468fSPeter Dunlap * regardless of the return value the connection is closed and 282930e7468fSPeter Dunlap * ready for reconnection. 283030e7468fSPeter Dunlap */ 2831fcf3ce44SJohn Forte return (rval); 2832fcf3ce44SJohn Forte } 2833fcf3ce44SJohn Forte 283430e7468fSPeter Dunlap 2835fcf3ce44SJohn Forte /* 2836fcf3ce44SJohn Forte * iscsi_handle_text - main control function for iSCSI text requests. This 2837fcf3ce44SJohn Forte * function handles allocating the command, sending initial text request, and 2838fcf3ce44SJohn Forte * handling long response sequence. 2839fcf3ce44SJohn Forte * If a data overflow condition occurs, iscsi_handle_text continues to 2840fcf3ce44SJohn Forte * receive responses until the all data has been recieved. This allows 2841fcf3ce44SJohn Forte * the full data length to be returned to the caller. 2842fcf3ce44SJohn Forte */ 2843fcf3ce44SJohn Forte iscsi_status_t 2844fcf3ce44SJohn Forte iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len, 2845fcf3ce44SJohn Forte uint32_t data_len, uint32_t *rx_data_len) 2846fcf3ce44SJohn Forte { 2847fcf3ce44SJohn Forte iscsi_sess_t *isp; 2848fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 2849fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2850fcf3ce44SJohn Forte 2851fcf3ce44SJohn Forte ASSERT(icp != NULL); 2852fcf3ce44SJohn Forte ASSERT(buf != NULL); 2853fcf3ce44SJohn Forte ASSERT(rx_data_len != NULL); 2854fcf3ce44SJohn Forte 2855fcf3ce44SJohn Forte isp = icp->conn_sess; 2856fcf3ce44SJohn Forte ASSERT(isp != NULL); 2857fcf3ce44SJohn Forte 2858fcf3ce44SJohn Forte /* 2859fcf3ce44SJohn Forte * Ensure data for text request command is not greater 2860fcf3ce44SJohn Forte * than the negotiated maximum receive data seqment length. 2861fcf3ce44SJohn Forte * 2862fcf3ce44SJohn Forte * Although iSCSI allows for long text requests (multiple 2863fcf3ce44SJohn Forte * pdus), this function places a restriction on text 2864fcf3ce44SJohn Forte * requests to ensure it is handled by a single PDU. 2865fcf3ce44SJohn Forte */ 2866fcf3ce44SJohn Forte if (data_len > icp->conn_params.max_xmit_data_seg_len) { 2867fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED); 2868fcf3ce44SJohn Forte } 2869fcf3ce44SJohn Forte 2870fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2871fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2872fcf3ce44SJohn Forte 2873fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_TEXT; 2874fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2875d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE; 2876fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2877fcf3ce44SJohn Forte 2878fcf3ce44SJohn Forte icmdp->cmd_un.text.buf = buf; 2879fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len = buf_len; 2880fcf3ce44SJohn Forte icmdp->cmd_un.text.offset = 0; 2881fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = data_len; 2882fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len = 0; 2883fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ISCSI_RSVD_TASK_TAG; 2884fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_INITIAL_REQ; 2885fcf3ce44SJohn Forte 2886fcf3ce44SJohn Forte long_text_response: 2887904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 2888fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 2889fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2890904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 2891fcf3ce44SJohn Forte return (ISCSI_STATUS_NO_CONN_LOGGED_IN); 2892fcf3ce44SJohn Forte } 2893fcf3ce44SJohn Forte 2894fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2895fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2896fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2897904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 2898fcf3ce44SJohn Forte 2899fcf3ce44SJohn Forte /* stall until completed */ 2900fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2901fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 2902fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2903fcf3ce44SJohn Forte } 2904fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2905fcf3ce44SJohn Forte 2906fcf3ce44SJohn Forte /* 2907fcf3ce44SJohn Forte * check if error occured. If data overflow occured, continue on 2908fcf3ce44SJohn Forte * to ensure we get all data so that the full data length can be 2909fcf3ce44SJohn Forte * returned to the user 2910fcf3ce44SJohn Forte */ 2911fcf3ce44SJohn Forte if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) && 2912fcf3ce44SJohn Forte (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) { 2913fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)", 2914fcf3ce44SJohn Forte icmdp->cmd_result); 2915fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2916fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2917fcf3ce44SJohn Forte return (rval); 2918fcf3ce44SJohn Forte } 2919fcf3ce44SJohn Forte 2920fcf3ce44SJohn Forte /* check if this was a partial text PDU */ 2921fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) { 2922fcf3ce44SJohn Forte /* 2923fcf3ce44SJohn Forte * If a paritial text rexponse received, send an empty 2924fcf3ce44SJohn Forte * text request. This follows the behaviour specified 2925fcf3ce44SJohn Forte * in RFC3720 regarding long text responses. 2926fcf3ce44SJohn Forte */ 2927d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE; 2928fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2929fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = 0; 2930fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION; 2931fcf3ce44SJohn Forte goto long_text_response; 2932fcf3ce44SJohn Forte } 2933fcf3ce44SJohn Forte 2934fcf3ce44SJohn Forte /* 2935fcf3ce44SJohn Forte * set total received data length. If data overflow this would be 2936fcf3ce44SJohn Forte * amount of data that would have been received if buffer large 2937fcf3ce44SJohn Forte * enough. 2938fcf3ce44SJohn Forte */ 2939fcf3ce44SJohn Forte *rx_data_len = icmdp->cmd_un.text.total_rx_len; 2940fcf3ce44SJohn Forte 2941fcf3ce44SJohn Forte /* copy rval */ 2942fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2943fcf3ce44SJohn Forte 2944fcf3ce44SJohn Forte /* clean up */ 2945fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2946fcf3ce44SJohn Forte 2947fcf3ce44SJohn Forte return (rval); 2948fcf3ce44SJohn Forte } 2949fcf3ce44SJohn Forte 2950fcf3ce44SJohn Forte /* 2951fcf3ce44SJohn Forte * iscsi_handle_passthru - This function is used to send a uscsi_cmd 2952fcf3ce44SJohn Forte * to a specific target lun. This routine is used for internal purposes 2953fcf3ce44SJohn Forte * during enumeration and via the ISCSI_USCSICMD IOCTL. We restrict 2954fcf3ce44SJohn Forte * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS, 2955fcf3ce44SJohn Forte * and READ_CAPACITY for security purposes. 2956fcf3ce44SJohn Forte * 2957fcf3ce44SJohn Forte * The logic here is broken into three phases. 2958fcf3ce44SJohn Forte * 1) Allocate and initialize a pkt/icmdp 2959fcf3ce44SJohn Forte * 2) Send the pkt/icmdp 2960fcf3ce44SJohn Forte * 3) cv_wait for completion 2961fcf3ce44SJohn Forte */ 2962fcf3ce44SJohn Forte iscsi_status_t 2963fcf3ce44SJohn Forte iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp) 2964fcf3ce44SJohn Forte { 2965146832dbSMilos Muzik iscsi_status_t rval; 2966146832dbSMilos Muzik iscsi_cmd_t *icmdp; 2967146832dbSMilos Muzik struct scsi_pkt *pkt; 2968146832dbSMilos Muzik struct buf *bp; 2969146832dbSMilos Muzik struct scsi_arq_status *arqstat; 2970146832dbSMilos Muzik int statuslen; 2971fcf3ce44SJohn Forte 2972fcf3ce44SJohn Forte ASSERT(isp != NULL); 2973fcf3ce44SJohn Forte ASSERT(ucmdp != NULL); 2974fcf3ce44SJohn Forte 2975fcf3ce44SJohn Forte if (ucmdp->uscsi_rqlen > SENSE_LENGTH) { 2976146832dbSMilos Muzik /* 2977146832dbSMilos Muzik * The caller provided sense buffer large enough for additional 2978146832dbSMilos Muzik * sense bytes. We need to allocate pkt_scbp to fit them there 2979146832dbSMilos Muzik * too. 2980146832dbSMilos Muzik */ 2981146832dbSMilos Muzik statuslen = ucmdp->uscsi_rqlen + ISCSI_ARQ_STATUS_NOSENSE_LEN; 2982146832dbSMilos Muzik } else { 2983146832dbSMilos Muzik /* The default size of pkt_scbp */ 2984146832dbSMilos Muzik statuslen = sizeof (struct scsi_arq_status); 2985fcf3ce44SJohn Forte } 2986fcf3ce44SJohn Forte 2987fcf3ce44SJohn Forte /* 2988fcf3ce44SJohn Forte * Step 1. Setup structs - KM_SLEEP will always succeed 2989fcf3ce44SJohn Forte */ 2990fcf3ce44SJohn Forte bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP); 2991fcf3ce44SJohn Forte ASSERT(bp != NULL); 2992fcf3ce44SJohn Forte pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP); 2993fcf3ce44SJohn Forte ASSERT(pkt != NULL); 2994fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP); 2995fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2996fcf3ce44SJohn Forte 2997fcf3ce44SJohn Forte /* setup bp structure */ 2998fcf3ce44SJohn Forte bp->b_flags = B_READ; 2999fcf3ce44SJohn Forte bp->b_bcount = ucmdp->uscsi_buflen; 3000fcf3ce44SJohn Forte bp->b_un.b_addr = ucmdp->uscsi_bufaddr; 3001fcf3ce44SJohn Forte 3002fcf3ce44SJohn Forte /* setup scsi_pkt structure */ 3003fcf3ce44SJohn Forte pkt->pkt_ha_private = icmdp; 3004146832dbSMilos Muzik pkt->pkt_scbp = kmem_zalloc(statuslen, KM_SLEEP); 3005fcf3ce44SJohn Forte pkt->pkt_cdbp = kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP); 3006fcf3ce44SJohn Forte /* callback routine for passthru, will wake cv_wait */ 3007fcf3ce44SJohn Forte pkt->pkt_comp = iscsi_handle_passthru_callback; 3008fcf3ce44SJohn Forte pkt->pkt_time = ucmdp->uscsi_timeout; 3009fcf3ce44SJohn Forte 3010fcf3ce44SJohn Forte /* setup iscsi_cmd structure */ 3011fcf3ce44SJohn Forte icmdp->cmd_lun = NULL; 3012fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_SCSI; 3013fcf3ce44SJohn Forte icmdp->cmd_un.scsi.lun = lun; 3014fcf3ce44SJohn Forte icmdp->cmd_un.scsi.pkt = pkt; 3015fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp = bp; 3016fcf3ce44SJohn Forte bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 3017fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen = ucmdp->uscsi_cdblen; 3018146832dbSMilos Muzik icmdp->cmd_un.scsi.statuslen = statuslen; 3019fcf3ce44SJohn Forte icmdp->cmd_crc_error_seen = B_FALSE; 3020fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 3021fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 3022fcf3ce44SJohn Forte 3023fcf3ce44SJohn Forte /* 3024fcf3ce44SJohn Forte * Step 2. Push IO onto pending queue. If we aren't in 3025fcf3ce44SJohn Forte * FULL_FEATURE we need to fail the IO. 3026fcf3ce44SJohn Forte */ 3027904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 3028fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 3029904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 3030fcf3ce44SJohn Forte 3031fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 3032fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 3033146832dbSMilos Muzik kmem_free(pkt->pkt_scbp, statuslen); 3034fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt)); 3035fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf)); 3036fcf3ce44SJohn Forte 3037fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED); 3038fcf3ce44SJohn Forte } 3039fcf3ce44SJohn Forte 3040fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3041fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 3042fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3043904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 3044fcf3ce44SJohn Forte 3045fcf3ce44SJohn Forte /* 3046fcf3ce44SJohn Forte * Step 3. Wait on cv_wait for completion routine 3047fcf3ce44SJohn Forte */ 3048fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 3049fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 3050fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 3051fcf3ce44SJohn Forte } 3052fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3053fcf3ce44SJohn Forte 3054fcf3ce44SJohn Forte /* copy rval */ 3055fcf3ce44SJohn Forte rval = icmdp->cmd_result; 3056fcf3ce44SJohn Forte 3057fcf3ce44SJohn Forte ucmdp->uscsi_resid = pkt->pkt_resid; 3058fcf3ce44SJohn Forte 3059fcf3ce44SJohn Forte /* update scsi status */ 3060fcf3ce44SJohn Forte arqstat = (struct scsi_arq_status *)pkt->pkt_scbp; 3061fcf3ce44SJohn Forte ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0]; 3062fcf3ce44SJohn Forte 3063fcf3ce44SJohn Forte /* copy request sense buffers if caller gave space */ 3064fcf3ce44SJohn Forte if ((ucmdp->uscsi_rqlen > 0) && 3065fcf3ce44SJohn Forte (ucmdp->uscsi_rqbuf != NULL)) { 3066146832dbSMilos Muzik ASSERT(ucmdp->uscsi_rqlen >= arqstat->sts_rqpkt_resid); 3067146832dbSMilos Muzik ucmdp->uscsi_rqresid = arqstat->sts_rqpkt_resid; 3068146832dbSMilos Muzik bcopy(&arqstat->sts_sensedata, ucmdp->uscsi_rqbuf, 3069146832dbSMilos Muzik ucmdp->uscsi_rqlen - arqstat->sts_rqpkt_resid); 3070fcf3ce44SJohn Forte } 3071fcf3ce44SJohn Forte 3072904e51f6SJack Meng if ((ucmdp->uscsi_status == STATUS_CHECK) && 3073904e51f6SJack Meng ((icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL)) == B_TRUE) { 3074904e51f6SJack Meng /* 3075904e51f6SJack Meng * Internal SCSI commands received status 3076904e51f6SJack Meng */ 3077904e51f6SJack Meng (void) iscsi_decode_sense( 3078904e51f6SJack Meng (uint8_t *)&arqstat->sts_sensedata, icmdp); 3079904e51f6SJack Meng } 3080904e51f6SJack Meng 3081fcf3ce44SJohn Forte /* clean up */ 3082fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 3083fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 3084146832dbSMilos Muzik kmem_free(pkt->pkt_scbp, statuslen); 3085fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt)); 3086fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf)); 3087fcf3ce44SJohn Forte 3088fcf3ce44SJohn Forte return (rval); 3089fcf3ce44SJohn Forte } 3090fcf3ce44SJohn Forte 3091fcf3ce44SJohn Forte 3092fcf3ce44SJohn Forte /* 3093fcf3ce44SJohn Forte * iscsi_handle_passthru_callback - 3094fcf3ce44SJohn Forte * 3095fcf3ce44SJohn Forte */ 3096fcf3ce44SJohn Forte static void 3097fcf3ce44SJohn Forte iscsi_handle_passthru_callback(struct scsi_pkt *pkt) 3098fcf3ce44SJohn Forte { 3099fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 3100fcf3ce44SJohn Forte 3101fcf3ce44SJohn Forte ASSERT(pkt != NULL); 3102fcf3ce44SJohn Forte icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private; 3103fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 3104fcf3ce44SJohn Forte 3105fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 3106fcf3ce44SJohn Forte icmdp->cmd_completed = B_TRUE; 3107fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 3108fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion); 3109fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3110fcf3ce44SJohn Forte 3111fcf3ce44SJohn Forte } 3112fcf3ce44SJohn Forte 311330e7468fSPeter Dunlap /* 311430e7468fSPeter Dunlap * IDM callbacks 311530e7468fSPeter Dunlap */ 311630e7468fSPeter Dunlap void 311730e7468fSPeter Dunlap iscsi_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode) 311830e7468fSPeter Dunlap { 311930e7468fSPeter Dunlap iscsi_cmd_t *icmdp = idm_task->idt_private; 312030e7468fSPeter Dunlap iscsi_conn_t *icp = icmdp->cmd_conn; 312130e7468fSPeter Dunlap iscsi_data_hdr_t *ihp = (iscsi_data_hdr_t *)pdu->isp_hdr; 312230e7468fSPeter Dunlap 312330e7468fSPeter Dunlap mutex_enter(&icmdp->cmd_mutex); 312430e7468fSPeter Dunlap if (opcode == ISCSI_OP_SCSI_DATA) { 312530e7468fSPeter Dunlap uint32_t data_sn; 312630e7468fSPeter Dunlap uint32_t lun; 312730e7468fSPeter Dunlap icmdp = idm_task->idt_private; 312830e7468fSPeter Dunlap icp = icmdp->cmd_conn; 312930e7468fSPeter Dunlap ihp->opcode = opcode; 313030e7468fSPeter Dunlap ihp->itt = icmdp->cmd_itt; 313130e7468fSPeter Dunlap ihp->ttt = idm_task->idt_r2t_ttt; 313230e7468fSPeter Dunlap ihp->expstatsn = htonl(icp->conn_expstatsn); 313330e7468fSPeter Dunlap icp->conn_laststatsn = icp->conn_expstatsn; 313430e7468fSPeter Dunlap data_sn = ntohl(ihp->datasn); 313530e7468fSPeter Dunlap data_sn++; 313630e7468fSPeter Dunlap lun = icmdp->cmd_un.scsi.lun; 313730e7468fSPeter Dunlap ISCSI_LUN_BYTE_COPY(ihp->lun, lun); 313830e7468fSPeter Dunlap /* CRM: upate_flow_control */ 313930e7468fSPeter Dunlap ISCSI_IO_LOG(CE_NOTE, "DEBUG: iscsi_build_hdr" 314030e7468fSPeter Dunlap "(ISCSI_OP_SCSI_DATA): task: %p icp: %p ic: %p itt: %x " 314130e7468fSPeter Dunlap "exp: %d data_sn: %d", (void *)idm_task, (void *)icp, 314230e7468fSPeter Dunlap (void *)icp->conn_ic, ihp->itt, icp->conn_expstatsn, 314330e7468fSPeter Dunlap data_sn); 314430e7468fSPeter Dunlap } else { 314530e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi_build_hdr: unprocessed build " 314630e7468fSPeter Dunlap "header opcode: %x", opcode); 314730e7468fSPeter Dunlap } 314830e7468fSPeter Dunlap mutex_exit(&icmdp->cmd_mutex); 314930e7468fSPeter Dunlap } 315030e7468fSPeter Dunlap 315130e7468fSPeter Dunlap static void 315230e7468fSPeter Dunlap iscsi_process_rsp_status(iscsi_sess_t *isp, iscsi_conn_t *icp, 315330e7468fSPeter Dunlap idm_status_t status) 315430e7468fSPeter Dunlap { 315530e7468fSPeter Dunlap switch (status) { 315630e7468fSPeter Dunlap case IDM_STATUS_SUCCESS: 315730e7468fSPeter Dunlap if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) && 315830e7468fSPeter Dunlap (icp->conn_queue_active.count == 0)) { 315930e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp); 316030e7468fSPeter Dunlap } 316130e7468fSPeter Dunlap break; 316230e7468fSPeter Dunlap case IDM_STATUS_PROTOCOL_ERROR: 316330e7468fSPeter Dunlap KSTAT_INC_CONN_ERR_PROTOCOL(icp); 316430e7468fSPeter Dunlap iscsi_drop_conn_cleanup(icp); 316530e7468fSPeter Dunlap break; 316630e7468fSPeter Dunlap default: 316730e7468fSPeter Dunlap break; 316830e7468fSPeter Dunlap } 316930e7468fSPeter Dunlap } 317030e7468fSPeter Dunlap 317130e7468fSPeter Dunlap static void 3172*811eca55SToomas Soome iscsi_drop_conn_cleanup(iscsi_conn_t *icp) 3173*811eca55SToomas Soome { 317430e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex); 317530e7468fSPeter Dunlap idm_ini_conn_disconnect(icp->conn_ic); 317630e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex); 317730e7468fSPeter Dunlap } 317830e7468fSPeter Dunlap 317930e7468fSPeter Dunlap void 318030e7468fSPeter Dunlap iscsi_rx_error_pdu(idm_conn_t *ic, idm_pdu_t *pdu, idm_status_t status) 318130e7468fSPeter Dunlap { 318230e7468fSPeter Dunlap iscsi_conn_t *icp = (iscsi_conn_t *)ic->ic_handle; 318330e7468fSPeter Dunlap iscsi_sess_t *isp; 318430e7468fSPeter Dunlap 318530e7468fSPeter Dunlap ASSERT(icp != NULL); 318630e7468fSPeter Dunlap isp = icp->conn_sess; 318730e7468fSPeter Dunlap ASSERT(isp != NULL); 318830e7468fSPeter Dunlap iscsi_process_rsp_status(isp, icp, status); 318930e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 319030e7468fSPeter Dunlap } 319130e7468fSPeter Dunlap 319230e7468fSPeter Dunlap void 319330e7468fSPeter Dunlap iscsi_rx_misc_pdu(idm_conn_t *ic, idm_pdu_t *pdu) 319430e7468fSPeter Dunlap { 3195*811eca55SToomas Soome iscsi_conn_t *icp; 319630e7468fSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr; 319730e7468fSPeter Dunlap iscsi_sess_t *isp; 319830e7468fSPeter Dunlap idm_status_t status; 319930e7468fSPeter Dunlap 320030e7468fSPeter Dunlap icp = ic->ic_handle; 320130e7468fSPeter Dunlap isp = icp->conn_sess; 320230e7468fSPeter Dunlap isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt(); 320330e7468fSPeter Dunlap switch (ihp->opcode & ISCSI_OPCODE_MASK) { 320430e7468fSPeter Dunlap case ISCSI_OP_LOGIN_RSP: 320530e7468fSPeter Dunlap status = iscsi_rx_process_login_pdu(ic, pdu); 320630e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 320730e7468fSPeter Dunlap break; 320830e7468fSPeter Dunlap case ISCSI_OP_LOGOUT_RSP: 320930e7468fSPeter Dunlap status = iscsi_rx_process_logout_rsp(ic, pdu); 321030e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 321130e7468fSPeter Dunlap break; 321230e7468fSPeter Dunlap case ISCSI_OP_REJECT_MSG: 321330e7468fSPeter Dunlap status = iscsi_rx_process_reject_rsp(ic, pdu); 321430e7468fSPeter Dunlap break; 321530e7468fSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP: 321630e7468fSPeter Dunlap status = iscsi_rx_process_task_mgt_rsp(ic, pdu); 321730e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 321830e7468fSPeter Dunlap break; 321930e7468fSPeter Dunlap case ISCSI_OP_NOOP_IN: 322030e7468fSPeter Dunlap status = iscsi_rx_process_nop(ic, pdu); 322130e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 322230e7468fSPeter Dunlap break; 322330e7468fSPeter Dunlap case ISCSI_OP_ASYNC_EVENT: 322430e7468fSPeter Dunlap status = iscsi_rx_process_async_rsp(ic, pdu); 322530e7468fSPeter Dunlap break; 322630e7468fSPeter Dunlap case ISCSI_OP_TEXT_RSP: 322730e7468fSPeter Dunlap status = iscsi_rx_process_text_rsp(ic, pdu); 322830e7468fSPeter Dunlap idm_pdu_complete(pdu, status); 322930e7468fSPeter Dunlap break; 323030e7468fSPeter Dunlap default: 323130e7468fSPeter Dunlap cmn_err(CE_WARN, "iscsi connection(%u) protocol error " 323230e7468fSPeter Dunlap "- received misc unsupported opcode 0x%02x", 323330e7468fSPeter Dunlap icp->conn_oid, ihp->opcode); 323430e7468fSPeter Dunlap status = IDM_STATUS_PROTOCOL_ERROR; 323530e7468fSPeter Dunlap break; 323630e7468fSPeter Dunlap } 323730e7468fSPeter Dunlap iscsi_process_rsp_status(isp, icp, status); 323830e7468fSPeter Dunlap } 323930e7468fSPeter Dunlap 3240fcf3ce44SJohn Forte /* 3241fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3242fcf3ce44SJohn Forte * | Beginning of completion routines | 3243fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3244fcf3ce44SJohn Forte */ 3245fcf3ce44SJohn Forte 3246fcf3ce44SJohn Forte /* 3247fcf3ce44SJohn Forte * iscsi_ic_thread - 3248fcf3ce44SJohn Forte */ 3249fcf3ce44SJohn Forte void 3250fcf3ce44SJohn Forte iscsi_ic_thread(iscsi_thread_t *thread, void *arg) 3251fcf3ce44SJohn Forte { 3252fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg; 3253fcf3ce44SJohn Forte int ret; 3254fcf3ce44SJohn Forte iscsi_queue_t q; 3255fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 3256fcf3ce44SJohn Forte iscsi_cmd_t *next_icmdp; 3257fcf3ce44SJohn Forte 3258fcf3ce44SJohn Forte ASSERT(isp != NULL); 3259fcf3ce44SJohn Forte ASSERT(thread != NULL); 3260fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD); 3261fcf3ce44SJohn Forte 3262fcf3ce44SJohn Forte for (;;) { 3263fcf3ce44SJohn Forte 3264fcf3ce44SJohn Forte /* 3265fcf3ce44SJohn Forte * We wait till iodone or somebody else wakes us up. 3266fcf3ce44SJohn Forte */ 3267fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, -1); 3268fcf3ce44SJohn Forte 3269fcf3ce44SJohn Forte /* 3270fcf3ce44SJohn Forte * The value should never be negative since we never timeout. 3271fcf3ce44SJohn Forte */ 3272fcf3ce44SJohn Forte ASSERT(ret >= 0); 3273fcf3ce44SJohn Forte 3274fcf3ce44SJohn Forte q.count = 0; 3275fcf3ce44SJohn Forte q.head = NULL; 3276fcf3ce44SJohn Forte q.tail = NULL; 3277fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_completion.mutex); 3278fcf3ce44SJohn Forte icmdp = isp->sess_queue_completion.head; 3279fcf3ce44SJohn Forte while (icmdp != NULL) { 3280fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next; 3281fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 3282fcf3ce44SJohn Forte /* 3283fcf3ce44SJohn Forte * check if the associated r2t/abort has finished 328430e7468fSPeter Dunlap * yet. If not, don't complete the command. 3285fcf3ce44SJohn Forte */ 3286fcf3ce44SJohn Forte if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) && 328730e7468fSPeter Dunlap (icmdp->cmd_un.scsi.abort_icmdp == NULL)) { 3288fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3289fcf3ce44SJohn Forte (void) iscsi_dequeue_cmd(&isp-> 3290fcf3ce44SJohn Forte sess_queue_completion.head, 3291fcf3ce44SJohn Forte &isp->sess_queue_completion.tail, 3292fcf3ce44SJohn Forte icmdp); 3293fcf3ce44SJohn Forte --isp->sess_queue_completion.count; 3294fcf3ce44SJohn Forte iscsi_enqueue_cmd_head(&q.head, 3295fcf3ce44SJohn Forte &q.tail, icmdp); 329630e7468fSPeter Dunlap } else { 3297fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 329830e7468fSPeter Dunlap } 3299fcf3ce44SJohn Forte icmdp = next_icmdp; 3300fcf3ce44SJohn Forte } 3301fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_completion.mutex); 3302fcf3ce44SJohn Forte icmdp = q.head; 3303fcf3ce44SJohn Forte while (icmdp != NULL) { 3304fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next; 3305fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp); 3306fcf3ce44SJohn Forte icmdp = next_icmdp; 3307fcf3ce44SJohn Forte } 3308fcf3ce44SJohn Forte 3309fcf3ce44SJohn Forte if (ret > 0) 3310fcf3ce44SJohn Forte /* Somebody woke us up to work */ 3311fcf3ce44SJohn Forte continue; 3312fcf3ce44SJohn Forte else 3313fcf3ce44SJohn Forte /* 3314fcf3ce44SJohn Forte * Somebody woke us up to kill ourselves. We will 3315fcf3ce44SJohn Forte * make sure, however that the completion queue is 3316fcf3ce44SJohn Forte * empty before leaving. After we've done that it 3317fcf3ce44SJohn Forte * is the originator of the signal that has to make 3318fcf3ce44SJohn Forte * sure no other SCSI command is posted. 3319fcf3ce44SJohn Forte */ 3320fcf3ce44SJohn Forte break; 3321fcf3ce44SJohn Forte } 3322fcf3ce44SJohn Forte 3323fcf3ce44SJohn Forte } 3324fcf3ce44SJohn Forte 3325fcf3ce44SJohn Forte /* 3326fcf3ce44SJohn Forte * iscsi_iodone - 3327fcf3ce44SJohn Forte * 3328fcf3ce44SJohn Forte */ 3329fcf3ce44SJohn Forte void 3330fcf3ce44SJohn Forte iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 3331fcf3ce44SJohn Forte { 3332fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 3333fcf3ce44SJohn Forte struct buf *bp = icmdp->cmd_un.scsi.bp; 3334fcf3ce44SJohn Forte 3335fcf3ce44SJohn Forte ASSERT(isp != NULL); 3336fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 3337fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt; 3338fcf3ce44SJohn Forte ASSERT(pkt != NULL); 3339fcf3ce44SJohn Forte 3340fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL); 3341fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL); 3342fcf3ce44SJohn Forte if (pkt->pkt_reason == CMD_CMPLT) { 3343fcf3ce44SJohn Forte if (bp) { 3344fcf3ce44SJohn Forte if (bp->b_flags & B_READ) { 3345fcf3ce44SJohn Forte KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount); 3346fcf3ce44SJohn Forte } else { 3347fcf3ce44SJohn Forte KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount); 3348fcf3ce44SJohn Forte } 3349fcf3ce44SJohn Forte } 3350fcf3ce44SJohn Forte } 3351fcf3ce44SJohn Forte 3352fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_NOINTR) { 3353fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion); 3354fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3355fcf3ce44SJohn Forte } else { 3356fcf3ce44SJohn Forte /* 3357fcf3ce44SJohn Forte * Release mutex. As soon as callback is 3358fcf3ce44SJohn Forte * issued the caller may destroy the command. 3359fcf3ce44SJohn Forte */ 3360fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3361fcf3ce44SJohn Forte /* 3362fcf3ce44SJohn Forte * We can't just directly call the pk_comp routine. In 3363fcf3ce44SJohn Forte * many error cases the target driver will use the calling 3364fcf3ce44SJohn Forte * thread to re-drive error handling (reset, retries...) 3365fcf3ce44SJohn Forte * back into the hba driver (iscsi). If the target redrives 3366fcf3ce44SJohn Forte * a reset back into the iscsi driver off this thead we have 3367fcf3ce44SJohn Forte * a chance of deadlocking. So instead use the io completion 3368fcf3ce44SJohn Forte * thread. 3369fcf3ce44SJohn Forte */ 3370fcf3ce44SJohn Forte (*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt); 3371fcf3ce44SJohn Forte } 3372fcf3ce44SJohn Forte } 3373fcf3ce44SJohn Forte 3374fcf3ce44SJohn Forte /* 3375fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3376fcf3ce44SJohn Forte * | End of completion routines | 3377fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3378fcf3ce44SJohn Forte */ 3379fcf3ce44SJohn Forte 3380fcf3ce44SJohn Forte /* 3381fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3382fcf3ce44SJohn Forte * | Beginning of watchdog routines | 3383fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3384fcf3ce44SJohn Forte */ 3385fcf3ce44SJohn Forte 3386fcf3ce44SJohn Forte /* 3387fcf3ce44SJohn Forte * iscsi_watchdog_thread - 3388fcf3ce44SJohn Forte * 3389fcf3ce44SJohn Forte */ 3390fcf3ce44SJohn Forte void 3391fcf3ce44SJohn Forte iscsi_wd_thread(iscsi_thread_t *thread, void *arg) 3392fcf3ce44SJohn Forte { 3393fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg; 3394fcf3ce44SJohn Forte int rc = 1; 3395fcf3ce44SJohn Forte 3396fcf3ce44SJohn Forte ASSERT(isp != NULL); 3397fcf3ce44SJohn Forte 3398*811eca55SToomas Soome while (rc != 0) { 3399fcf3ce44SJohn Forte 3400fcf3ce44SJohn Forte iscsi_timeout_checks(isp); 3401fcf3ce44SJohn Forte iscsi_nop_checks(isp); 3402fcf3ce44SJohn Forte 3403fcf3ce44SJohn Forte rc = iscsi_thread_wait(thread, SEC_TO_TICK(1)); 3404fcf3ce44SJohn Forte } 3405fcf3ce44SJohn Forte } 3406fcf3ce44SJohn Forte 3407fcf3ce44SJohn Forte /* 3408fcf3ce44SJohn Forte * iscsi_timeout_checks - 3409fcf3ce44SJohn Forte * 3410fcf3ce44SJohn Forte */ 3411fcf3ce44SJohn Forte static void 3412fcf3ce44SJohn Forte iscsi_timeout_checks(iscsi_sess_t *isp) 3413fcf3ce44SJohn Forte { 3414fcf3ce44SJohn Forte clock_t now = ddi_get_lbolt(); 3415fcf3ce44SJohn Forte iscsi_conn_t *icp; 341630e7468fSPeter Dunlap iscsi_cmd_t *icmdp, *nicmdp; 3417fcf3ce44SJohn Forte 3418fcf3ce44SJohn Forte ASSERT(isp != NULL); 3419fcf3ce44SJohn Forte 3420fcf3ce44SJohn Forte /* PENDING */ 3421904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 3422fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3423fcf3ce44SJohn Forte for (icmdp = isp->sess_queue_pending.head; 3424fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) { 3425fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next; 3426fcf3ce44SJohn Forte 3427fcf3ce44SJohn Forte /* Skip entries with no timeout */ 3428fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0) 3429fcf3ce44SJohn Forte continue; 3430fcf3ce44SJohn Forte 3431fcf3ce44SJohn Forte /* 3432fcf3ce44SJohn Forte * Skip pending queue entries for cmd_type values that depend 3433fcf3ce44SJohn Forte * on having an open cmdsn window for successfull transition 3434fcf3ce44SJohn Forte * from pending to the active (i.e. ones that depend on 3435fcf3ce44SJohn Forte * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts 3436fcf3ce44SJohn Forte * when they are successfully moved to the active queue by 3437fcf3ce44SJohn Forte * iscsi_cmd_state_pending() code. 3438fcf3ce44SJohn Forte */ 3439d233de7eSJack Meng /* 3440d233de7eSJack Meng * If the cmd is stuck, at least give it a chance 3441d233de7eSJack Meng * to timeout 3442d233de7eSJack Meng */ 3443d233de7eSJack Meng if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) || 3444d233de7eSJack Meng (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) && 3445d233de7eSJack Meng !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK)) 3446fcf3ce44SJohn Forte continue; 3447fcf3ce44SJohn Forte 3448fcf3ce44SJohn Forte /* Skip if timeout still in the future */ 3449fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout) 3450fcf3ce44SJohn Forte continue; 3451fcf3ce44SJohn Forte 3452fcf3ce44SJohn Forte /* timeout */ 3453fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp); 3454fcf3ce44SJohn Forte } 3455fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3456904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 3457fcf3ce44SJohn Forte 3458fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 3459fcf3ce44SJohn Forte icp = isp->sess_conn_list; 3460fcf3ce44SJohn Forte while (icp != NULL) { 3461fcf3ce44SJohn Forte 3462aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_FALSE; 3463fcf3ce44SJohn Forte /* ACTIVE */ 3464fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 3465fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3466fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 3467fcf3ce44SJohn Forte for (icmdp = icp->conn_queue_active.head; 3468fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) { 3469fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next; 3470fcf3ce44SJohn Forte 3471aff4bce5Syi zhang - Sun Microsystems - Beijing China if (iscsi_nop_timeout_checks(icmdp) == B_TRUE) { 3472aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_TRUE; 3473aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3474aff4bce5Syi zhang - Sun Microsystems - Beijing China 3475fcf3ce44SJohn Forte /* Skip entries with no timeout */ 3476fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0) 3477fcf3ce44SJohn Forte continue; 3478fcf3ce44SJohn Forte 34792b79d384Sbing zhao - Sun Microsystems - Beijing China /* 34802b79d384Sbing zhao - Sun Microsystems - Beijing China * Skip if command is not active or not needed 34812b79d384Sbing zhao - Sun Microsystems - Beijing China * to flush. 34822b79d384Sbing zhao - Sun Microsystems - Beijing China */ 34832b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE && 34842b79d384Sbing zhao - Sun Microsystems - Beijing China !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH)) 3485fcf3ce44SJohn Forte continue; 3486fcf3ce44SJohn Forte 3487fcf3ce44SJohn Forte /* Skip if timeout still in the future */ 3488fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout) 3489fcf3ce44SJohn Forte continue; 3490fcf3ce44SJohn Forte 34912b79d384Sbing zhao - Sun Microsystems - Beijing China if (icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FLUSH) { 34922b79d384Sbing zhao - Sun Microsystems - Beijing China /* 34932b79d384Sbing zhao - Sun Microsystems - Beijing China * This command is left during target reset, 34942b79d384Sbing zhao - Sun Microsystems - Beijing China * we can flush it now. 34952b79d384Sbing zhao - Sun Microsystems - Beijing China */ 34962b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp, 34972b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E7, isp); 34982b79d384Sbing zhao - Sun Microsystems - Beijing China } else if (icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE) { 34992b79d384Sbing zhao - Sun Microsystems - Beijing China /* timeout */ 35002b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_state_machine(icmdp, 35012b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_EVENT_E6, isp); 35022b79d384Sbing zhao - Sun Microsystems - Beijing China } 35032b79d384Sbing zhao - Sun Microsystems - Beijing China 3504fcf3ce44SJohn Forte } 3505fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 3506fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3507fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 3508fcf3ce44SJohn Forte 3509fcf3ce44SJohn Forte icp = icp->conn_next; 3510fcf3ce44SJohn Forte } 3511aff4bce5Syi zhang - Sun Microsystems - Beijing China 3512aff4bce5Syi zhang - Sun Microsystems - Beijing China icp = isp->sess_conn_list; 3513aff4bce5Syi zhang - Sun Microsystems - Beijing China while (icp != NULL) { 3514aff4bce5Syi zhang - Sun Microsystems - Beijing China if (icp->conn_timeout == B_TRUE) { 3515aff4bce5Syi zhang - Sun Microsystems - Beijing China /* timeout on this connect detected */ 3516aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_ini_conn_disconnect(icp->conn_ic); 3517aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_timeout = B_FALSE; 3518aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3519aff4bce5Syi zhang - Sun Microsystems - Beijing China icp = icp->conn_next; 3520aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3521fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 3522fcf3ce44SJohn Forte } 3523fcf3ce44SJohn Forte 3524fcf3ce44SJohn Forte /* 3525fcf3ce44SJohn Forte * iscsi_nop_checks - sends a NOP on idle connections 3526fcf3ce44SJohn Forte * 3527fcf3ce44SJohn Forte * This function walks the connections on a session and 3528fcf3ce44SJohn Forte * issues NOPs on those connections that are in FULL 3529fcf3ce44SJohn Forte * FEATURE mode and have not received data for the 3530fcf3ce44SJohn Forte * time period specified by iscsi_nop_delay (global). 3531fcf3ce44SJohn Forte */ 3532fcf3ce44SJohn Forte static void 3533fcf3ce44SJohn Forte iscsi_nop_checks(iscsi_sess_t *isp) 3534fcf3ce44SJohn Forte { 3535fcf3ce44SJohn Forte iscsi_conn_t *icp; 3536fcf3ce44SJohn Forte 3537fcf3ce44SJohn Forte ASSERT(isp != NULL); 3538fcf3ce44SJohn Forte 3539fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) { 3540fcf3ce44SJohn Forte return; 3541fcf3ce44SJohn Forte } 3542fcf3ce44SJohn Forte 3543fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 3544fcf3ce44SJohn Forte icp = isp->sess_conn_act; 3545fcf3ce44SJohn Forte if (icp != NULL) { 3546fcf3ce44SJohn Forte 3547fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 3548fcf3ce44SJohn Forte if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) && 3549fcf3ce44SJohn Forte (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt + 3550fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() > 3551fcf3ce44SJohn Forte isp->sess_conn_act->conn_nop_lbolt + 3552fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay))) { 3553fcf3ce44SJohn Forte 3554fcf3ce44SJohn Forte /* 3555fcf3ce44SJohn Forte * We haven't received anything from the 3556fcf3ce44SJohn Forte * target is a defined period of time, 3557fcf3ce44SJohn Forte * send NOP to see if the target is alive. 3558fcf3ce44SJohn Forte */ 3559fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3560fcf3ce44SJohn Forte iscsi_handle_nop(isp->sess_conn_act, 3561fcf3ce44SJohn Forte 0, ISCSI_RSVD_TASK_TAG); 3562fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3563fcf3ce44SJohn Forte } 3564fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 3565fcf3ce44SJohn Forte 3566fcf3ce44SJohn Forte icp = icp->conn_next; 3567fcf3ce44SJohn Forte } 3568fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 3569fcf3ce44SJohn Forte } 3570fcf3ce44SJohn Forte 3571aff4bce5Syi zhang - Sun Microsystems - Beijing China static boolean_t 3572aff4bce5Syi zhang - Sun Microsystems - Beijing China iscsi_nop_timeout_checks(iscsi_cmd_t *icmdp) 3573aff4bce5Syi zhang - Sun Microsystems - Beijing China { 3574aff4bce5Syi zhang - Sun Microsystems - Beijing China if (icmdp->cmd_type == ISCSI_CMD_TYPE_NOP) { 3575aff4bce5Syi zhang - Sun Microsystems - Beijing China if ((ddi_get_lbolt() - icmdp->cmd_lbolt_active) > 3576aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(ISCSI_CONN_TIEMOUT_DETECT)) { 3577aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_TRUE); 3578aff4bce5Syi zhang - Sun Microsystems - Beijing China } else { 3579aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_FALSE); 3580aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3581aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3582aff4bce5Syi zhang - Sun Microsystems - Beijing China return (B_FALSE); 3583aff4bce5Syi zhang - Sun Microsystems - Beijing China } 3584fcf3ce44SJohn Forte /* 3585fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3586fcf3ce44SJohn Forte * | End of wd routines | 3587fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3588fcf3ce44SJohn Forte */ 35892b79d384Sbing zhao - Sun Microsystems - Beijing China 35902b79d384Sbing zhao - Sun Microsystems - Beijing China /* 35912b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_flush_cmd_after_reset - flush commands after reset 35922b79d384Sbing zhao - Sun Microsystems - Beijing China * 3593b97c1f92SMilos Muzik * Here we will flush all the commands for a specified LUN whose cmdsn is less 3594b97c1f92SMilos Muzik * than the one received with the Unit Attention. 35952b79d384Sbing zhao - Sun Microsystems - Beijing China */ 35962b79d384Sbing zhao - Sun Microsystems - Beijing China static void 35972b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_flush_cmd_after_reset(uint32_t cmd_sn, uint16_t lun_num, 35982b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_conn_t *icp) 35992b79d384Sbing zhao - Sun Microsystems - Beijing China { 36002b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *t_icmdp = NULL; 36012b79d384Sbing zhao - Sun Microsystems - Beijing China iscsi_cmd_t *next_icmdp = NULL; 36022b79d384Sbing zhao - Sun Microsystems - Beijing China 36032b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(icp != NULL); 36042b79d384Sbing zhao - Sun Microsystems - Beijing China 36052b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = icp->conn_queue_active.head; 36062b79d384Sbing zhao - Sun Microsystems - Beijing China while (t_icmdp != NULL) { 36072b79d384Sbing zhao - Sun Microsystems - Beijing China next_icmdp = t_icmdp->cmd_next; 36082b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_enter(&t_icmdp->cmd_mutex); 36092b79d384Sbing zhao - Sun Microsystems - Beijing China /* 36102b79d384Sbing zhao - Sun Microsystems - Beijing China * We will flush the commands whose cmdsn is less than the one 36112b79d384Sbing zhao - Sun Microsystems - Beijing China * got Unit Attention. 36122b79d384Sbing zhao - Sun Microsystems - Beijing China * Here we will check for wrap by subtracting and compare to 36132b79d384Sbing zhao - Sun Microsystems - Beijing China * 1/2 of a 32 bit number, if greater then we wrapped. 36142b79d384Sbing zhao - Sun Microsystems - Beijing China */ 36152b79d384Sbing zhao - Sun Microsystems - Beijing China if ((t_icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_SENT) && 36162b79d384Sbing zhao - Sun Microsystems - Beijing China ((cmd_sn > t_icmdp->cmd_sn) || 36172b79d384Sbing zhao - Sun Microsystems - Beijing China ((t_icmdp->cmd_sn - cmd_sn) > 36182b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_SN_WRAP))) { 3619b97c1f92SMilos Muzik /* 3620b97c1f92SMilos Muzik * Internally generated SCSI commands do not have 3621b97c1f92SMilos Muzik * t_icmdp->cmd_lun set, but the LUN can be retrieved 3622b97c1f92SMilos Muzik * from t_icmdp->cmd_un.scsi.lun. 3623b97c1f92SMilos Muzik */ 3624b97c1f92SMilos Muzik if ((t_icmdp->cmd_lun != NULL && 3625b97c1f92SMilos Muzik t_icmdp->cmd_lun->lun_num == lun_num) || 3626b97c1f92SMilos Muzik (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI && 3627b97c1f92SMilos Muzik (t_icmdp->cmd_un.scsi.lun & ISCSI_LUN_MASK) == 3628b97c1f92SMilos Muzik lun_num)) { 36292b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_misc_flags |= 36302b79d384Sbing zhao - Sun Microsystems - Beijing China ISCSI_CMD_MISCFLAG_FLUSH; 36312b79d384Sbing zhao - Sun Microsystems - Beijing China if (t_icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) { 36322b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp->cmd_un.scsi.pkt_stat |= 36332b79d384Sbing zhao - Sun Microsystems - Beijing China STAT_BUS_RESET; 36342b79d384Sbing zhao - Sun Microsystems - Beijing China } 36352b79d384Sbing zhao - Sun Microsystems - Beijing China } 36362b79d384Sbing zhao - Sun Microsystems - Beijing China } 36372b79d384Sbing zhao - Sun Microsystems - Beijing China mutex_exit(&t_icmdp->cmd_mutex); 36382b79d384Sbing zhao - Sun Microsystems - Beijing China t_icmdp = next_icmdp; 36392b79d384Sbing zhao - Sun Microsystems - Beijing China } 36402b79d384Sbing zhao - Sun Microsystems - Beijing China } 36412b79d384Sbing zhao - Sun Microsystems - Beijing China 36422b79d384Sbing zhao - Sun Microsystems - Beijing China /* 36432b79d384Sbing zhao - Sun Microsystems - Beijing China * iscsi_decode_sense - decode the sense data in the cmd response 3644904e51f6SJack Meng * and take proper actions 36452b79d384Sbing zhao - Sun Microsystems - Beijing China */ 36462b79d384Sbing zhao - Sun Microsystems - Beijing China static boolean_t 3647904e51f6SJack Meng iscsi_decode_sense(uint8_t *sense_data, iscsi_cmd_t *icmdp) 36482b79d384Sbing zhao - Sun Microsystems - Beijing China { 3649904e51f6SJack Meng uint8_t sense_key = 0; 3650904e51f6SJack Meng uint8_t asc = 0; 3651904e51f6SJack Meng uint8_t ascq = 0; 3652904e51f6SJack Meng boolean_t flush_io = B_FALSE; 3653904e51f6SJack Meng boolean_t reconfig_lun = B_FALSE; 3654904e51f6SJack Meng iscsi_sess_t *isp = NULL; 36552b79d384Sbing zhao - Sun Microsystems - Beijing China 36562b79d384Sbing zhao - Sun Microsystems - Beijing China ASSERT(sense_data != NULL); 36572b79d384Sbing zhao - Sun Microsystems - Beijing China 3658904e51f6SJack Meng isp = icmdp->cmd_conn->conn_sess; 3659904e51f6SJack Meng 36602b79d384Sbing zhao - Sun Microsystems - Beijing China sense_key = scsi_sense_key(sense_data); 36612b79d384Sbing zhao - Sun Microsystems - Beijing China switch (sense_key) { 36622b79d384Sbing zhao - Sun Microsystems - Beijing China case KEY_UNIT_ATTENTION: 36632b79d384Sbing zhao - Sun Microsystems - Beijing China asc = scsi_sense_asc(sense_data); 36642b79d384Sbing zhao - Sun Microsystems - Beijing China switch (asc) { 36652b79d384Sbing zhao - Sun Microsystems - Beijing China case ISCSI_SCSI_RESET_SENSE_CODE: 36662b79d384Sbing zhao - Sun Microsystems - Beijing China /* 36672b79d384Sbing zhao - Sun Microsystems - Beijing China * POWER ON, RESET, OR BUS_DEVICE RESET 36682b79d384Sbing zhao - Sun Microsystems - Beijing China * OCCURRED 36692b79d384Sbing zhao - Sun Microsystems - Beijing China */ 3670904e51f6SJack Meng flush_io = B_TRUE; 36712b79d384Sbing zhao - Sun Microsystems - Beijing China break; 3672904e51f6SJack Meng case ISCSI_SCSI_LUNCHANGED_CODE: 3673904e51f6SJack Meng ascq = scsi_sense_ascq(sense_data); 3674904e51f6SJack Meng if (ascq == ISCSI_SCSI_LUNCHANGED_ASCQ) 3675904e51f6SJack Meng reconfig_lun = B_TRUE; 36762b79d384Sbing zhao - Sun Microsystems - Beijing China default: 36772b79d384Sbing zhao - Sun Microsystems - Beijing China break; 36782b79d384Sbing zhao - Sun Microsystems - Beijing China } 36792b79d384Sbing zhao - Sun Microsystems - Beijing China break; 36802b79d384Sbing zhao - Sun Microsystems - Beijing China default: 36812b79d384Sbing zhao - Sun Microsystems - Beijing China /* 36822b79d384Sbing zhao - Sun Microsystems - Beijing China * Currently we don't care 36832b79d384Sbing zhao - Sun Microsystems - Beijing China * about other sense key. 36842b79d384Sbing zhao - Sun Microsystems - Beijing China */ 36852b79d384Sbing zhao - Sun Microsystems - Beijing China break; 36862b79d384Sbing zhao - Sun Microsystems - Beijing China } 3687904e51f6SJack Meng 3688904e51f6SJack Meng if (reconfig_lun == B_TRUE) { 3689904e51f6SJack Meng rw_enter(&isp->sess_state_rwlock, RW_READER); 3690904e51f6SJack Meng if ((isp->sess_state == ISCSI_SESS_STATE_LOGGED_IN) && 3691904e51f6SJack Meng (iscsi_sess_enum_request(isp, B_FALSE, 3692904e51f6SJack Meng isp->sess_state_event_count) != 3693904e51f6SJack Meng ISCSI_SESS_ENUM_SUBMITTED)) { 3694904e51f6SJack Meng cmn_err(CE_WARN, "Unable to commit re-enumeration for" 3695904e51f6SJack Meng " session(%u) %s", isp->sess_oid, isp->sess_name); 3696904e51f6SJack Meng } 3697904e51f6SJack Meng rw_exit(&isp->sess_state_rwlock); 3698904e51f6SJack Meng } 3699904e51f6SJack Meng 3700904e51f6SJack Meng return (flush_io); 37012b79d384Sbing zhao - Sun Microsystems - Beijing China } 3702