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. 23fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24fcf3ce44SJohn Forte * Use is subject to license terms. 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() */ 36fcf3ce44SJohn Forte 37fcf3ce44SJohn Forte #include "iscsi.h" /* iscsi driver */ 38fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_protocol.h> /* iscsi protocol */ 39fcf3ce44SJohn Forte 40fcf3ce44SJohn Forte /* generic io helpers */ 41fcf3ce44SJohn Forte static uint32_t n2h24(uchar_t *ptr); 42fcf3ce44SJohn Forte static int iscsi_sna_lt(uint32_t n1, uint32_t n2); 43fcf3ce44SJohn Forte static void iscsi_update_flow_control(iscsi_sess_t *isp, 44fcf3ce44SJohn Forte uint32_t max, uint32_t exp); 45fcf3ce44SJohn Forte 46fcf3ce44SJohn Forte /* receivers */ 47fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_hdr(iscsi_conn_t *icp, 48fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data, int data_size); 49fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_nop(iscsi_conn_t *icp, 50fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 51fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_data_rsp(iscsi_conn_t *icp, 52fcf3ce44SJohn Forte iscsi_hdr_t *ihp); 53fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_cmd_rsp(iscsi_conn_t *icp, 54fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 55fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_rtt_rsp(iscsi_conn_t *icp, 56fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 57fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_reject_rsp(iscsi_conn_t *icp, 58fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 59fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_rejected_tsk_mgt(iscsi_conn_t *icp, 60fcf3ce44SJohn Forte iscsi_hdr_t *old_ihp); 61fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, 62fcf3ce44SJohn Forte iscsi_hdr_t *ihp, iscsi_cmd_t **icmdp); 63fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_task_mgt_rsp(iscsi_conn_t *icp, 64fcf3ce44SJohn Forte iscsi_hdr_t *ihp, void *data); 65fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_logout_rsp(iscsi_conn_t *icp, 66fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 67fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_async_rsp(iscsi_conn_t *icp, 68fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 69fcf3ce44SJohn Forte static iscsi_status_t iscsi_rx_process_text_rsp(iscsi_conn_t *icp, 70fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data); 71fcf3ce44SJohn Forte 72fcf3ce44SJohn Forte 73fcf3ce44SJohn Forte /* senders */ 74fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 75fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_r2t(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 76fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_data(iscsi_sess_t *isp, iscsi_conn_t *icp, 77fcf3ce44SJohn Forte iscsi_cmd_t *icmdp, uint32_t ttt, size_t datalen, size_t offset); 78fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 79fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 80fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 81fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 82fcf3ce44SJohn Forte static iscsi_status_t iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp); 83fcf3ce44SJohn Forte 84fcf3ce44SJohn Forte 85fcf3ce44SJohn Forte /* helpers */ 86fcf3ce44SJohn Forte static void iscsi_handle_r2t(iscsi_conn_t *icp, iscsi_cmd_t *icmdp, 87fcf3ce44SJohn Forte uint32_t offset, uint32_t length, uint32_t ttt); 88fcf3ce44SJohn Forte static void iscsi_handle_passthru_callback(struct scsi_pkt *pkt); 89fcf3ce44SJohn Forte static void iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt); 90fcf3ce44SJohn Forte 91fcf3ce44SJohn Forte static void iscsi_timeout_checks(iscsi_sess_t *isp); 92fcf3ce44SJohn Forte static void iscsi_nop_checks(iscsi_sess_t *isp); 93fcf3ce44SJohn Forte 94fcf3ce44SJohn Forte 95fcf3ce44SJohn Forte #define ISCSI_CONN_TO_NET_DIGEST(icp) \ 96fcf3ce44SJohn Forte ((icp->conn_params.header_digest ? ISCSI_NET_HEADER_DIGEST : 0) | \ 97fcf3ce44SJohn Forte (icp->conn_params.data_digest ? ISCSI_NET_DATA_DIGEST : 0)) 98fcf3ce44SJohn Forte 99fcf3ce44SJohn Forte /* 100fcf3ce44SJohn Forte * This file contains the main guts of the iSCSI protocol layer. 101fcf3ce44SJohn Forte * It's broken into 5 sections; Basic helper functions, RX IO path, 102fcf3ce44SJohn Forte * TX IO path, Completion (IC) IO path, and watchdog (WD) routines. 103fcf3ce44SJohn Forte * 104fcf3ce44SJohn Forte * The IO flow model is similiar to the below diagram. The 105fcf3ce44SJohn Forte * iscsi session, connection and command state machines are used 106fcf3ce44SJohn Forte * to drive IO through this flow diagram. Reference those files 107fcf3ce44SJohn Forte * to get a detailed description of their respective state models 108fcf3ce44SJohn Forte * prior to their xxx_state_machine_function(). 109fcf3ce44SJohn Forte * 110fcf3ce44SJohn Forte * tran_start() -> CMD_E1 TX_THREAD RX_THREAD 111fcf3ce44SJohn Forte * | T T 112fcf3ce44SJohn Forte * V T T 113fcf3ce44SJohn Forte * PENDING_Q --CMD_E2--> ACTIVE_Q - --CMD_E3--+ 114fcf3ce44SJohn Forte * T \ C T | 115fcf3ce44SJohn Forte * T \M T | 116fcf3ce44SJohn Forte * D T | 117fcf3ce44SJohn Forte * WD_THREAD TT|TT T | 118fcf3ce44SJohn Forte * /E T | 119fcf3ce44SJohn Forte * / 6 T | 120fcf3ce44SJohn Forte * ABORTING_Q<- --CMD_E3--+ 121fcf3ce44SJohn Forte * T | 122fcf3ce44SJohn Forte * T T | 123fcf3ce44SJohn Forte * T | 124fcf3ce44SJohn Forte * callback() <--CMD_E#-- COMPLETION_Q <------------+ 125fcf3ce44SJohn Forte * T 126fcf3ce44SJohn Forte * T 127fcf3ce44SJohn Forte * IC_THREAD 128fcf3ce44SJohn Forte * 129fcf3ce44SJohn Forte * External and internal command are ran thru this same state 130fcf3ce44SJohn Forte * machine. All commands enter the state machine by receiving an 131fcf3ce44SJohn Forte * ISCSI_CMD_EVENT_E1. This event places the command into the 132fcf3ce44SJohn Forte * PENDING_Q. Next when resources are available the TX_THREAD 133fcf3ce44SJohn Forte * issues a E2 event on the command. This sends the command 134fcf3ce44SJohn Forte * to the TCP stack and places the command on the ACTIVE_Q. While 135fcf3ce44SJohn Forte * on the PENDIING_Q and ACTIVE_Q, the command is monitored via the 136fcf3ce44SJohn Forte * WD_THREAD to ensure the pkt_time has not elapsed. If elapsed the 137fcf3ce44SJohn Forte * command is issued an E6(timeout) event which moves either (if pending) 138fcf3ce44SJohn Forte * completed the command or (if active) moves the command to the 139fcf3ce44SJohn Forte * aborting queue and issues a SCSI TASK MANAGEMENT ABORT command 140fcf3ce44SJohn Forte * to cancel the IO request. If the original command is completed 141fcf3ce44SJohn Forte * or the TASK MANAGEMENT command completes the command is moved 142fcf3ce44SJohn Forte * to the COMPLETION_Q via a E3 event. The IC_THREAD then processes 143fcf3ce44SJohn Forte * the COMPLETION_Q and issues the scsi_pkt callback. This 144fcf3ce44SJohn Forte * callback can not be processed directly from the RX_THREAD 145fcf3ce44SJohn Forte * because the callback might call back into the iscsi driver 146fcf3ce44SJohn Forte * causing a deadlock condition. 147fcf3ce44SJohn Forte * 148fcf3ce44SJohn Forte * For more details on the complete CMD state machine reference 149fcf3ce44SJohn Forte * the state machine diagram in iscsi_cmd.c. The connection state 150fcf3ce44SJohn Forte * machine is driven via IO events in this file. Then session 151fcf3ce44SJohn Forte * events are driven by the connection events. For complete 152fcf3ce44SJohn Forte * details on these state machines reference iscsi_sess.c and 153fcf3ce44SJohn Forte * iscsi_conn.c 154fcf3ce44SJohn Forte */ 155fcf3ce44SJohn Forte 156fcf3ce44SJohn Forte 157fcf3ce44SJohn Forte /* 158fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 159fcf3ce44SJohn Forte * | io helper routines | 160fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 161fcf3ce44SJohn Forte */ 162fcf3ce44SJohn Forte 163fcf3ce44SJohn Forte /* 164fcf3ce44SJohn Forte * n2h24 - native to host 24 bit integer translation. 165fcf3ce44SJohn Forte */ 166fcf3ce44SJohn Forte static uint32_t 167fcf3ce44SJohn Forte n2h24(uchar_t *ptr) 168fcf3ce44SJohn Forte { 169fcf3ce44SJohn Forte uint32_t idx; 170fcf3ce44SJohn Forte bcopy(ptr, &idx, 3); 171fcf3ce44SJohn Forte return (ntohl(idx) >> 8); 172fcf3ce44SJohn Forte } 173fcf3ce44SJohn Forte 174fcf3ce44SJohn Forte /* 175fcf3ce44SJohn Forte * iscsi_sna_lt - Serial Number Arithmetic, 32 bits, less than, RFC1982 176fcf3ce44SJohn Forte */ 177fcf3ce44SJohn Forte static int 178fcf3ce44SJohn Forte iscsi_sna_lt(uint32_t n1, uint32_t n2) 179fcf3ce44SJohn Forte { 180fcf3ce44SJohn Forte return ((n1 != n2) && 181fcf3ce44SJohn Forte (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) || 182fcf3ce44SJohn Forte ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK)))); 183fcf3ce44SJohn Forte } 184fcf3ce44SJohn Forte 185fcf3ce44SJohn Forte /* 186fcf3ce44SJohn Forte * iscsi_sna_lte - Serial Number Arithmetic, 32 bits, less than or equal, 187fcf3ce44SJohn Forte * RFC1982 188fcf3ce44SJohn Forte */ 189fcf3ce44SJohn Forte int 190fcf3ce44SJohn Forte iscsi_sna_lte(uint32_t n1, uint32_t n2) 191fcf3ce44SJohn Forte { 192fcf3ce44SJohn Forte return ((n1 == n2) || 193fcf3ce44SJohn Forte (((n1 < n2) && ((n2 - n1) < ISCSI_SNA32_CHECK)) || 194fcf3ce44SJohn Forte ((n1 > n2) && ((n1 - n2) > ISCSI_SNA32_CHECK)))); 195fcf3ce44SJohn Forte } 196fcf3ce44SJohn Forte 197fcf3ce44SJohn Forte /* 198fcf3ce44SJohn Forte * iscsi_update_flow_control - Update expcmdsn and maxcmdsn iSCSI 199fcf3ce44SJohn Forte * flow control information for a session 200fcf3ce44SJohn Forte */ 201fcf3ce44SJohn Forte static void 202fcf3ce44SJohn Forte iscsi_update_flow_control(iscsi_sess_t *isp, uint32_t max, uint32_t exp) 203fcf3ce44SJohn Forte { 204fcf3ce44SJohn Forte ASSERT(isp != NULL); 205fcf3ce44SJohn Forte ASSERT(mutex_owned(&isp->sess_cmdsn_mutex)); 206fcf3ce44SJohn Forte 207fcf3ce44SJohn Forte if (!iscsi_sna_lt(max, (exp - 1))) { 208fcf3ce44SJohn Forte 209fcf3ce44SJohn Forte if (!iscsi_sna_lte(exp, isp->sess_expcmdsn)) { 210fcf3ce44SJohn Forte isp->sess_expcmdsn = exp; 211fcf3ce44SJohn Forte } 212fcf3ce44SJohn Forte 213fcf3ce44SJohn Forte if (!iscsi_sna_lte(max, isp->sess_maxcmdsn)) { 214fcf3ce44SJohn Forte isp->sess_maxcmdsn = max; 215fcf3ce44SJohn Forte if (iscsi_sna_lte(isp->sess_cmdsn, 216fcf3ce44SJohn Forte isp->sess_maxcmdsn)) { 217fcf3ce44SJohn Forte /* 218fcf3ce44SJohn Forte * the window is open again - schedule 219fcf3ce44SJohn Forte * to send any held tasks soon 220fcf3ce44SJohn Forte */ 221fcf3ce44SJohn Forte iscsi_sess_redrive_io(isp); 222fcf3ce44SJohn Forte } 223fcf3ce44SJohn Forte } 224fcf3ce44SJohn Forte } 225fcf3ce44SJohn Forte } 226fcf3ce44SJohn Forte 227fcf3ce44SJohn Forte 228fcf3ce44SJohn Forte /* 229fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 230fcf3ce44SJohn Forte * | io receive and processing routines | 231fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 232fcf3ce44SJohn Forte */ 233fcf3ce44SJohn Forte 234fcf3ce44SJohn Forte /* 235fcf3ce44SJohn Forte * iscsi_rx_thread - The connection creates a thread of this 236fcf3ce44SJohn Forte * function during login. After which point this thread is 237fcf3ce44SJohn Forte * used to receive and process all iSCSI PDUs on this connection. 238fcf3ce44SJohn Forte * The PDUs received on this connection are used to drive the 239fcf3ce44SJohn Forte * commands through their state machine. This thread will 240fcf3ce44SJohn Forte * continue processing while the connection is on a LOGGED_IN 241fcf3ce44SJohn Forte * or IN_LOGOUT state. Once the connection moves out of this 242fcf3ce44SJohn Forte * state the thread will die. 243fcf3ce44SJohn Forte */ 244fcf3ce44SJohn Forte void 245fcf3ce44SJohn Forte iscsi_rx_thread(iscsi_thread_t *thread, void *arg) 246fcf3ce44SJohn Forte { 247fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 248fcf3ce44SJohn Forte iscsi_conn_t *icp = (iscsi_conn_t *)arg; 249fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 250fcf3ce44SJohn Forte char *hdr = NULL; 251fcf3ce44SJohn Forte int hdr_size = 0; 252fcf3ce44SJohn Forte char *data = NULL; 253fcf3ce44SJohn Forte int data_size = 0; 254fcf3ce44SJohn Forte iscsi_hdr_t *ihp; 255fcf3ce44SJohn Forte 256fcf3ce44SJohn Forte ASSERT(icp != NULL); 257fcf3ce44SJohn Forte isp = icp->conn_sess; 258fcf3ce44SJohn Forte ASSERT(isp != NULL); 259fcf3ce44SJohn Forte 260fcf3ce44SJohn Forte /* pre-alloc recv header buffer for common actions */ 261fcf3ce44SJohn Forte hdr_size = sizeof (iscsi_hdr_t) + 255; /* 255 = one byte hlength */ 262fcf3ce44SJohn Forte hdr = (char *)kmem_zalloc(hdr_size, KM_SLEEP); 263fcf3ce44SJohn Forte ihp = (iscsi_hdr_t *)hdr; 264fcf3ce44SJohn Forte ASSERT(ihp != NULL); 265fcf3ce44SJohn Forte 266fcf3ce44SJohn Forte /* pre-alloc max_recv_size buffer for common actions */ 267fcf3ce44SJohn Forte data_size = icp->conn_params.max_recv_data_seg_len; 268fcf3ce44SJohn Forte data = (char *)kmem_zalloc(data_size, KM_SLEEP); 269fcf3ce44SJohn Forte ASSERT(data != NULL); 270fcf3ce44SJohn Forte 271fcf3ce44SJohn Forte do { 272fcf3ce44SJohn Forte /* Wait for the next iSCSI header */ 273fcf3ce44SJohn Forte rval = iscsi_net->recvhdr(icp->conn_socket, 274fcf3ce44SJohn Forte ihp, hdr_size, 0, (icp->conn_params.header_digest ? 275fcf3ce44SJohn Forte ISCSI_NET_HEADER_DIGEST : 0)); 276fcf3ce44SJohn Forte if (ISCSI_SUCCESS(rval)) { 277fcf3ce44SJohn Forte isp->sess_rx_lbolt = 278fcf3ce44SJohn Forte icp->conn_rx_lbolt = 279fcf3ce44SJohn Forte ddi_get_lbolt(); 280fcf3ce44SJohn Forte 281fcf3ce44SJohn Forte /* Perform specific hdr handling */ 282fcf3ce44SJohn Forte rval = iscsi_rx_process_hdr(icp, ihp, 283fcf3ce44SJohn Forte data, data_size); 284fcf3ce44SJohn Forte } 285fcf3ce44SJohn Forte 286fcf3ce44SJohn Forte /* 287fcf3ce44SJohn Forte * handle failures 288fcf3ce44SJohn Forte */ 289fcf3ce44SJohn Forte switch (rval) { 290fcf3ce44SJohn Forte case ISCSI_STATUS_SUCCESS: 291fcf3ce44SJohn Forte /* 292fcf3ce44SJohn Forte * If we successfully completed a receive 293fcf3ce44SJohn Forte * and we are in an IN_FLUSH state then 294fcf3ce44SJohn Forte * check the active queue count to see 295fcf3ce44SJohn Forte * if its empty. If its empty then force 296fcf3ce44SJohn Forte * a disconnect event on the connection. 297fcf3ce44SJohn Forte * This will move the session from IN_FLUSH 298fcf3ce44SJohn Forte * to FLUSHED and complete the login 299fcf3ce44SJohn Forte * parameter update. 300fcf3ce44SJohn Forte */ 301fcf3ce44SJohn Forte if ((isp->sess_state == ISCSI_SESS_STATE_IN_FLUSH) && 302fcf3ce44SJohn Forte (icp->conn_queue_active.count == 0)) { 303fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 304fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, 305fcf3ce44SJohn Forte ISCSI_CONN_EVENT_T14); 306fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 307fcf3ce44SJohn Forte } 308fcf3ce44SJohn Forte break; 309fcf3ce44SJohn Forte case ISCSI_STATUS_TCP_RX_ERROR: 310fcf3ce44SJohn Forte /* connection had an error */ 311fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 312fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, 313fcf3ce44SJohn Forte ISCSI_CONN_EVENT_T15); 314fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 315fcf3ce44SJohn Forte break; 316fcf3ce44SJohn Forte case ISCSI_STATUS_HEADER_DIGEST_ERROR: 317fcf3ce44SJohn Forte /* 318fcf3ce44SJohn Forte * If we encounter a digest error we have to restart 319fcf3ce44SJohn Forte * all the connections on this session. per iSCSI 320fcf3ce44SJohn Forte * Level 0 Recovery. 321fcf3ce44SJohn Forte */ 322fcf3ce44SJohn Forte KSTAT_INC_CONN_ERR_HEADER_DIGEST(icp); 323fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 324fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, 325fcf3ce44SJohn Forte ISCSI_CONN_EVENT_T14); 326fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 327fcf3ce44SJohn Forte break; 328fcf3ce44SJohn Forte case ISCSI_STATUS_DATA_DIGEST_ERROR: 329fcf3ce44SJohn Forte /* 330fcf3ce44SJohn Forte * We can continue with a data digest error. The 331fcf3ce44SJohn Forte * icmdp was flaged as having a crc problem. It 332fcf3ce44SJohn Forte * will be aborted when all data is received. This 333fcf3ce44SJohn Forte * saves us from restarting the session when we 334fcf3ce44SJohn Forte * might be able to keep it going. If the data 335fcf3ce44SJohn Forte * digest issue was really bad we will hit a 336fcf3ce44SJohn Forte * status protocol error on the next pdu, which 337fcf3ce44SJohn Forte * will force a connection retstart. 338fcf3ce44SJohn Forte */ 339fcf3ce44SJohn Forte KSTAT_INC_CONN_ERR_DATA_DIGEST(icp); 340fcf3ce44SJohn Forte break; 341fcf3ce44SJohn Forte case ISCSI_STATUS_PROTOCOL_ERROR: 342fcf3ce44SJohn Forte /* 343fcf3ce44SJohn Forte * A protocol problem was encountered. Reset 344fcf3ce44SJohn Forte * session to try and repair issue. 345fcf3ce44SJohn Forte */ 346fcf3ce44SJohn Forte KSTAT_INC_CONN_ERR_PROTOCOL(icp); 347fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 348fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, 349fcf3ce44SJohn Forte ISCSI_CONN_EVENT_T14); 350fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 351fcf3ce44SJohn Forte break; 352fcf3ce44SJohn Forte case ISCSI_STATUS_INTERNAL_ERROR: 353fcf3ce44SJohn Forte /* 354fcf3ce44SJohn Forte * These should have all been handled before now. 355fcf3ce44SJohn Forte */ 356fcf3ce44SJohn Forte break; 357fcf3ce44SJohn Forte default: 358fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) encountered " 359fcf3ce44SJohn Forte "unknown error(%d) on a receive", icp->conn_oid, 360fcf3ce44SJohn Forte rval); 361fcf3ce44SJohn Forte ASSERT(B_FALSE); 362fcf3ce44SJohn Forte } 363fcf3ce44SJohn Forte 364fcf3ce44SJohn Forte } while ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) && 365fcf3ce44SJohn Forte (iscsi_thread_wait(thread, 0) != 0)); 366fcf3ce44SJohn Forte 367fcf3ce44SJohn Forte kmem_free(hdr, hdr_size); 368fcf3ce44SJohn Forte kmem_free(data, data_size); 369fcf3ce44SJohn Forte } 370fcf3ce44SJohn Forte 371fcf3ce44SJohn Forte 372fcf3ce44SJohn Forte /* 373fcf3ce44SJohn Forte * iscsi_rx_process_hdr - This function collects data for all PDUs 374fcf3ce44SJohn Forte * that do not have data that will be mapped to a specific scsi_pkt. 375fcf3ce44SJohn Forte * Then for each hdr type fan out the processing. 376fcf3ce44SJohn Forte */ 377fcf3ce44SJohn Forte static iscsi_status_t 378fcf3ce44SJohn Forte iscsi_rx_process_hdr(iscsi_conn_t *icp, iscsi_hdr_t *ihp, 379fcf3ce44SJohn Forte char *data, int data_size) 380fcf3ce44SJohn Forte { 381fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 382fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 383fcf3ce44SJohn Forte 384fcf3ce44SJohn Forte ASSERT(icp != NULL); 385fcf3ce44SJohn Forte ASSERT(ihp != NULL); 386fcf3ce44SJohn Forte ASSERT(data != NULL); 387fcf3ce44SJohn Forte isp = icp->conn_sess; 388fcf3ce44SJohn Forte ASSERT(isp != NULL); 389fcf3ce44SJohn Forte 390fcf3ce44SJohn Forte /* If this is not a SCSI_DATA_RSP we can go ahead and get the data */ 391fcf3ce44SJohn Forte if ((ihp->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_DATA_RSP) { 392fcf3ce44SJohn Forte rval = iscsi_net->recvdata(icp->conn_socket, ihp, 393fcf3ce44SJohn Forte data, data_size, 0, (icp->conn_params.data_digest) ? 394fcf3ce44SJohn Forte ISCSI_NET_DATA_DIGEST : 0); 395fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(rval)) { 396fcf3ce44SJohn Forte return (rval); 397fcf3ce44SJohn Forte } 398fcf3ce44SJohn Forte isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt(); 399fcf3ce44SJohn Forte } 400fcf3ce44SJohn Forte 401fcf3ce44SJohn Forte /* fan out the hdr processing */ 402fcf3ce44SJohn Forte switch (ihp->opcode & ISCSI_OPCODE_MASK) { 403fcf3ce44SJohn Forte case ISCSI_OP_SCSI_DATA_RSP: 404fcf3ce44SJohn Forte rval = iscsi_rx_process_data_rsp(icp, ihp); 405fcf3ce44SJohn Forte break; 406fcf3ce44SJohn Forte case ISCSI_OP_SCSI_RSP: 407fcf3ce44SJohn Forte rval = iscsi_rx_process_cmd_rsp(icp, ihp, data); 408fcf3ce44SJohn Forte break; 409fcf3ce44SJohn Forte case ISCSI_OP_RTT_RSP: 410fcf3ce44SJohn Forte rval = iscsi_rx_process_rtt_rsp(icp, ihp, data); 411fcf3ce44SJohn Forte break; 412fcf3ce44SJohn Forte case ISCSI_OP_NOOP_IN: 413fcf3ce44SJohn Forte rval = iscsi_rx_process_nop(icp, ihp, data); 414fcf3ce44SJohn Forte break; 415fcf3ce44SJohn Forte case ISCSI_OP_REJECT_MSG: 416fcf3ce44SJohn Forte rval = iscsi_rx_process_reject_rsp(icp, ihp, data); 417fcf3ce44SJohn Forte break; 418fcf3ce44SJohn Forte case ISCSI_OP_SCSI_TASK_MGT_RSP: 419fcf3ce44SJohn Forte rval = iscsi_rx_process_task_mgt_rsp(icp, ihp, data); 420fcf3ce44SJohn Forte break; 421fcf3ce44SJohn Forte case ISCSI_OP_LOGOUT_RSP: 422fcf3ce44SJohn Forte rval = iscsi_rx_process_logout_rsp(icp, ihp, data); 423fcf3ce44SJohn Forte break; 424fcf3ce44SJohn Forte case ISCSI_OP_ASYNC_EVENT: 425fcf3ce44SJohn Forte rval = iscsi_rx_process_async_rsp(icp, ihp, data); 426fcf3ce44SJohn Forte break; 427fcf3ce44SJohn Forte case ISCSI_OP_TEXT_RSP: 428fcf3ce44SJohn Forte rval = iscsi_rx_process_text_rsp(icp, ihp, data); 429fcf3ce44SJohn Forte break; 430fcf3ce44SJohn Forte default: 431fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 432fcf3ce44SJohn Forte "received an unsupported opcode 0x%02x", 433fcf3ce44SJohn Forte icp->conn_oid, ihp->opcode); 434fcf3ce44SJohn Forte rval = ISCSI_STATUS_PROTOCOL_ERROR; 435fcf3ce44SJohn Forte } 436fcf3ce44SJohn Forte 437fcf3ce44SJohn Forte return (rval); 438fcf3ce44SJohn Forte } 439fcf3ce44SJohn Forte 440fcf3ce44SJohn Forte 441fcf3ce44SJohn Forte /* 442fcf3ce44SJohn Forte * iscsi_rx_process_data_rsp - Processed received data header. Once 443fcf3ce44SJohn Forte * header is processed we read data off the connection directly into 444fcf3ce44SJohn Forte * the scsi_pkt to avoid duplicate bcopy of a large amount of data. 445fcf3ce44SJohn Forte * If this is the final data sequence denoted by the data response 446fcf3ce44SJohn Forte * PDU Status bit being set. We will not receive the SCSI response. 447fcf3ce44SJohn Forte * This bit denotes that the PDU is the successful completion of the 448fcf3ce44SJohn Forte * command. In this case complete the command. If This bit isn't 449fcf3ce44SJohn Forte * set we wait for more data or a scsi command response. 450fcf3ce44SJohn Forte */ 451fcf3ce44SJohn Forte static iscsi_status_t 452fcf3ce44SJohn Forte iscsi_rx_process_data_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp) 453fcf3ce44SJohn Forte { 454fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 455fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 456fcf3ce44SJohn Forte iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)ihp; 457fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 458fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 459fcf3ce44SJohn Forte struct buf *bp = NULL; 460fcf3ce44SJohn Forte uint32_t offset = 0; 461fcf3ce44SJohn Forte uint32_t dlength = 0; 462fcf3ce44SJohn Forte char *bcp = NULL; 463fcf3ce44SJohn Forte 464fcf3ce44SJohn Forte ASSERT(icp != NULL); 465fcf3ce44SJohn Forte ASSERT(ihp != NULL); 466fcf3ce44SJohn Forte isp = icp->conn_sess; 467fcf3ce44SJohn Forte ASSERT(isp != NULL); 468fcf3ce44SJohn Forte 469fcf3ce44SJohn Forte if (idrhp->flags & ISCSI_FLAG_DATA_STATUS) { 470fcf3ce44SJohn Forte /* make sure we got status in order */ 471fcf3ce44SJohn Forte if (icp->conn_expstatsn == ntohl(idrhp->statsn)) { 472fcf3ce44SJohn Forte icp->conn_expstatsn++; 473fcf3ce44SJohn Forte } else { 474fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error " 475fcf3ce44SJohn Forte "- received status out of order itt:0x%x " 476fcf3ce44SJohn Forte "statsn:0x%x expstatsn:0x%x", icp->conn_oid, 477fcf3ce44SJohn Forte idrhp->itt, ntohl(idrhp->statsn), 478fcf3ce44SJohn Forte icp->conn_expstatsn); 479fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 480fcf3ce44SJohn Forte } 481fcf3ce44SJohn Forte } 482fcf3ce44SJohn Forte 483fcf3ce44SJohn Forte /* match itt in the session's command table */ 484fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 485fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 486fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) { 487fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 488fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 489fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 490fcf3ce44SJohn Forte } 491fcf3ce44SJohn Forte /* 492fcf3ce44SJohn Forte * Holding the pending/active queue locks across the 493fcf3ce44SJohn Forte * iscsi_rx_data call later in this function may cause 494fcf3ce44SJohn Forte * deadlock during fault injections. Instead remove 495fcf3ce44SJohn Forte * the cmd from the active queue and release the locks. 496fcf3ce44SJohn Forte * Then before returning or completing the command 497fcf3ce44SJohn Forte * return the cmd to the active queue and reacquire 498fcf3ce44SJohn Forte * the locks. 499fcf3ce44SJohn Forte */ 500fcf3ce44SJohn Forte iscsi_dequeue_active_cmd(icp, icmdp); 501fcf3ce44SJohn Forte 502fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 503fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(idrhp->maxcmdsn), 504fcf3ce44SJohn Forte ntohl(idrhp->expcmdsn)); 505fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 506fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 507fcf3ce44SJohn Forte 508fcf3ce44SJohn Forte /* shorthand some values */ 509fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt; 510fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 511fcf3ce44SJohn Forte offset = ntohl(idrhp->offset); 512fcf3ce44SJohn Forte dlength = n2h24(idrhp->dlength); 513fcf3ce44SJohn Forte 514fcf3ce44SJohn Forte /* 515fcf3ce44SJohn Forte * some poorly behaved targets have been observed 516fcf3ce44SJohn Forte * sending data-in pdu's during a write operation 517fcf3ce44SJohn Forte */ 518fcf3ce44SJohn Forte if (bp != NULL) { 519fcf3ce44SJohn Forte if (!(bp->b_flags & B_READ)) { 520fcf3ce44SJohn Forte cmn_err(CE_WARN, 521fcf3ce44SJohn Forte "iscsi connection(%u) protocol error - " 522fcf3ce44SJohn Forte "received data response during write operation " 523fcf3ce44SJohn Forte "itt:0x%x", 524fcf3ce44SJohn Forte icp->conn_oid, idrhp->itt); 525fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 526fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(icp, icmdp); 527fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 528fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 529fcf3ce44SJohn Forte } 530fcf3ce44SJohn Forte 531fcf3ce44SJohn Forte /* 532fcf3ce44SJohn Forte * We can't tolerate the target sending too much 533fcf3ce44SJohn Forte * data for our buffer 534fcf3ce44SJohn Forte */ 535fcf3ce44SJohn Forte if ((dlength > 536fcf3ce44SJohn Forte (bp->b_bcount - icmdp->cmd_un.scsi.data_transferred)) || 537fcf3ce44SJohn Forte (dlength > (bp->b_bcount - offset))) { 538fcf3ce44SJohn Forte cmn_err(CE_WARN, 539fcf3ce44SJohn Forte "iscsi connection(%u) protocol error - " 540fcf3ce44SJohn Forte "received too much data itt:0x%x", 541fcf3ce44SJohn Forte icp->conn_oid, idrhp->itt); 542fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 543fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(icp, icmdp); 544fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 545fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 546fcf3ce44SJohn Forte } 547fcf3ce44SJohn Forte 548fcf3ce44SJohn Forte bcp = ((char *)bp->b_un.b_addr) + offset; 549fcf3ce44SJohn Forte 550fcf3ce44SJohn Forte /* 551fcf3ce44SJohn Forte * Get the rest of the data and copy it directly into 552fcf3ce44SJohn Forte * the scsi_pkt. 553fcf3ce44SJohn Forte */ 554fcf3ce44SJohn Forte rval = iscsi_net->recvdata(icp->conn_socket, ihp, 555fcf3ce44SJohn Forte bcp, dlength, 0, (icp->conn_params.data_digest ? 556fcf3ce44SJohn Forte ISCSI_NET_DATA_DIGEST : 0)); 557fcf3ce44SJohn Forte if (ISCSI_SUCCESS(rval)) { 558fcf3ce44SJohn Forte KSTAT_ADD_CONN_RX_BYTES(icp, dlength); 559fcf3ce44SJohn Forte } else { 560fcf3ce44SJohn Forte /* If digest error flag icmdp with a crc error */ 561fcf3ce44SJohn Forte if (rval == ISCSI_STATUS_DATA_DIGEST_ERROR) { 562fcf3ce44SJohn Forte icmdp->cmd_crc_error_seen = B_TRUE; 563fcf3ce44SJohn Forte } 564fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 565fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(icp, icmdp); 566fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 567fcf3ce44SJohn Forte return (rval); 568fcf3ce44SJohn Forte } 569fcf3ce44SJohn Forte isp->sess_rx_lbolt = icp->conn_rx_lbolt = ddi_get_lbolt(); 570fcf3ce44SJohn Forte 571fcf3ce44SJohn Forte /* update icmdp statistics */ 572fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred += dlength; 573fcf3ce44SJohn Forte } 574fcf3ce44SJohn Forte 575fcf3ce44SJohn Forte /* 576fcf3ce44SJohn Forte * We got status. This should only happen if we have 577fcf3ce44SJohn Forte * received all the data with no errors. The command 578fcf3ce44SJohn Forte * must be completed now, since we won't get a command 579fcf3ce44SJohn Forte * response PDU. The cmd_status and residual_count are 580fcf3ce44SJohn Forte * not meaningful unless status_present is set. 581fcf3ce44SJohn Forte */ 582fcf3ce44SJohn Forte if (idrhp->flags & ISCSI_FLAG_DATA_STATUS) { 583fcf3ce44SJohn Forte pkt->pkt_resid = 0; 584fcf3ce44SJohn Forte /* Check the residual count */ 585fcf3ce44SJohn Forte if (bp && 586fcf3ce44SJohn Forte (icmdp->cmd_un.scsi.data_transferred != 587fcf3ce44SJohn Forte bp->b_bcount)) { 588fcf3ce44SJohn Forte /* 589fcf3ce44SJohn Forte * We didn't xfer the expected amount of data - 590fcf3ce44SJohn Forte * the residual_count in the header is only valid 591fcf3ce44SJohn Forte * if the underflow flag is set. 592fcf3ce44SJohn Forte */ 593fcf3ce44SJohn Forte if (idrhp->flags & ISCSI_FLAG_DATA_UNDERFLOW) { 594fcf3ce44SJohn Forte pkt->pkt_resid = ntohl(idrhp->residual_count); 595fcf3ce44SJohn Forte } else { 596fcf3ce44SJohn Forte if (bp->b_bcount > 597fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred) { 598fcf3ce44SJohn Forte /* Some data fell on the floor somehw */ 599fcf3ce44SJohn Forte pkt->pkt_resid = 600fcf3ce44SJohn Forte bp->b_bcount - 601fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred; 602fcf3ce44SJohn Forte } 603fcf3ce44SJohn Forte } 604fcf3ce44SJohn Forte } 605fcf3ce44SJohn Forte 606fcf3ce44SJohn Forte pkt->pkt_reason = CMD_CMPLT; 607fcf3ce44SJohn Forte pkt->pkt_state |= (STATE_XFERRED_DATA | STATE_GOT_STATUS); 608fcf3ce44SJohn Forte 609fcf3ce44SJohn Forte if (((idrhp->cmd_status & STATUS_MASK) != STATUS_GOOD) && 610fcf3ce44SJohn Forte (icmdp->cmd_un.scsi.statuslen >= 611fcf3ce44SJohn Forte sizeof (struct scsi_arq_status)) && pkt->pkt_scbp) { 612fcf3ce44SJohn Forte 613fcf3ce44SJohn Forte /* 614fcf3ce44SJohn Forte * Not supposed to get exception status here! 615fcf3ce44SJohn Forte * We have no request sense data so just do the 616fcf3ce44SJohn Forte * best we can 617fcf3ce44SJohn Forte */ 618fcf3ce44SJohn Forte struct scsi_arq_status *arqstat = 619fcf3ce44SJohn Forte (struct scsi_arq_status *)pkt->pkt_scbp; 620fcf3ce44SJohn Forte 621fcf3ce44SJohn Forte 622fcf3ce44SJohn Forte bzero(arqstat, sizeof (struct scsi_arq_status)); 623fcf3ce44SJohn Forte 624fcf3ce44SJohn Forte *((uchar_t *)&arqstat->sts_status) = 625fcf3ce44SJohn Forte idrhp->cmd_status; 626fcf3ce44SJohn Forte 627fcf3ce44SJohn Forte arqstat->sts_rqpkt_resid = 628fcf3ce44SJohn Forte sizeof (struct scsi_extended_sense); 629fcf3ce44SJohn Forte 630fcf3ce44SJohn Forte } else if (pkt->pkt_scbp) { 631fcf3ce44SJohn Forte /* just pass along the status we got */ 632fcf3ce44SJohn Forte pkt->pkt_scbp[0] = idrhp->cmd_status; 633fcf3ce44SJohn Forte } 634fcf3ce44SJohn Forte 635fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 636fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(icp, icmdp); 637fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 638fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 639fcf3ce44SJohn Forte } else { 640fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 641fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(icp, icmdp); 642fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 643fcf3ce44SJohn Forte } 644fcf3ce44SJohn Forte 645fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 646fcf3ce44SJohn Forte } 647fcf3ce44SJohn Forte 648fcf3ce44SJohn Forte 649fcf3ce44SJohn Forte /* 650fcf3ce44SJohn Forte * iscsi_rx_process_cmd_rsp - Process received scsi command response. This 651fcf3ce44SJohn Forte * will contain sense data if the command was not successful. This data needs 652fcf3ce44SJohn Forte * to be copied into the scsi_pkt. Otherwise we just complete the IO. 653fcf3ce44SJohn Forte */ 654fcf3ce44SJohn Forte static iscsi_status_t 655fcf3ce44SJohn Forte iscsi_rx_process_cmd_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 656fcf3ce44SJohn Forte { 657fcf3ce44SJohn Forte iscsi_sess_t *isp = icp->conn_sess; 658fcf3ce44SJohn Forte iscsi_scsi_rsp_hdr_t *issrhp = (iscsi_scsi_rsp_hdr_t *)ihp; 659fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 660fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 661fcf3ce44SJohn Forte uint32_t dlength = 0; 662fcf3ce44SJohn Forte struct scsi_arq_status *arqstat = NULL; 663fcf3ce44SJohn Forte size_t senselen = 0; 664*b4243054SSheng-Liang Eric Zhang int statuslen = 0; 665fcf3ce44SJohn Forte 666fcf3ce44SJohn Forte /* make sure we get status in order */ 667fcf3ce44SJohn Forte if (icp->conn_expstatsn == ntohl(issrhp->statsn)) { 668fcf3ce44SJohn Forte icp->conn_expstatsn++; 669fcf3ce44SJohn Forte } else { 670fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 671fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 672fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, issrhp->itt, 673fcf3ce44SJohn Forte ntohl(issrhp->statsn), icp->conn_expstatsn); 674fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 675fcf3ce44SJohn Forte } 676fcf3ce44SJohn Forte 677fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 678fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 679fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) { 680fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 681fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 682fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 683fcf3ce44SJohn Forte } 684fcf3ce44SJohn Forte 685fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 686fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(issrhp->maxcmdsn), 687fcf3ce44SJohn Forte ntohl(issrhp->expcmdsn)); 688fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 689fcf3ce44SJohn Forte 690fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt; 691fcf3ce44SJohn Forte 692fcf3ce44SJohn Forte if (issrhp->response) { 693fcf3ce44SJohn Forte /* The target failed the command. */ 694fcf3ce44SJohn Forte pkt->pkt_reason = CMD_TRAN_ERR; 695fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp) { 696fcf3ce44SJohn Forte pkt->pkt_resid = icmdp->cmd_un.scsi.bp->b_bcount; 697fcf3ce44SJohn Forte } else { 698fcf3ce44SJohn Forte pkt->pkt_resid = 0; 699fcf3ce44SJohn Forte } 700fcf3ce44SJohn Forte } else { 701fcf3ce44SJohn Forte /* success */ 702fcf3ce44SJohn Forte pkt->pkt_resid = 0; 703fcf3ce44SJohn Forte /* Check the residual count */ 704fcf3ce44SJohn Forte if ((icmdp->cmd_un.scsi.bp) && 705fcf3ce44SJohn Forte (icmdp->cmd_un.scsi.data_transferred != 706fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp->b_bcount)) { 707fcf3ce44SJohn Forte /* 708fcf3ce44SJohn Forte * We didn't xfer the expected amount of data - 709fcf3ce44SJohn Forte * the residual_count in the header is only 710fcf3ce44SJohn Forte * valid if the underflow flag is set. 711fcf3ce44SJohn Forte */ 712fcf3ce44SJohn Forte if (issrhp->flags & ISCSI_FLAG_CMD_UNDERFLOW) { 713fcf3ce44SJohn Forte pkt->pkt_resid = ntohl(issrhp->residual_count); 714fcf3ce44SJohn Forte } else { 715fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp->b_bcount > 716fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred) { 717fcf3ce44SJohn Forte /* 718fcf3ce44SJohn Forte * Some data fell on the floor 719fcf3ce44SJohn Forte * somehow - probably a CRC error 720fcf3ce44SJohn Forte */ 721fcf3ce44SJohn Forte pkt->pkt_resid = 722fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp->b_bcount - 723fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred; 724fcf3ce44SJohn Forte } 725fcf3ce44SJohn Forte } 726fcf3ce44SJohn Forte } 727fcf3ce44SJohn Forte 728fcf3ce44SJohn Forte /* set flags that tell SCSA that the command is complete */ 729fcf3ce44SJohn Forte if (icmdp->cmd_crc_error_seen == B_FALSE) { 730fcf3ce44SJohn Forte /* Set successful completion */ 731fcf3ce44SJohn Forte pkt->pkt_reason = CMD_CMPLT; 732fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp) { 733fcf3ce44SJohn Forte pkt->pkt_state |= (STATE_XFERRED_DATA | 734fcf3ce44SJohn Forte STATE_GOT_STATUS); 735fcf3ce44SJohn Forte } else { 736fcf3ce44SJohn Forte pkt->pkt_state |= STATE_GOT_STATUS; 737fcf3ce44SJohn Forte } 738fcf3ce44SJohn Forte } else { 739fcf3ce44SJohn Forte /* 740fcf3ce44SJohn Forte * Some of the data was found to have an incorrect 741fcf3ce44SJohn Forte * error at the protocol error. 742fcf3ce44SJohn Forte */ 743fcf3ce44SJohn Forte pkt->pkt_reason = CMD_PER_FAIL; 744fcf3ce44SJohn Forte pkt->pkt_statistics |= STAT_PERR; 745fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.bp) { 746fcf3ce44SJohn Forte pkt->pkt_resid = 747fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp->b_bcount; 748fcf3ce44SJohn Forte } else { 749fcf3ce44SJohn Forte pkt->pkt_resid = 0; 750fcf3ce44SJohn Forte } 751fcf3ce44SJohn Forte } 752fcf3ce44SJohn Forte 753fcf3ce44SJohn Forte dlength = n2h24(issrhp->dlength); 754fcf3ce44SJohn Forte 755fcf3ce44SJohn Forte /* 756fcf3ce44SJohn Forte * Process iSCSI Cmd Response Status 757fcf3ce44SJohn Forte * RFC 3720 Sectionn 10.4.2. 758fcf3ce44SJohn Forte */ 759fcf3ce44SJohn Forte switch (issrhp->cmd_status & STATUS_MASK) { 760fcf3ce44SJohn Forte case STATUS_GOOD: 761fcf3ce44SJohn Forte /* pass SCSI status up stack */ 762fcf3ce44SJohn Forte if (pkt->pkt_scbp) { 763fcf3ce44SJohn Forte pkt->pkt_scbp[0] = issrhp->cmd_status; 764fcf3ce44SJohn Forte } 765fcf3ce44SJohn Forte break; 766fcf3ce44SJohn Forte case STATUS_CHECK: 767fcf3ce44SJohn Forte /* 768fcf3ce44SJohn Forte * Verify we received a sense buffer and 769fcf3ce44SJohn Forte * that there is the correct amount of 770fcf3ce44SJohn Forte * request sense space to copy it to. 771fcf3ce44SJohn Forte */ 772fcf3ce44SJohn Forte if ((dlength > 1) && 773fcf3ce44SJohn Forte (pkt->pkt_scbp != NULL) && 774fcf3ce44SJohn Forte (icmdp->cmd_un.scsi.statuslen >= 775fcf3ce44SJohn Forte sizeof (struct scsi_arq_status))) { 776fcf3ce44SJohn Forte /* 777fcf3ce44SJohn Forte * If a bad command status is received we 778fcf3ce44SJohn Forte * need to reset the pkt_resid to zero. 779fcf3ce44SJohn Forte * The target driver compares its value 780fcf3ce44SJohn Forte * before checking other error flags. 781fcf3ce44SJohn Forte * (ex. check conditions) 782fcf3ce44SJohn Forte */ 783fcf3ce44SJohn Forte pkt->pkt_resid = 0; 784fcf3ce44SJohn Forte 785fcf3ce44SJohn Forte /* get sense length from first 2 bytes */ 786fcf3ce44SJohn Forte senselen = ((data[0] << 8) | data[1]) & 787fcf3ce44SJohn Forte (size_t)0xFFFF; 788fcf3ce44SJohn Forte 789fcf3ce44SJohn Forte /* Sanity-check on the sense length */ 790fcf3ce44SJohn Forte if ((senselen + 2) > dlength) { 791fcf3ce44SJohn Forte senselen = dlength - 2; 792fcf3ce44SJohn Forte } 793fcf3ce44SJohn Forte 794fcf3ce44SJohn Forte /* 795fcf3ce44SJohn Forte * If there was a Data Digest error then 796fcf3ce44SJohn Forte * the sense data cannot be trusted. 797fcf3ce44SJohn Forte */ 798fcf3ce44SJohn Forte if (icmdp->cmd_crc_error_seen) { 799fcf3ce44SJohn Forte senselen = 0; 800fcf3ce44SJohn Forte } 801fcf3ce44SJohn Forte 802fcf3ce44SJohn Forte /* automatic request sense */ 803fcf3ce44SJohn Forte arqstat = 804fcf3ce44SJohn Forte (struct scsi_arq_status *)pkt->pkt_scbp; 805fcf3ce44SJohn Forte 806fcf3ce44SJohn Forte /* pass SCSI status up stack */ 807fcf3ce44SJohn Forte *((uchar_t *)&arqstat->sts_status) = 808fcf3ce44SJohn Forte issrhp->cmd_status; 809fcf3ce44SJohn Forte 810fcf3ce44SJohn Forte /* 811fcf3ce44SJohn Forte * Set the status for the automatic 812fcf3ce44SJohn Forte * request sense command 813fcf3ce44SJohn Forte */ 814fcf3ce44SJohn Forte arqstat->sts_rqpkt_state = (STATE_GOT_BUS | 815fcf3ce44SJohn Forte STATE_GOT_TARGET | STATE_SENT_CMD | 816fcf3ce44SJohn Forte STATE_XFERRED_DATA | STATE_GOT_STATUS | 817fcf3ce44SJohn Forte STATE_ARQ_DONE); 818fcf3ce44SJohn Forte 819fcf3ce44SJohn Forte *((uchar_t *)&arqstat->sts_rqpkt_status) = 820fcf3ce44SJohn Forte STATUS_GOOD; 821fcf3ce44SJohn Forte 822fcf3ce44SJohn Forte arqstat->sts_rqpkt_reason = CMD_CMPLT; 823fcf3ce44SJohn Forte 824*b4243054SSheng-Liang Eric Zhang statuslen = icmdp->cmd_un.scsi.statuslen; 825*b4243054SSheng-Liang Eric Zhang 826fcf3ce44SJohn Forte if (senselen == 0) { 827fcf3ce44SJohn Forte /* auto request sense failed */ 828fcf3ce44SJohn Forte arqstat->sts_rqpkt_status.sts_chk = 1; 829fcf3ce44SJohn Forte arqstat->sts_rqpkt_resid = 830*b4243054SSheng-Liang Eric Zhang statuslen; 831fcf3ce44SJohn Forte } else if (senselen < 832*b4243054SSheng-Liang Eric Zhang statuslen) { 833fcf3ce44SJohn Forte /* auto request sense short */ 834fcf3ce44SJohn Forte arqstat->sts_rqpkt_resid = 835*b4243054SSheng-Liang Eric Zhang statuslen 836fcf3ce44SJohn Forte - senselen; 837fcf3ce44SJohn Forte } else { 838fcf3ce44SJohn Forte /* auto request sense complete */ 839fcf3ce44SJohn Forte arqstat->sts_rqpkt_resid = 0; 840fcf3ce44SJohn Forte } 841fcf3ce44SJohn Forte arqstat->sts_rqpkt_statistics = 0; 842fcf3ce44SJohn Forte pkt->pkt_state |= STATE_ARQ_DONE; 843fcf3ce44SJohn Forte 844*b4243054SSheng-Liang Eric Zhang if (icmdp->cmd_misc_flags & 845*b4243054SSheng-Liang Eric Zhang ISCSI_CMD_MISCFLAG_XARQ) { 846*b4243054SSheng-Liang Eric Zhang pkt->pkt_state |= STATE_XARQ_DONE; 847*b4243054SSheng-Liang Eric Zhang } 848*b4243054SSheng-Liang Eric Zhang 849fcf3ce44SJohn Forte /* copy auto request sense */ 850fcf3ce44SJohn Forte dlength = min(senselen, 851*b4243054SSheng-Liang Eric Zhang statuslen); 852fcf3ce44SJohn Forte if (dlength) { 853fcf3ce44SJohn Forte bcopy(&data[2], (uchar_t *)&arqstat-> 854fcf3ce44SJohn Forte sts_sensedata, dlength); 855fcf3ce44SJohn Forte } 856fcf3ce44SJohn Forte break; 857fcf3ce44SJohn Forte } 858fcf3ce44SJohn Forte /* FALLTHRU */ 859fcf3ce44SJohn Forte case STATUS_BUSY: 860fcf3ce44SJohn Forte case STATUS_RESERVATION_CONFLICT: 861fcf3ce44SJohn Forte case STATUS_QFULL: 862fcf3ce44SJohn Forte case STATUS_ACA_ACTIVE: 863fcf3ce44SJohn Forte default: 864fcf3ce44SJohn Forte /* 865fcf3ce44SJohn Forte * If a bad command status is received we need to 866fcf3ce44SJohn Forte * reset the pkt_resid to zero. The target driver 867fcf3ce44SJohn Forte * compares its value before checking other error 868fcf3ce44SJohn Forte * flags. (ex. check conditions) 869fcf3ce44SJohn Forte */ 870fcf3ce44SJohn Forte pkt->pkt_resid = 0; 871fcf3ce44SJohn Forte /* pass SCSI status up stack */ 872fcf3ce44SJohn Forte if (pkt->pkt_scbp) { 873fcf3ce44SJohn Forte pkt->pkt_scbp[0] = issrhp->cmd_status; 874fcf3ce44SJohn Forte } 875fcf3ce44SJohn Forte } 876fcf3ce44SJohn Forte } 877fcf3ce44SJohn Forte 878fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 879fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 880fcf3ce44SJohn Forte 881fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 882fcf3ce44SJohn Forte } 883fcf3ce44SJohn Forte 884fcf3ce44SJohn Forte /* 885fcf3ce44SJohn Forte * iscsi_rx_process_rtt_rsp - Process received RTT. This means the target is 886fcf3ce44SJohn Forte * requesting data. 887fcf3ce44SJohn Forte */ 888fcf3ce44SJohn Forte /* ARGSUSED */ 889fcf3ce44SJohn Forte static iscsi_status_t 890fcf3ce44SJohn Forte iscsi_rx_process_rtt_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 891fcf3ce44SJohn Forte { 892fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)icp->conn_sess; 893fcf3ce44SJohn Forte iscsi_rtt_hdr_t *irhp = (iscsi_rtt_hdr_t *)ihp; 894fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 895fcf3ce44SJohn Forte struct buf *bp = NULL; 896fcf3ce44SJohn Forte uint32_t data_length; 897fcf3ce44SJohn Forte iscsi_status_t status = ISCSI_STATUS_PROTOCOL_ERROR; 898fcf3ce44SJohn Forte 899fcf3ce44SJohn Forte 900fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 901fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 902fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 903fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) { 904fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 905fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 906fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 907fcf3ce44SJohn Forte return (status); 908fcf3ce44SJohn Forte } 909fcf3ce44SJohn Forte 910fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 911fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(irhp->maxcmdsn), 912fcf3ce44SJohn Forte ntohl(irhp->expcmdsn)); 913fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 914fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 915fcf3ce44SJohn Forte 916fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 917fcf3ce44SJohn Forte data_length = ntohl(irhp->data_length); 918fcf3ce44SJohn Forte 919fcf3ce44SJohn Forte /* 920fcf3ce44SJohn Forte * Perform boundary-checks per RFC 3720 (section 10.8.4). 921fcf3ce44SJohn Forte * The Desired Data Transfer Length must satisfy this relation: 922fcf3ce44SJohn Forte * 923fcf3ce44SJohn Forte * 0 < Desired Data Transfer Length <= MaxBurstLength 924fcf3ce44SJohn Forte */ 925fcf3ce44SJohn Forte if ((bp == NULL) || (data_length == 0)) { 926fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) received r2t but pkt " 927fcf3ce44SJohn Forte "has no data itt:0x%x - protocol error", icp->conn_oid, 928fcf3ce44SJohn Forte irhp->itt); 929fcf3ce44SJohn Forte } else if (data_length > icp->conn_params.max_burst_length) { 930fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) received r2t but pkt " 931fcf3ce44SJohn Forte "is larger than MaxBurstLength itt:0x%x len:0x%x - " 932fcf3ce44SJohn Forte "protocol error", 933fcf3ce44SJohn Forte icp->conn_oid, irhp->itt, data_length); 934fcf3ce44SJohn Forte } else { 935fcf3ce44SJohn Forte iscsi_handle_r2t(icp, icmdp, ntohl(irhp->data_offset), 936fcf3ce44SJohn Forte data_length, irhp->ttt); 937fcf3ce44SJohn Forte status = ISCSI_STATUS_SUCCESS; 938fcf3ce44SJohn Forte } 939fcf3ce44SJohn Forte 940fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 941fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 942fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 943fcf3ce44SJohn Forte 944fcf3ce44SJohn Forte return (status); 945fcf3ce44SJohn Forte } 946fcf3ce44SJohn Forte 947fcf3ce44SJohn Forte 948fcf3ce44SJohn Forte /* 949fcf3ce44SJohn Forte * iscsi_rx_process_nop - Process a received nop. If nop is in response 950fcf3ce44SJohn Forte * to a ping we sent update stats. If initiated by the target we need 951fcf3ce44SJohn Forte * to response back to the target with a nop. Schedule the response. 952fcf3ce44SJohn Forte */ 953fcf3ce44SJohn Forte /* ARGSUSED */ 954fcf3ce44SJohn Forte static iscsi_status_t 955fcf3ce44SJohn Forte iscsi_rx_process_nop(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 956fcf3ce44SJohn Forte { 957fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 958fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 959fcf3ce44SJohn Forte iscsi_nop_in_hdr_t *inihp = (iscsi_nop_in_hdr_t *)ihp; 960fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 961fcf3ce44SJohn Forte 962fcf3ce44SJohn Forte ASSERT(icp != NULL); 963fcf3ce44SJohn Forte ASSERT(ihp != NULL); 964fcf3ce44SJohn Forte /* ASSERT(data != NULL) data is allowed to be NULL */ 965fcf3ce44SJohn Forte isp = icp->conn_sess; 966fcf3ce44SJohn Forte ASSERT(isp != NULL); 967fcf3ce44SJohn Forte 968fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(inihp->statsn)) { 969fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 970fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 971fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, inihp->itt, 972fcf3ce44SJohn Forte ntohl(inihp->statsn), icp->conn_expstatsn); 973fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 974fcf3ce44SJohn Forte } 975fcf3ce44SJohn Forte 976fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 977fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 978fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 979fcf3ce44SJohn Forte if (inihp->itt != ISCSI_RSVD_TASK_TAG) { 980fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 981fcf3ce44SJohn Forte isp, ihp, &icmdp))) { 982fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 983fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 984fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 985fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 986fcf3ce44SJohn Forte } 987fcf3ce44SJohn Forte } 988fcf3ce44SJohn Forte 989fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 990fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(inihp->maxcmdsn), 991fcf3ce44SJohn Forte ntohl(inihp->expcmdsn)); 992fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 993fcf3ce44SJohn Forte 994fcf3ce44SJohn Forte if ((inihp->itt != ISCSI_RSVD_TASK_TAG) && 995fcf3ce44SJohn Forte (inihp->ttt == ISCSI_RSVD_TASK_TAG)) { 996fcf3ce44SJohn Forte /* This is the only type of nop that incs. the expstatsn */ 997fcf3ce44SJohn Forte icp->conn_expstatsn++; 998fcf3ce44SJohn Forte 999fcf3ce44SJohn Forte /* 1000fcf3ce44SJohn Forte * This is a targets response to our nop 1001fcf3ce44SJohn Forte */ 1002fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1003fcf3ce44SJohn Forte } else if (inihp->ttt != ISCSI_RSVD_TASK_TAG) { 1004fcf3ce44SJohn Forte /* 1005fcf3ce44SJohn Forte * Target requested a nop. Send one. 1006fcf3ce44SJohn Forte */ 1007fcf3ce44SJohn Forte iscsi_handle_nop(icp, ISCSI_RSVD_TASK_TAG, inihp->ttt); 1008fcf3ce44SJohn Forte } else { 1009fcf3ce44SJohn Forte /* 1010fcf3ce44SJohn Forte * This is a target-initiated ping that doesn't expect 1011fcf3ce44SJohn Forte * a response; nothing to do except update our flow control 1012fcf3ce44SJohn Forte * (which we do in all cases above). 1013fcf3ce44SJohn Forte */ 1014fcf3ce44SJohn Forte /* EMPTY */ 1015fcf3ce44SJohn Forte } 1016fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1017fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 1018fcf3ce44SJohn Forte 1019fcf3ce44SJohn Forte return (rval); 1020fcf3ce44SJohn Forte } 1021fcf3ce44SJohn Forte 1022fcf3ce44SJohn Forte 1023fcf3ce44SJohn Forte /* 1024fcf3ce44SJohn Forte * iscsi_rx_process_reject_rsp - The server rejected a PDU 1025fcf3ce44SJohn Forte */ 1026fcf3ce44SJohn Forte static iscsi_status_t 1027fcf3ce44SJohn Forte iscsi_rx_process_reject_rsp(iscsi_conn_t *icp, 1028fcf3ce44SJohn Forte iscsi_hdr_t *ihp, char *data) 1029fcf3ce44SJohn Forte { 1030fcf3ce44SJohn Forte iscsi_reject_rsp_hdr_t *irrhp = (iscsi_reject_rsp_hdr_t *)ihp; 1031fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1032fcf3ce44SJohn Forte uint32_t dlength = 0; 1033fcf3ce44SJohn Forte iscsi_hdr_t *old_ihp = NULL; 1034fcf3ce44SJohn Forte 1035fcf3ce44SJohn Forte ASSERT(icp != NULL); 1036fcf3ce44SJohn Forte isp = icp->conn_sess; 1037fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1038fcf3ce44SJohn Forte ASSERT(data != NULL); 1039fcf3ce44SJohn Forte 1040fcf3ce44SJohn Forte /* make sure we only Ack Status numbers that we've actually received. */ 1041fcf3ce44SJohn Forte if (icp->conn_expstatsn == ntohl(irrhp->statsn)) { 1042fcf3ce44SJohn Forte icp->conn_expstatsn++; 1043fcf3ce44SJohn Forte } else { 1044fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1045fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 1046fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, ihp->itt, 1047fcf3ce44SJohn Forte ntohl(irrhp->statsn), icp->conn_expstatsn); 1048fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1049fcf3ce44SJohn Forte } 1050fcf3ce44SJohn Forte 1051fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 1052fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1053fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(irrhp->maxcmdsn), 1054fcf3ce44SJohn Forte ntohl(irrhp->expcmdsn)); 1055fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1056fcf3ce44SJohn Forte 1057fcf3ce44SJohn Forte /* If we don't have the rejected header we can't do anything */ 1058fcf3ce44SJohn Forte dlength = n2h24(irrhp->dlength); 1059fcf3ce44SJohn Forte if (dlength < sizeof (iscsi_hdr_t)) { 1060fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1061fcf3ce44SJohn Forte } 1062fcf3ce44SJohn Forte 1063fcf3ce44SJohn Forte /* map old ihp */ 1064fcf3ce44SJohn Forte old_ihp = (iscsi_hdr_t *)data; 1065fcf3ce44SJohn Forte 1066fcf3ce44SJohn Forte switch (irrhp->reason) { 1067fcf3ce44SJohn Forte /* 1068fcf3ce44SJohn Forte * ISCSI_REJECT_IMM_CMD_REJECT - Immediate Command Reject 1069fcf3ce44SJohn Forte * too many immediate commands (original cmd can be resent) 1070fcf3ce44SJohn Forte */ 1071fcf3ce44SJohn Forte case ISCSI_REJECT_IMM_CMD_REJECT: 1072fcf3ce44SJohn Forte /* 1073fcf3ce44SJohn Forte * We have exceeded the server's capacity for outstanding 1074fcf3ce44SJohn Forte * immediate commands. This must be a task management 1075fcf3ce44SJohn Forte * command so try to find it in the abortingqueue and 1076fcf3ce44SJohn Forte * complete it. 1077fcf3ce44SJohn Forte */ 1078fcf3ce44SJohn Forte if (!(old_ihp->opcode & ISCSI_OP_IMMEDIATE)) { 1079fcf3ce44SJohn Forte /* Rejecting IMM but old old_hdr wasn't IMM */ 1080fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1081fcf3ce44SJohn Forte } 1082fcf3ce44SJohn Forte 1083fcf3ce44SJohn Forte /* 1084fcf3ce44SJohn Forte * We only send NOP and TASK_MGT as IMM. All other 1085fcf3ce44SJohn Forte * cases should be considered as a protocol error. 1086fcf3ce44SJohn Forte */ 1087fcf3ce44SJohn Forte switch (old_ihp->opcode & ISCSI_OPCODE_MASK) { 1088fcf3ce44SJohn Forte case ISCSI_OP_NOOP_OUT: 1089fcf3ce44SJohn Forte /* 1090fcf3ce44SJohn Forte * A ping was rejected - treat this like 1091fcf3ce44SJohn Forte * ping response. The down side is we 1092fcf3ce44SJohn Forte * didn't get an updated MaxCmdSn. 1093fcf3ce44SJohn Forte */ 1094fcf3ce44SJohn Forte break; 1095fcf3ce44SJohn Forte case ISCSI_OP_SCSI_TASK_MGT_MSG: 1096fcf3ce44SJohn Forte (void) iscsi_rx_process_rejected_tsk_mgt(icp, 1097fcf3ce44SJohn Forte old_ihp); 1098fcf3ce44SJohn Forte break; 1099fcf3ce44SJohn Forte default: 1100fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error " 1101fcf3ce44SJohn Forte "- received a reject for a command(0x%02x) not " 1102fcf3ce44SJohn Forte "sent as an immediate", icp->conn_oid, 1103fcf3ce44SJohn Forte old_ihp->opcode); 1104fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1105fcf3ce44SJohn Forte } 1106fcf3ce44SJohn Forte break; 1107fcf3ce44SJohn Forte 1108fcf3ce44SJohn Forte /* 1109fcf3ce44SJohn Forte * For the rest of the reject cases just use the general 1110fcf3ce44SJohn Forte * hammer of dis/reconnecting. This will resolve all 1111fcf3ce44SJohn Forte * noted issues although could be more graceful. 1112fcf3ce44SJohn Forte */ 1113fcf3ce44SJohn Forte case ISCSI_REJECT_DATA_DIGEST_ERROR: 1114fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_BEFORE_LOGIN: 1115fcf3ce44SJohn Forte case ISCSI_REJECT_SNACK_REJECT: 1116fcf3ce44SJohn Forte case ISCSI_REJECT_PROTOCOL_ERROR: 1117fcf3ce44SJohn Forte case ISCSI_REJECT_CMD_NOT_SUPPORTED: 1118fcf3ce44SJohn Forte case ISCSI_REJECT_TASK_IN_PROGRESS: 1119fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_DATA_ACK: 1120fcf3ce44SJohn Forte case ISCSI_REJECT_INVALID_PDU_FIELD: 1121fcf3ce44SJohn Forte case ISCSI_REJECT_LONG_OPERATION_REJECT: 1122fcf3ce44SJohn Forte case ISCSI_REJECT_NEGOTIATION_RESET: 1123fcf3ce44SJohn Forte default: 1124fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) closing connection - " 1125fcf3ce44SJohn Forte "target requested itt:0x%x reason:0x%x", 1126fcf3ce44SJohn Forte icp->conn_oid, ihp->itt, irrhp->reason); 1127fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1128fcf3ce44SJohn Forte } 1129fcf3ce44SJohn Forte 1130fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1131fcf3ce44SJohn Forte } 1132fcf3ce44SJohn Forte 1133fcf3ce44SJohn Forte 1134fcf3ce44SJohn Forte /* 1135fcf3ce44SJohn Forte * iscsi_rx_process_rejected_tsk_mgt - 1136fcf3ce44SJohn Forte */ 1137fcf3ce44SJohn Forte static iscsi_status_t 1138fcf3ce44SJohn Forte iscsi_rx_process_rejected_tsk_mgt(iscsi_conn_t *icp, 1139fcf3ce44SJohn Forte iscsi_hdr_t *old_ihp) 1140fcf3ce44SJohn Forte { 1141fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1142fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1143fcf3ce44SJohn Forte 1144fcf3ce44SJohn Forte ASSERT(icp != NULL); 1145fcf3ce44SJohn Forte isp = icp->conn_sess; 1146fcf3ce44SJohn Forte ASSERT(old_ihp != NULL); 1147fcf3ce44SJohn Forte ASSERT(icp->conn_sess != NULL); 1148fcf3ce44SJohn Forte 1149fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1150fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1151fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 1152fcf3ce44SJohn Forte isp, old_ihp, &icmdp))) { 1153fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1154fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1155fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1156fcf3ce44SJohn Forte } 1157fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1158fcf3ce44SJohn Forte 1159fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1160fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1161fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1162fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E4, 1163fcf3ce44SJohn Forte icp->conn_sess); 1164fcf3ce44SJohn Forte break; 1165fcf3ce44SJohn Forte /* We don't send any other task mgr types */ 1166fcf3ce44SJohn Forte default: 1167fcf3ce44SJohn Forte ASSERT(B_FALSE); 1168fcf3ce44SJohn Forte break; 1169fcf3ce44SJohn Forte } 1170fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1171fcf3ce44SJohn Forte 1172fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1173fcf3ce44SJohn Forte } 1174fcf3ce44SJohn Forte 1175fcf3ce44SJohn Forte 1176fcf3ce44SJohn Forte /* 1177fcf3ce44SJohn Forte * iscsi_rx_process_task_mgt_rsp - 1178fcf3ce44SJohn Forte */ 1179fcf3ce44SJohn Forte /* ARGSUSED */ 1180fcf3ce44SJohn Forte static iscsi_status_t 1181fcf3ce44SJohn Forte iscsi_rx_process_task_mgt_rsp(iscsi_conn_t *icp, 1182fcf3ce44SJohn Forte iscsi_hdr_t *ihp, void *data) 1183fcf3ce44SJohn Forte { 1184fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1185fcf3ce44SJohn Forte iscsi_scsi_task_mgt_rsp_hdr_t *istmrhp = NULL; 1186fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1187fcf3ce44SJohn Forte 1188fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1189fcf3ce44SJohn Forte ASSERT(icp != NULL); 1190fcf3ce44SJohn Forte isp = icp->conn_sess; 1191fcf3ce44SJohn Forte ASSERT(isp != NULL); 1192fcf3ce44SJohn Forte istmrhp = (iscsi_scsi_task_mgt_rsp_hdr_t *)ihp; 1193fcf3ce44SJohn Forte 1194fcf3ce44SJohn Forte if (icp->conn_expstatsn == ntohl(istmrhp->statsn)) { 1195fcf3ce44SJohn Forte icp->conn_expstatsn++; 1196fcf3ce44SJohn Forte } else { 1197fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1198fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 1199fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, istmrhp->itt, 1200fcf3ce44SJohn Forte ntohl(istmrhp->statsn), icp->conn_expstatsn); 1201fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1202fcf3ce44SJohn Forte } 1203fcf3ce44SJohn Forte 1204fcf3ce44SJohn Forte /* make sure we only Ack Status numbers that we've actually received. */ 1205fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1206fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1207fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) { 1208fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1209fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1210fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1211fcf3ce44SJohn Forte } 1212fcf3ce44SJohn Forte 1213fcf3ce44SJohn Forte /* update expcmdsn and maxcmdn */ 1214fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(istmrhp->maxcmdsn), 1215fcf3ce44SJohn Forte ntohl(istmrhp->expcmdsn)); 1216fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1217fcf3ce44SJohn Forte 1218fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1219fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1220fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1221fcf3ce44SJohn Forte switch (istmrhp->response) { 1222fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_COMPLETE: 1223fcf3ce44SJohn Forte /* success */ 1224fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, 1225fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E3, isp); 1226fcf3ce44SJohn Forte break; 1227fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_TASK: 1228fcf3ce44SJohn Forte /* 1229fcf3ce44SJohn Forte * If the array no longer knows about 1230fcf3ce44SJohn Forte * an ABORT RTT and we no longer have 1231fcf3ce44SJohn Forte * a parent SCSI command it was just 1232fcf3ce44SJohn Forte * completed, free this ABORT resource. 1233fcf3ce44SJohn Forte * Otherwise FALLTHRU this will flag a 1234fcf3ce44SJohn Forte * protocol problem. 1235fcf3ce44SJohn Forte */ 1236fcf3ce44SJohn Forte if ((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) && 1237fcf3ce44SJohn Forte (icmdp->cmd_un.abort.icmdp == NULL)) { 1238fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, 1239fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E4, isp); 1240fcf3ce44SJohn Forte break; 1241fcf3ce44SJohn Forte } 1242fcf3ce44SJohn Forte /* FALLTHRU */ 1243fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_LUN: 1244fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_TASK_ALLEGIANT: 1245fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_NO_FAILOVER: 1246fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_IN_PRGRESS: 1247fcf3ce44SJohn Forte case SCSI_TCP_TM_RESP_REJECTED: 1248fcf3ce44SJohn Forte default: 1249fcf3ce44SJohn Forte /* 1250fcf3ce44SJohn Forte * Something is out of sync. Flush 1251fcf3ce44SJohn Forte * active queues and resync the 1252fcf3ce44SJohn Forte * the connection to try and recover 1253fcf3ce44SJohn Forte * to a known state. 1254fcf3ce44SJohn Forte */ 1255fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1256fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1257fcf3ce44SJohn Forte } 1258fcf3ce44SJohn Forte break; 1259fcf3ce44SJohn Forte 1260fcf3ce44SJohn Forte default: 1261fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1262fcf3ce44SJohn Forte "received a task mgt response for a non-task mgt " 1263fcf3ce44SJohn Forte "cmd itt:0x%x type:%d", icp->conn_oid, istmrhp->itt, 1264fcf3ce44SJohn Forte icmdp->cmd_type); 1265fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1266fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1267fcf3ce44SJohn Forte } 1268fcf3ce44SJohn Forte 1269fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1270fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1271fcf3ce44SJohn Forte } 1272fcf3ce44SJohn Forte 1273fcf3ce44SJohn Forte 1274fcf3ce44SJohn Forte /* 1275fcf3ce44SJohn Forte * iscsi_rx_process_logout - 1276fcf3ce44SJohn Forte * 1277fcf3ce44SJohn Forte */ 1278fcf3ce44SJohn Forte /* ARGSUSED */ 1279fcf3ce44SJohn Forte static iscsi_status_t 1280fcf3ce44SJohn Forte iscsi_rx_process_logout_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 1281fcf3ce44SJohn Forte { 1282fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1283fcf3ce44SJohn Forte iscsi_sess_t *isp = icp->conn_sess; 1284fcf3ce44SJohn Forte iscsi_logout_rsp_hdr_t *ilrhp = (iscsi_logout_rsp_hdr_t *)ihp; 1285fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1286fcf3ce44SJohn Forte 1287fcf3ce44SJohn Forte ASSERT(icp != NULL); 1288fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1289fcf3ce44SJohn Forte isp = icp->conn_sess; 1290fcf3ce44SJohn Forte ASSERT(isp != NULL); 1291fcf3ce44SJohn Forte 1292fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(ilrhp->statsn)) { 1293fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1294fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 1295fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, ilrhp->itt, 1296fcf3ce44SJohn Forte ntohl(ilrhp->statsn), icp->conn_expstatsn); 1297fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1298fcf3ce44SJohn Forte } 1299fcf3ce44SJohn Forte 1300fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1301fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1302fcf3ce44SJohn Forte if (ilrhp->itt != ISCSI_RSVD_TASK_TAG) { 1303fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp( 1304fcf3ce44SJohn Forte isp, ihp, &icmdp))) { 1305fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1306fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1307fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1308fcf3ce44SJohn Forte } 1309fcf3ce44SJohn Forte } 1310fcf3ce44SJohn Forte 1311fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 1312fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(ilrhp->maxcmdsn), 1313fcf3ce44SJohn Forte ntohl(ilrhp->expcmdsn)); 1314fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1315fcf3ce44SJohn Forte 1316fcf3ce44SJohn Forte switch (ilrhp->response) { 1317fcf3ce44SJohn Forte case ISCSI_LOGOUT_CID_NOT_FOUND: 1318fcf3ce44SJohn Forte /* 1319fcf3ce44SJohn Forte * If the target doesn't know about our connection 1320fcf3ce44SJohn Forte * then we can consider our self disconnected. 1321fcf3ce44SJohn Forte */ 1322fcf3ce44SJohn Forte /* FALLTHRU */ 1323fcf3ce44SJohn Forte case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED: 1324fcf3ce44SJohn Forte /* 1325fcf3ce44SJohn Forte * We don't support ErrorRecovery levels above 0 1326fcf3ce44SJohn Forte * currently so consider this success. 1327fcf3ce44SJohn Forte */ 1328fcf3ce44SJohn Forte /* FALLTHRU */ 1329fcf3ce44SJohn Forte case ISCSI_LOGOUT_CLEANUP_FAILED: 1330fcf3ce44SJohn Forte /* 1331fcf3ce44SJohn Forte * per spec. "cleanup failed for various reasons." 1332fcf3ce44SJohn Forte * Although those various reasons are undefined. 1333fcf3ce44SJohn Forte * Not sure what to do here. So fake success, 1334fcf3ce44SJohn Forte * which will disconnect the connection. 1335fcf3ce44SJohn Forte */ 1336fcf3ce44SJohn Forte /* FALLTHRU */ 1337fcf3ce44SJohn Forte case ISCSI_LOGOUT_SUCCESS: 1338fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1339fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1340fcf3ce44SJohn Forte /* logout completed successfully notify the conn */ 1341fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1342fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T17); 1343fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1344fcf3ce44SJohn Forte break; 1345fcf3ce44SJohn Forte default: 1346fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1347fcf3ce44SJohn Forte rval = ISCSI_STATUS_PROTOCOL_ERROR; 1348fcf3ce44SJohn Forte } 1349fcf3ce44SJohn Forte 1350fcf3ce44SJohn Forte return (rval); 1351fcf3ce44SJohn Forte } 1352fcf3ce44SJohn Forte 1353fcf3ce44SJohn Forte 1354fcf3ce44SJohn Forte /* 1355fcf3ce44SJohn Forte * iscsi_rx_process_logout - 1356fcf3ce44SJohn Forte * 1357fcf3ce44SJohn Forte */ 1358fcf3ce44SJohn Forte /* ARGSUSED */ 1359fcf3ce44SJohn Forte static iscsi_status_t 1360fcf3ce44SJohn Forte iscsi_rx_process_async_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 1361fcf3ce44SJohn Forte { 1362fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1363fcf3ce44SJohn Forte iscsi_async_evt_hdr_t *iaehp = (iscsi_async_evt_hdr_t *)ihp; 1364fcf3ce44SJohn Forte 1365fcf3ce44SJohn Forte ASSERT(icp != NULL); 1366fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1367fcf3ce44SJohn Forte ASSERT(icp->conn_sess != NULL); 1368fcf3ce44SJohn Forte 1369fcf3ce44SJohn Forte if (icp->conn_expstatsn != ntohl(iaehp->statsn)) { 1370fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1371fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 1372fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, ihp->itt, 1373fcf3ce44SJohn Forte ntohl(iaehp->statsn), icp->conn_expstatsn); 1374fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1375fcf3ce44SJohn Forte } 1376fcf3ce44SJohn Forte 1377fcf3ce44SJohn Forte switch (iaehp->async_event) { 1378fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_SCSI_EVENT: 1379fcf3ce44SJohn Forte /* 1380fcf3ce44SJohn Forte * SCSI asynchronous event is reported in 1381fcf3ce44SJohn Forte * the sense data. Sense data that accompanies 1382fcf3ce44SJohn Forte * the report in the data segment identifies the 1383fcf3ce44SJohn Forte * condition. If the target supports SCSI 1384fcf3ce44SJohn Forte * asynchronous events reporting (see [SAM2]) 1385fcf3ce44SJohn Forte * as indicated in the stardard INQUIRY data 1386fcf3ce44SJohn Forte * (see [SPC3]), its use may be enabled by 1387fcf3ce44SJohn Forte * parameters in the SCSI control mode page 1388fcf3ce44SJohn Forte * (see [SPC3]). 1389fcf3ce44SJohn Forte * 1390fcf3ce44SJohn Forte * T-10 has removed SCSI asunchronous events 1391fcf3ce44SJohn Forte * from the standard. Although we have seen 1392fcf3ce44SJohn Forte * a couple targets still spending these requests. 1393fcf3ce44SJohn Forte * Those targets were specifically sending them 1394fcf3ce44SJohn Forte * for notification of a LUN/Volume change 1395fcf3ce44SJohn Forte * (ex. LUN addition/removal). Take a general 1396fcf3ce44SJohn Forte * action to these events of dis/reconnecting. 1397fcf3ce44SJohn Forte * Once reconnected we perform a reenumeration. 1398fcf3ce44SJohn Forte */ 1399fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1400fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1401fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1402fcf3ce44SJohn Forte break; 1403fcf3ce44SJohn Forte 1404fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT: 1405fcf3ce44SJohn Forte /* Target has requested this connection to logout. */ 1406fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1407fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1408fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1409fcf3ce44SJohn Forte break; 1410fcf3ce44SJohn Forte 1411fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION: 1412fcf3ce44SJohn Forte /* 1413fcf3ce44SJohn Forte * Target is going to drop our connection. 1414fcf3ce44SJohn Forte * param1 - CID which will be dropped. 1415fcf3ce44SJohn Forte * param2 - Min time to reconnect. 1416fcf3ce44SJohn Forte * param3 - Max time to reconnect. 1417fcf3ce44SJohn Forte * 1418fcf3ce44SJohn Forte * For now just let fail as another disconnect. 1419fcf3ce44SJohn Forte * 1420fcf3ce44SJohn Forte * MC/S Once we support > 1 connections then 1421fcf3ce44SJohn Forte * we need to check the CID and drop that 1422fcf3ce44SJohn Forte * specific connection. 1423fcf3ce44SJohn Forte */ 1424fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(icp, iaehp->param2, iaehp->param3); 1425fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1426fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1427fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1428fcf3ce44SJohn Forte break; 1429fcf3ce44SJohn Forte 1430fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS: 1431fcf3ce44SJohn Forte /* 1432fcf3ce44SJohn Forte * Target is going to drop ALL connections. 1433fcf3ce44SJohn Forte * param2 - Min time to reconnect. 1434fcf3ce44SJohn Forte * param3 - Max time to reconnect. 1435fcf3ce44SJohn Forte * 1436fcf3ce44SJohn Forte * For now just let fail as anyother disconnect. 1437fcf3ce44SJohn Forte * 1438fcf3ce44SJohn Forte * MC/S Once we support more than > 1 connections 1439fcf3ce44SJohn Forte * then we need to drop all connections on the 1440fcf3ce44SJohn Forte * session. 1441fcf3ce44SJohn Forte */ 1442fcf3ce44SJohn Forte iscsi_conn_set_login_min_max(icp, iaehp->param2, iaehp->param3); 1443fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1444fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1445fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1446fcf3ce44SJohn Forte break; 1447fcf3ce44SJohn Forte 1448fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION: 1449fcf3ce44SJohn Forte /* 1450fcf3ce44SJohn Forte * Target requests parameter negotiation 1451fcf3ce44SJohn Forte * on this connection. 1452fcf3ce44SJohn Forte * 1453fcf3ce44SJohn Forte * The initiator must honor this request. For 1454fcf3ce44SJohn Forte * now we will request a logout. We can't 1455fcf3ce44SJohn Forte * just ignore this or it might force corruption? 1456fcf3ce44SJohn Forte */ 1457fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1458fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1459fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1460fcf3ce44SJohn Forte break; 1461fcf3ce44SJohn Forte 1462fcf3ce44SJohn Forte case ISCSI_ASYNC_EVENT_VENDOR_SPECIFIC: 1463fcf3ce44SJohn Forte /* 1464fcf3ce44SJohn Forte * We currently don't handle any vendor 1465fcf3ce44SJohn Forte * specific async events. So just ignore 1466fcf3ce44SJohn Forte * the request. 1467fcf3ce44SJohn Forte */ 1468fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 1469fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T14); 1470fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 1471fcf3ce44SJohn Forte break; 1472fcf3ce44SJohn Forte default: 1473fcf3ce44SJohn Forte rval = ISCSI_STATUS_PROTOCOL_ERROR; 1474fcf3ce44SJohn Forte } 1475fcf3ce44SJohn Forte 1476fcf3ce44SJohn Forte return (rval); 1477fcf3ce44SJohn Forte } 1478fcf3ce44SJohn Forte 1479fcf3ce44SJohn Forte /* 1480fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp - processes iSCSI text response. It sets 1481fcf3ce44SJohn Forte * the cmd_result field of the command data structure with the actual 1482fcf3ce44SJohn Forte * status value instead of returning the status value. The return value 1483fcf3ce44SJohn Forte * is SUCCESS in order to let iscsi_handle_text control the operation of 1484fcf3ce44SJohn Forte * a text request. 1485fcf3ce44SJohn Forte * Test requests are a handled a little different than other types of 1486fcf3ce44SJohn Forte * iSCSI commands because the initiator sends additional empty text requests 1487fcf3ce44SJohn Forte * in order to obtain the remaining responses required to complete the 1488fcf3ce44SJohn Forte * request. iscsi_handle_text controls the operation of text request, while 1489fcf3ce44SJohn Forte * iscsi_rx_process_text_rsp just process the current response. 1490fcf3ce44SJohn Forte */ 1491fcf3ce44SJohn Forte static iscsi_status_t 1492fcf3ce44SJohn Forte iscsi_rx_process_text_rsp(iscsi_conn_t *icp, iscsi_hdr_t *ihp, char *data) 1493fcf3ce44SJohn Forte { 1494fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1495fcf3ce44SJohn Forte iscsi_text_rsp_hdr_t *ithp = (iscsi_text_rsp_hdr_t *)ihp; 1496fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1497fcf3ce44SJohn Forte boolean_t final = B_FALSE; 1498fcf3ce44SJohn Forte uint32_t data_len; 1499fcf3ce44SJohn Forte 1500fcf3ce44SJohn Forte ASSERT(icp != NULL); 1501fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1502fcf3ce44SJohn Forte ASSERT(data != NULL); 1503fcf3ce44SJohn Forte 1504fcf3ce44SJohn Forte isp = icp->conn_sess; 1505fcf3ce44SJohn Forte ASSERT(isp != NULL); 1506fcf3ce44SJohn Forte 1507fcf3ce44SJohn Forte if (icp->conn_expstatsn == ntohl(ithp->statsn)) { 1508fcf3ce44SJohn Forte icp->conn_expstatsn++; 1509fcf3ce44SJohn Forte } else { 1510fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1511fcf3ce44SJohn Forte "received status out of order itt:0x%x statsn:0x%x " 1512fcf3ce44SJohn Forte "expstatsn:0x%x", icp->conn_oid, ithp->itt, 1513fcf3ce44SJohn Forte ntohl(ithp->statsn), icp->conn_expstatsn); 1514fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1515fcf3ce44SJohn Forte } 1516fcf3ce44SJohn Forte 1517fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 1518fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1519fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_rx_process_itt_to_icmdp(isp, ihp, &icmdp))) { 1520fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1521fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1522fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1523fcf3ce44SJohn Forte } 1524fcf3ce44SJohn Forte 1525fcf3ce44SJohn Forte /* update expcmdsn and maxcmdsn */ 1526fcf3ce44SJohn Forte iscsi_update_flow_control(isp, ntohl(ithp->maxcmdsn), 1527fcf3ce44SJohn Forte ntohl(ithp->expcmdsn)); 1528fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1529fcf3ce44SJohn Forte 1530fcf3ce44SJohn Forte /* update local final response flag */ 1531fcf3ce44SJohn Forte if (ithp->flags & ISCSI_FLAG_FINAL) { 1532fcf3ce44SJohn Forte final = B_TRUE; 1533fcf3ce44SJohn Forte } 1534fcf3ce44SJohn Forte 1535fcf3ce44SJohn Forte /* 1536fcf3ce44SJohn Forte * validate received TTT value. RFC3720 specifies the following: 1537fcf3ce44SJohn Forte * - F bit set to 1 MUST have a reserved TTT value 0xffffffff 1538fcf3ce44SJohn Forte * - F bit set to 0 MUST have a non-reserved TTT value !0xffffffff 1539fcf3ce44SJohn Forte * In addition, the received TTT value must not change between 1540fcf3ce44SJohn Forte * responses of a long text response 1541fcf3ce44SJohn Forte */ 1542fcf3ce44SJohn Forte if (((final == B_TRUE) && (ithp->ttt != ISCSI_RSVD_TASK_TAG)) || 1543fcf3ce44SJohn Forte ((final == B_FALSE) && (ithp->ttt == ISCSI_RSVD_TASK_TAG))) { 1544fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR; 1545fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1546fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1547fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol error - " 1548fcf3ce44SJohn Forte "received text response with invalid flags:0x%x or " 1549fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->flags, ithp->itt); 1550fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1551fcf3ce44SJohn Forte } 1552fcf3ce44SJohn Forte 1553fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) && 1554fcf3ce44SJohn Forte (ithp->ttt == ISCSI_RSVD_TASK_TAG) && 1555fcf3ce44SJohn Forte (final == B_FALSE)) { 1556fcf3ce44SJohn Forte /* TTT should have matched reserved value */ 1557fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_PROTOCOL_ERROR; 1558fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1559fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1560fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) protocol " 1561fcf3ce44SJohn Forte "error - received text response with invalid " 1562fcf3ce44SJohn Forte "ttt:0x%x", icp->conn_oid, ithp->ttt); 1563fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 1564fcf3ce44SJohn Forte } 1565fcf3ce44SJohn Forte 1566fcf3ce44SJohn Forte /* 1567fcf3ce44SJohn Forte * If this is first response, save away TTT value for later use 1568fcf3ce44SJohn Forte * in a long text request/response sequence 1569fcf3ce44SJohn Forte */ 1570fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage == ISCSI_CMD_TEXT_INITIAL_REQ) { 1571fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ithp->ttt; 1572fcf3ce44SJohn Forte } 1573fcf3ce44SJohn Forte 1574fcf3ce44SJohn Forte data_len = ntoh24(ithp->dlength); 1575fcf3ce44SJohn Forte 1576fcf3ce44SJohn Forte /* check whether enough buffer available to copy data */ 1577fcf3ce44SJohn Forte if ((icmdp->cmd_un.text.total_rx_len + data_len) > 1578fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len) { 1579fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len; 1580fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_DATA_OVERFLOW; 1581fcf3ce44SJohn Forte /* 1582fcf3ce44SJohn Forte * DATA_OVERFLOW will result in a SUCCESS return so that 1583fcf3ce44SJohn Forte * iscsi_handle_text can continue to obtain the remaining 1584fcf3ce44SJohn Forte * text response if needed. 1585fcf3ce44SJohn Forte */ 1586fcf3ce44SJohn Forte } else { 1587fcf3ce44SJohn Forte char *buf_data = (icmdp->cmd_un.text.buf + 1588fcf3ce44SJohn Forte icmdp->cmd_un.text.offset); 1589fcf3ce44SJohn Forte 1590fcf3ce44SJohn Forte bcopy(data, buf_data, data_len); 1591fcf3ce44SJohn Forte icmdp->cmd_un.text.offset += data_len; 1592fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len += data_len; 1593fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 1594fcf3ce44SJohn Forte bcopy(ithp->rsvd4, icmdp->cmd_un.text.lun, 1595fcf3ce44SJohn Forte sizeof (icmdp->cmd_un.text.lun)); 1596fcf3ce44SJohn Forte } 1597fcf3ce44SJohn Forte 1598fcf3ce44SJohn Forte /* update stage */ 1599fcf3ce44SJohn Forte if (final == B_TRUE) { 1600fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP; 1601fcf3ce44SJohn Forte } else { 1602fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION; 1603fcf3ce44SJohn Forte } 1604fcf3ce44SJohn Forte 1605fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E3, isp); 1606fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 1607fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1608fcf3ce44SJohn Forte } 1609fcf3ce44SJohn Forte 1610fcf3ce44SJohn Forte /* 1611fcf3ce44SJohn Forte * iscsi_rx_process_itt_to_icmdp - Lookup itt in the session's 1612fcf3ce44SJohn Forte * cmd table to find matching icmdp. Verify itt in hdr and 1613fcf3ce44SJohn Forte * icmdp are the same. 1614fcf3ce44SJohn Forte */ 1615fcf3ce44SJohn Forte static iscsi_status_t 1616fcf3ce44SJohn Forte iscsi_rx_process_itt_to_icmdp(iscsi_sess_t *isp, iscsi_hdr_t *ihp, 1617fcf3ce44SJohn Forte iscsi_cmd_t **icmdp) 1618fcf3ce44SJohn Forte { 1619fcf3ce44SJohn Forte int cmd_table_idx = 0; 1620fcf3ce44SJohn Forte 1621fcf3ce44SJohn Forte ASSERT(isp != NULL); 1622fcf3ce44SJohn Forte ASSERT(ihp != NULL); 1623fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 1624fcf3ce44SJohn Forte ASSERT(mutex_owned(&isp->sess_cmdsn_mutex)); 1625fcf3ce44SJohn Forte 1626fcf3ce44SJohn Forte /* try to find an associated iscsi_pkt */ 1627fcf3ce44SJohn Forte cmd_table_idx = ihp->itt % ISCSI_CMD_TABLE_SIZE; 1628fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx] == NULL) { 1629fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) protocol error - " 1630fcf3ce44SJohn Forte "received unknown itt:0x%x - protocol error", 1631fcf3ce44SJohn Forte isp->sess_oid, ihp->itt); 1632fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 1633fcf3ce44SJohn Forte } 1634fcf3ce44SJohn Forte 1635fcf3ce44SJohn Forte /* verify itt */ 1636fcf3ce44SJohn Forte if (isp->sess_cmd_table[cmd_table_idx]->cmd_itt != ihp->itt) { 1637fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x " 1638fcf3ce44SJohn Forte " which is out of sync with itt:0x%x", isp->sess_oid, 1639fcf3ce44SJohn Forte ihp->itt, isp->sess_cmd_table[cmd_table_idx]->cmd_itt); 1640fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 1641fcf3ce44SJohn Forte } 1642fcf3ce44SJohn Forte 164329e23f3fSandrew.rutz@sun.com /* ensure that icmdp is still in Active state */ 164429e23f3fSandrew.rutz@sun.com if (isp->sess_cmd_table[cmd_table_idx]->cmd_state != 164529e23f3fSandrew.rutz@sun.com ISCSI_CMD_STATE_ACTIVE) { 164629e23f3fSandrew.rutz@sun.com cmn_err(CE_WARN, "iscsi session(%u) received itt:0x%x " 164729e23f3fSandrew.rutz@sun.com "but icmdp (%p) is not in active state", 164829e23f3fSandrew.rutz@sun.com isp->sess_oid, ihp->itt, 164929e23f3fSandrew.rutz@sun.com (void *)isp->sess_cmd_table[cmd_table_idx]); 165029e23f3fSandrew.rutz@sun.com return (ISCSI_STATUS_INTERNAL_ERROR); 165129e23f3fSandrew.rutz@sun.com } 165229e23f3fSandrew.rutz@sun.com 1653fcf3ce44SJohn Forte /* make sure this is a SCSI cmd */ 1654fcf3ce44SJohn Forte *icmdp = isp->sess_cmd_table[cmd_table_idx]; 1655fcf3ce44SJohn Forte 1656fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 1657fcf3ce44SJohn Forte } 1658fcf3ce44SJohn Forte 1659fcf3ce44SJohn Forte 1660fcf3ce44SJohn Forte /* 1661fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1662fcf3ce44SJohn Forte * | End of protocol receive routines | 1663fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1664fcf3ce44SJohn Forte */ 1665fcf3ce44SJohn Forte 1666fcf3ce44SJohn Forte /* 1667fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1668fcf3ce44SJohn Forte * | Beginning of protocol send routines | 1669fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 1670fcf3ce44SJohn Forte */ 1671fcf3ce44SJohn Forte 1672fcf3ce44SJohn Forte 1673fcf3ce44SJohn Forte /* 1674fcf3ce44SJohn Forte * iscsi_tx_thread - This thread is the driving point for all 1675fcf3ce44SJohn Forte * iSCSI PDUs after login. No PDUs should call sendpdu() 1676fcf3ce44SJohn Forte * directly they should be funneled through iscsi_tx_thread. 1677fcf3ce44SJohn Forte */ 1678fcf3ce44SJohn Forte void 1679fcf3ce44SJohn Forte iscsi_tx_thread(iscsi_thread_t *thread, void *arg) 1680fcf3ce44SJohn Forte { 1681fcf3ce44SJohn Forte iscsi_conn_t *icp = (iscsi_conn_t *)arg; 1682fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 1683fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 1684fcf3ce44SJohn Forte clock_t tout; 1685fcf3ce44SJohn Forte int ret = 1; 1686fcf3ce44SJohn Forte 1687fcf3ce44SJohn Forte ASSERT(icp != NULL); 1688fcf3ce44SJohn Forte isp = icp->conn_sess; 1689fcf3ce44SJohn Forte ASSERT(isp != NULL); 1690fcf3ce44SJohn Forte ASSERT(thread != NULL); 1691fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD); 1692fcf3ce44SJohn Forte 1693fcf3ce44SJohn Forte tout = SEC_TO_TICK(1); 1694fcf3ce44SJohn Forte /* 1695fcf3ce44SJohn Forte * Transfer icmdps until shutdown by owning session. 1696fcf3ce44SJohn Forte */ 1697fcf3ce44SJohn Forte while (ret != 0) { 1698fcf3ce44SJohn Forte 1699fcf3ce44SJohn Forte isp->sess_window_open = B_TRUE; 1700fcf3ce44SJohn Forte 1701fcf3ce44SJohn Forte /* 1702fcf3ce44SJohn Forte * While the window is open, there are commands available 1703fcf3ce44SJohn Forte * to send and the session state allows those commands to 1704fcf3ce44SJohn Forte * be sent try to transfer them. 1705fcf3ce44SJohn Forte */ 1706fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 1707fcf3ce44SJohn Forte while ((isp->sess_window_open == B_TRUE) && 1708fcf3ce44SJohn Forte ((icmdp = isp->sess_queue_pending.head) != NULL) && 1709fcf3ce44SJohn Forte (((icmdp->cmd_type != ISCSI_CMD_TYPE_SCSI) && 1710fcf3ce44SJohn Forte (ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state))) || 1711fcf3ce44SJohn Forte (icp->conn_state == ISCSI_CONN_STATE_LOGGED_IN))) { 1712fcf3ce44SJohn Forte 1713fcf3ce44SJohn Forte /* update command with this connection info */ 1714fcf3ce44SJohn Forte icmdp->cmd_conn = icp; 1715fcf3ce44SJohn Forte /* attempt to send this command */ 1716fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E2, isp); 1717fcf3ce44SJohn Forte 1718fcf3ce44SJohn Forte ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex)); 1719fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 1720fcf3ce44SJohn Forte } 1721fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 1722fcf3ce44SJohn Forte 1723fcf3ce44SJohn Forte /* 1724fcf3ce44SJohn Forte * Go to sleep until there is something new 1725fcf3ce44SJohn Forte * to process (awoken via cv_boardcast). 1726fcf3ce44SJohn Forte * Or the timer goes off. 1727fcf3ce44SJohn Forte */ 1728fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, tout); 1729fcf3ce44SJohn Forte } 1730fcf3ce44SJohn Forte 1731fcf3ce44SJohn Forte } 1732fcf3ce44SJohn Forte 1733fcf3ce44SJohn Forte 1734fcf3ce44SJohn Forte /* 1735fcf3ce44SJohn Forte * iscsi_tx_cmd - transfers icmdp across wire as iscsi pdu 1736fcf3ce44SJohn Forte * 1737fcf3ce44SJohn Forte * Just prior to sending the command to the networking layer the 1738fcf3ce44SJohn Forte * pending queue lock will be dropped. At this point only local 1739fcf3ce44SJohn Forte * resources will be used, not the icmdp. Holding the queue lock 1740fcf3ce44SJohn Forte * across the networking call can lead to a hang. (This is due 1741fcf3ce44SJohn Forte * to the the target driver and networking layers competing use 1742fcf3ce44SJohn Forte * of the timeout() resources and the queue lock being held for 1743fcf3ce44SJohn Forte * both sides.) Upon the completion of this command the lock 1744fcf3ce44SJohn Forte * will have been re-acquired. 1745fcf3ce44SJohn Forte */ 1746fcf3ce44SJohn Forte iscsi_status_t 1747fcf3ce44SJohn Forte iscsi_tx_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 1748fcf3ce44SJohn Forte { 1749fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR; 1750fcf3ce44SJohn Forte 1751fcf3ce44SJohn Forte ASSERT(isp != NULL); 1752fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 1753fcf3ce44SJohn Forte 1754fcf3ce44SJohn Forte /* transfer specific command type */ 1755fcf3ce44SJohn Forte switch (icmdp->cmd_type) { 1756fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_SCSI: 1757fcf3ce44SJohn Forte rval = iscsi_tx_scsi(isp, icmdp); 1758fcf3ce44SJohn Forte break; 1759fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_R2T: 1760fcf3ce44SJohn Forte rval = iscsi_tx_r2t(isp, icmdp); 1761fcf3ce44SJohn Forte break; 1762fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_NOP: 1763fcf3ce44SJohn Forte rval = iscsi_tx_nop(isp, icmdp); 1764fcf3ce44SJohn Forte break; 1765fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_ABORT: 1766fcf3ce44SJohn Forte rval = iscsi_tx_abort(isp, icmdp); 1767fcf3ce44SJohn Forte break; 1768fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_RESET: 1769fcf3ce44SJohn Forte rval = iscsi_tx_reset(isp, icmdp); 1770fcf3ce44SJohn Forte break; 1771fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_LOGOUT: 1772fcf3ce44SJohn Forte rval = iscsi_tx_logout(isp, icmdp); 1773fcf3ce44SJohn Forte break; 1774fcf3ce44SJohn Forte case ISCSI_CMD_TYPE_TEXT: 1775fcf3ce44SJohn Forte rval = iscsi_tx_text(isp, icmdp); 1776fcf3ce44SJohn Forte break; 1777fcf3ce44SJohn Forte default: 1778fcf3ce44SJohn Forte ASSERT(FALSE); 1779fcf3ce44SJohn Forte } 1780fcf3ce44SJohn Forte 1781fcf3ce44SJohn Forte ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex)); 1782fcf3ce44SJohn Forte return (rval); 1783fcf3ce44SJohn Forte } 1784fcf3ce44SJohn Forte 1785fcf3ce44SJohn Forte /* 1786fcf3ce44SJohn Forte * a variable length cdb can be up to 16K, but we obviously don't want 1787fcf3ce44SJohn Forte * to put that on the stack; go with 200 bytes; if we get something 1788fcf3ce44SJohn Forte * bigger than that we will kmem_alloc a buffer 1789fcf3ce44SJohn Forte */ 1790fcf3ce44SJohn Forte #define DEF_CDB_LEN 200 1791fcf3ce44SJohn Forte 1792fcf3ce44SJohn Forte /* 1793fcf3ce44SJohn Forte * given the size of the cdb, return how many bytes the header takes, 1794fcf3ce44SJohn Forte * which is the sizeof addl_hdr_t + the CDB size, minus the 16 bytes 1795fcf3ce44SJohn Forte * stored in the basic header, minus sizeof (ahs_extscb) 1796fcf3ce44SJohn Forte */ 1797fcf3ce44SJohn Forte #define ADDLHDRSZ(x) (sizeof (iscsi_addl_hdr_t) + (x) - \ 1798fcf3ce44SJohn Forte 16 - 4) 1799fcf3ce44SJohn Forte 1800fcf3ce44SJohn Forte /* 1801fcf3ce44SJohn Forte * iscsi_tx_scsi - 1802fcf3ce44SJohn Forte * 1803fcf3ce44SJohn Forte */ 1804fcf3ce44SJohn Forte static iscsi_status_t 1805fcf3ce44SJohn Forte iscsi_tx_scsi(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 1806fcf3ce44SJohn Forte { 1807fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 1808fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 1809fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 1810fcf3ce44SJohn Forte struct buf *bp = NULL; 1811fcf3ce44SJohn Forte union { 1812fcf3ce44SJohn Forte iscsi_scsi_cmd_hdr_t isch; 1813fcf3ce44SJohn Forte iscsi_addl_hdr_t iah; 1814fcf3ce44SJohn Forte uchar_t arr[ADDLHDRSZ(DEF_CDB_LEN)]; 1815fcf3ce44SJohn Forte } hdr_un; 1816fcf3ce44SJohn Forte iscsi_scsi_cmd_hdr_t *ihp = 1817fcf3ce44SJohn Forte (iscsi_scsi_cmd_hdr_t *)&hdr_un.isch; 1818fcf3ce44SJohn Forte int cdblen = 0; 1819fcf3ce44SJohn Forte size_t buflen = 0; 1820fcf3ce44SJohn Forte uint32_t imdata = 0; 1821fcf3ce44SJohn Forte uint32_t first_burst_length = 0; 1822fcf3ce44SJohn Forte 1823fcf3ce44SJohn Forte ASSERT(isp != NULL); 1824fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 1825fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt; 1826fcf3ce44SJohn Forte ASSERT(pkt != NULL); 1827fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 1828fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 1829fcf3ce44SJohn Forte ASSERT(icp != NULL); 1830fcf3ce44SJohn Forte 1831fcf3ce44SJohn Forte /* Reset counts in case we are on a retry */ 1832fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred = 0; 1833fcf3ce44SJohn Forte 1834fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.cmdlen > DEF_CDB_LEN) { 1835fcf3ce44SJohn Forte cdblen = icmdp->cmd_un.scsi.cmdlen; 1836fcf3ce44SJohn Forte ihp = kmem_zalloc(ADDLHDRSZ(cdblen), KM_SLEEP); 1837fcf3ce44SJohn Forte } else { 1838fcf3ce44SJohn Forte /* 1839fcf3ce44SJohn Forte * only bzero the basic header; the additional header 1840fcf3ce44SJohn Forte * will be set up correctly later, if needed 1841fcf3ce44SJohn Forte */ 1842fcf3ce44SJohn Forte bzero(ihp, sizeof (iscsi_scsi_cmd_hdr_t)); 1843fcf3ce44SJohn Forte } 1844fcf3ce44SJohn Forte ihp->opcode = ISCSI_OP_SCSI_CMD; 1845fcf3ce44SJohn Forte ihp->itt = icmdp->cmd_itt; 1846fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 1847fcf3ce44SJohn Forte ihp->cmdsn = htonl(isp->sess_cmdsn); 1848fcf3ce44SJohn Forte isp->sess_cmdsn++; 1849fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 1850fcf3ce44SJohn Forte ihp->expstatsn = htonl(icp->conn_expstatsn); 1851fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 1852fcf3ce44SJohn Forte 1853fcf3ce44SJohn Forte pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET); 1854fcf3ce44SJohn Forte pkt->pkt_reason = CMD_INCOMPLETE; 1855fcf3ce44SJohn Forte 1856fcf3ce44SJohn Forte /* 1857fcf3ce44SJohn Forte * Sestion 12.11 of the iSCSI specification has a good table 1858fcf3ce44SJohn Forte * describing when uncolicited data and/or immediate data 1859fcf3ce44SJohn Forte * should be sent. 1860fcf3ce44SJohn Forte */ 1861fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 1862fcf3ce44SJohn Forte if ((bp != NULL) && bp->b_bcount) { 1863fcf3ce44SJohn Forte buflen = bp->b_bcount; 1864fcf3ce44SJohn Forte first_burst_length = icp->conn_params.first_burst_length; 1865fcf3ce44SJohn Forte 1866fcf3ce44SJohn Forte if (bp->b_flags & B_READ) { 1867fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL; 1868fcf3ce44SJohn Forte /* 1869fcf3ce44SJohn Forte * fix problem where OS sends bp (B_READ & 1870fcf3ce44SJohn Forte * b_bcount!=0) for a TUR or START_STOP. 1871fcf3ce44SJohn Forte * (comment came from cisco code.) 1872fcf3ce44SJohn Forte */ 1873fcf3ce44SJohn Forte if ((pkt->pkt_cdbp[0] != SCMD_TEST_UNIT_READY) && 1874fcf3ce44SJohn Forte (pkt->pkt_cdbp[0] != SCMD_START_STOP)) { 1875fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_CMD_READ; 1876fcf3ce44SJohn Forte ihp->data_length = htonl(buflen); 1877fcf3ce44SJohn Forte } 1878fcf3ce44SJohn Forte } else { 1879fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_CMD_WRITE; 1880fcf3ce44SJohn Forte /* 1881fcf3ce44SJohn Forte * FinalBit on the the iSCSI PDU denotes this 1882fcf3ce44SJohn Forte * is the last PDU in the sequence. 1883fcf3ce44SJohn Forte * 1884fcf3ce44SJohn Forte * initial_r2t = true means R2T is required 1885fcf3ce44SJohn Forte * for additional PDU, so there will be no more 1886fcf3ce44SJohn Forte * unsolicited PDUs following 1887fcf3ce44SJohn Forte */ 1888fcf3ce44SJohn Forte if (icp->conn_params.initial_r2t) { 1889fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL; 1890fcf3ce44SJohn Forte } 1891fcf3ce44SJohn Forte 1892fcf3ce44SJohn Forte /* Check if we should send ImmediateData */ 1893fcf3ce44SJohn Forte if (icp->conn_params.immediate_data) { 1894fcf3ce44SJohn Forte imdata = MIN(MIN(buflen, 1895fcf3ce44SJohn Forte first_burst_length), 1896fcf3ce44SJohn Forte icmdp->cmd_conn->conn_params. 1897fcf3ce44SJohn Forte max_xmit_data_seg_len); 1898fcf3ce44SJohn Forte 1899fcf3ce44SJohn Forte /* 1900fcf3ce44SJohn Forte * if everything fits immediate, or 1901fcf3ce44SJohn Forte * we can send all burst data immediate 1902fcf3ce44SJohn Forte * (not unsol), set F 1903fcf3ce44SJohn Forte */ 1904fcf3ce44SJohn Forte if ((imdata == buflen) || 1905fcf3ce44SJohn Forte (imdata == first_burst_length)) { 1906fcf3ce44SJohn Forte ihp->flags |= ISCSI_FLAG_FINAL; 1907fcf3ce44SJohn Forte } 1908fcf3ce44SJohn Forte 1909fcf3ce44SJohn Forte hton24(ihp->dlength, imdata); 1910fcf3ce44SJohn Forte } 1911fcf3ce44SJohn Forte 1912fcf3ce44SJohn Forte /* total data transfer length */ 1913fcf3ce44SJohn Forte ihp->data_length = htonl(buflen); 1914fcf3ce44SJohn Forte } 1915fcf3ce44SJohn Forte } else { 1916fcf3ce44SJohn Forte ihp->flags = ISCSI_FLAG_FINAL; 1917fcf3ce44SJohn Forte buflen = 0; 1918fcf3ce44SJohn Forte } 1919fcf3ce44SJohn Forte 1920fcf3ce44SJohn Forte /* tagged queuing */ 1921fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_HTAG) { 1922fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_HEAD_OF_QUEUE; 1923fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_OTAG) { 1924fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_ORDERED; 1925fcf3ce44SJohn Forte } else if (pkt->pkt_flags & FLAG_STAG) { 1926fcf3ce44SJohn Forte ihp->flags |= ISCSI_ATTR_SIMPLE; 1927fcf3ce44SJohn Forte } else { 1928fcf3ce44SJohn Forte /* ihp->flags |= ISCSI_ATTR_UNTAGGED; */ 1929fcf3ce44SJohn Forte /* EMPTY */ 1930fcf3ce44SJohn Forte } 1931fcf3ce44SJohn Forte 1932fcf3ce44SJohn Forte /* iscsi states lun is based on spc.2 */ 1933fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(ihp->lun, icmdp->cmd_un.scsi.lun); 1934fcf3ce44SJohn Forte 1935fcf3ce44SJohn Forte if (icmdp->cmd_un.scsi.cmdlen <= 16) { 1936fcf3ce44SJohn Forte /* copy the SCSI Command Block into the PDU */ 1937fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb, 1938fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen); 1939fcf3ce44SJohn Forte } else { 1940fcf3ce44SJohn Forte iscsi_addl_hdr_t *iahp; 1941fcf3ce44SJohn Forte 1942fcf3ce44SJohn Forte iahp = (iscsi_addl_hdr_t *)ihp; 1943fcf3ce44SJohn Forte 1944fcf3ce44SJohn Forte ihp->hlength = (ADDLHDRSZ(icmdp->cmd_un.scsi.cmdlen) - 1945fcf3ce44SJohn Forte sizeof (iscsi_scsi_cmd_hdr_t) + 3) / 4; 1946fcf3ce44SJohn Forte iahp->ahs_hlen_hi = 0; 1947fcf3ce44SJohn Forte iahp->ahs_hlen_lo = (icmdp->cmd_un.scsi.cmdlen - 15); 1948fcf3ce44SJohn Forte iahp->ahs_key = 0x01; 1949fcf3ce44SJohn Forte iahp->ahs_resv = 0; 1950fcf3ce44SJohn Forte bcopy(pkt->pkt_cdbp, ihp->scb, 16); 1951fcf3ce44SJohn Forte bcopy(((char *)pkt->pkt_cdbp) + 16, &iahp->ahs_extscb[0], 1952fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen); 1953fcf3ce44SJohn Forte } 1954fcf3ce44SJohn Forte 1955fcf3ce44SJohn Forte /* 1956fcf3ce44SJohn Forte * Update all values before transfering. 1957fcf3ce44SJohn Forte * We should never touch the icmdp after 1958fcf3ce44SJohn Forte * transfering if there is no more data 1959fcf3ce44SJohn Forte * to send. The only case the sendpdu() 1960fcf3ce44SJohn Forte * will fail is a on a connection disconnect 1961fcf3ce44SJohn Forte * in that case the command will be flushed. 1962fcf3ce44SJohn Forte */ 1963fcf3ce44SJohn Forte pkt->pkt_state |= STATE_SENT_CMD; 1964fcf3ce44SJohn Forte 1965fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred += imdata; 1966fcf3ce44SJohn Forte 1967fcf3ce44SJohn Forte /* 1968fcf3ce44SJohn Forte * Check if there is additional data to transfer beyond what 1969fcf3ce44SJohn Forte * will be sent as part of the initial command. If InitialR2T 1970fcf3ce44SJohn Forte * is disabled then we should fake up a R2T so all the data, 1971fcf3ce44SJohn Forte * up to first burst length, is sent in an unsolicited 1972fcf3ce44SJohn Forte * fashion. We have already sent as much immediate data 1973fcf3ce44SJohn Forte * as possible. 1974fcf3ce44SJohn Forte */ 1975fcf3ce44SJohn Forte if ((buflen > 0) && 1976fcf3ce44SJohn Forte ((bp->b_flags & B_READ) == 0) && 1977fcf3ce44SJohn Forte (icp->conn_params.initial_r2t == 0) && 1978fcf3ce44SJohn Forte (MIN(first_burst_length, buflen) - imdata > 0)) { 1979fcf3ce44SJohn Forte 1980fcf3ce44SJohn Forte uint32_t xfer_len = MIN(first_burst_length, buflen) - imdata; 1981fcf3ce44SJohn Forte /* data will be chunked at tx */ 1982fcf3ce44SJohn Forte iscsi_handle_r2t(icp, icmdp, imdata, 1983fcf3ce44SJohn Forte xfer_len, ISCSI_RSVD_TASK_TAG); 1984fcf3ce44SJohn Forte } 1985fcf3ce44SJohn Forte 1986fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 1987fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 1988fcf3ce44SJohn Forte 1989fcf3ce44SJohn Forte /* Transfer Cmd PDU */ 1990fcf3ce44SJohn Forte if (imdata) { 1991fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 1992fcf3ce44SJohn Forte (iscsi_hdr_t *)ihp, icmdp->cmd_un.scsi.bp->b_un.b_addr, 1993fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 1994fcf3ce44SJohn Forte if (ISCSI_SUCCESS(rval)) { 1995fcf3ce44SJohn Forte KSTAT_ADD_CONN_TX_BYTES(icp, imdata); 1996fcf3ce44SJohn Forte } 1997fcf3ce44SJohn Forte } else { 1998fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 1999fcf3ce44SJohn Forte (iscsi_hdr_t *)ihp, NULL, 2000fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2001fcf3ce44SJohn Forte } 2002fcf3ce44SJohn Forte if (cdblen) { 2003fcf3ce44SJohn Forte kmem_free(ihp, ADDLHDRSZ(cdblen)); 2004fcf3ce44SJohn Forte } 2005fcf3ce44SJohn Forte 2006fcf3ce44SJohn Forte return (rval); 2007fcf3ce44SJohn Forte } 2008fcf3ce44SJohn Forte 2009fcf3ce44SJohn Forte 2010fcf3ce44SJohn Forte /* 2011fcf3ce44SJohn Forte * iscsi_tx_r2t - 2012fcf3ce44SJohn Forte * 2013fcf3ce44SJohn Forte */ 2014fcf3ce44SJohn Forte static iscsi_status_t 2015fcf3ce44SJohn Forte iscsi_tx_r2t(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2016fcf3ce44SJohn Forte { 2017fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2018fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2019fcf3ce44SJohn Forte iscsi_cmd_t *orig_icmdp = NULL; 2020fcf3ce44SJohn Forte 2021fcf3ce44SJohn Forte ASSERT(isp != NULL); 2022fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2023fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2024fcf3ce44SJohn Forte ASSERT(icp); 2025fcf3ce44SJohn Forte orig_icmdp = icmdp->cmd_un.r2t.icmdp; 2026fcf3ce44SJohn Forte ASSERT(orig_icmdp); 2027fcf3ce44SJohn Forte 2028fcf3ce44SJohn Forte /* validate the offset and length against the buffer size */ 2029fcf3ce44SJohn Forte if ((icmdp->cmd_un.r2t.offset + icmdp->cmd_un.r2t.length) > 2030fcf3ce44SJohn Forte orig_icmdp->cmd_un.scsi.bp->b_bcount) { 2031fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi session(%u) ignoring invalid r2t " 2032fcf3ce44SJohn Forte "for icmd itt:0x%x offset:0x%x length:0x%x bufsize:0x%lx", 2033fcf3ce44SJohn Forte isp->sess_oid, icmdp->cmd_itt, icmdp->cmd_un.r2t.offset, 2034fcf3ce44SJohn Forte icmdp->cmd_un.r2t.length, orig_icmdp->cmd_un.scsi.bp-> 2035fcf3ce44SJohn Forte b_bcount); 2036fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2037fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 2038fcf3ce44SJohn Forte } 2039fcf3ce44SJohn Forte ASSERT(orig_icmdp->cmd_un.scsi.r2t_icmdp); 2040fcf3ce44SJohn Forte 2041fcf3ce44SJohn Forte rval = iscsi_tx_data(isp, icp, orig_icmdp, icmdp->cmd_ttt, 2042fcf3ce44SJohn Forte icmdp->cmd_un.r2t.length, icmdp->cmd_un.r2t.offset); 2043fcf3ce44SJohn Forte 2044fcf3ce44SJohn Forte mutex_enter(&orig_icmdp->cmd_mutex); 2045fcf3ce44SJohn Forte orig_icmdp->cmd_un.scsi.r2t_icmdp = NULL; 2046fcf3ce44SJohn Forte icmdp->cmd_un.r2t.icmdp = NULL; 2047fcf3ce44SJohn Forte /* 2048fcf3ce44SJohn Forte * we're finished with this r2t; there could be another r2t 2049fcf3ce44SJohn Forte * waiting on us to finish, so signal it. 2050fcf3ce44SJohn Forte */ 2051fcf3ce44SJohn Forte cv_broadcast(&orig_icmdp->cmd_completion); 2052fcf3ce44SJohn Forte mutex_exit(&orig_icmdp->cmd_mutex); 2053fcf3ce44SJohn Forte /* 2054fcf3ce44SJohn Forte * the parent command may be waiting for us to finish; if so, 2055fcf3ce44SJohn Forte * wake the _ic_ thread 2056fcf3ce44SJohn Forte */ 2057fcf3ce44SJohn Forte if ((orig_icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED) && 2058fcf3ce44SJohn Forte (ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state))) 2059fcf3ce44SJohn Forte iscsi_thread_send_wakeup(isp->sess_ic_thread); 2060fcf3ce44SJohn Forte ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex)); 2061fcf3ce44SJohn Forte return (rval); 2062fcf3ce44SJohn Forte } 2063fcf3ce44SJohn Forte 2064fcf3ce44SJohn Forte 2065fcf3ce44SJohn Forte /* 2066fcf3ce44SJohn Forte * iscsi_tx_data - 2067fcf3ce44SJohn Forte */ 2068fcf3ce44SJohn Forte static iscsi_status_t 2069fcf3ce44SJohn Forte iscsi_tx_data(iscsi_sess_t *isp, iscsi_conn_t *icp, iscsi_cmd_t *icmdp, 2070fcf3ce44SJohn Forte uint32_t ttt, size_t datalen, size_t offset) 2071fcf3ce44SJohn Forte { 2072fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2073fcf3ce44SJohn Forte struct buf *bp = NULL; 2074fcf3ce44SJohn Forte size_t remainder = 0; 2075fcf3ce44SJohn Forte size_t chunk = 0; 2076fcf3ce44SJohn Forte char *data = NULL; 2077fcf3ce44SJohn Forte uint32_t data_sn = 0; 2078fcf3ce44SJohn Forte iscsi_data_hdr_t idhp; 2079fcf3ce44SJohn Forte uint32_t itt; 2080fcf3ce44SJohn Forte uint32_t lun; 2081fcf3ce44SJohn Forte 2082fcf3ce44SJohn Forte ASSERT(isp != NULL); 2083fcf3ce44SJohn Forte ASSERT(icp != NULL); 2084fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2085fcf3ce44SJohn Forte bp = icmdp->cmd_un.scsi.bp; 2086fcf3ce44SJohn Forte 2087fcf3ce44SJohn Forte /* verify there is data to send */ 2088fcf3ce44SJohn Forte if (bp == NULL) { 2089fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2090fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 2091fcf3ce44SJohn Forte } 2092fcf3ce44SJohn Forte 2093fcf3ce44SJohn Forte itt = icmdp->cmd_itt; 2094fcf3ce44SJohn Forte lun = icmdp->cmd_un.scsi.lun; 2095fcf3ce44SJohn Forte 2096fcf3ce44SJohn Forte /* 2097fcf3ce44SJohn Forte * update the LUN with the amount of data we will 2098fcf3ce44SJohn Forte * transfer. If there is a failure it's because of 2099fcf3ce44SJohn Forte * a network fault and the command will get flushed. 2100fcf3ce44SJohn Forte */ 2101fcf3ce44SJohn Forte icmdp->cmd_un.scsi.data_transferred += datalen; 2102fcf3ce44SJohn Forte 2103fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2104fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2105fcf3ce44SJohn Forte 2106fcf3ce44SJohn Forte remainder = datalen; 2107fcf3ce44SJohn Forte while (remainder) { 2108fcf3ce44SJohn Forte 2109fcf3ce44SJohn Forte /* Check so see if we need to chunk the data */ 2110fcf3ce44SJohn Forte if ((icp->conn_params.max_xmit_data_seg_len > 0) && 2111fcf3ce44SJohn Forte (remainder > icp->conn_params.max_xmit_data_seg_len)) { 2112fcf3ce44SJohn Forte chunk = icp->conn_params.max_xmit_data_seg_len; 2113fcf3ce44SJohn Forte } else { 2114fcf3ce44SJohn Forte chunk = remainder; 2115fcf3ce44SJohn Forte } 2116fcf3ce44SJohn Forte 2117fcf3ce44SJohn Forte /* setup iscsi data hdr */ 2118fcf3ce44SJohn Forte bzero(&idhp, sizeof (iscsi_data_hdr_t)); 2119fcf3ce44SJohn Forte idhp.opcode = ISCSI_OP_SCSI_DATA; 2120fcf3ce44SJohn Forte idhp.itt = itt; 2121fcf3ce44SJohn Forte idhp.ttt = ttt; 2122fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(idhp.lun, lun); 2123fcf3ce44SJohn Forte idhp.expstatsn = htonl(icp->conn_expstatsn); 2124fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 2125fcf3ce44SJohn Forte idhp.datasn = htonl(data_sn); 2126fcf3ce44SJohn Forte data_sn++; 2127fcf3ce44SJohn Forte idhp.offset = htonl(offset); 2128fcf3ce44SJohn Forte hton24(idhp.dlength, chunk); 2129fcf3ce44SJohn Forte 2130fcf3ce44SJohn Forte if (chunk == remainder) { 2131fcf3ce44SJohn Forte idhp.flags = ISCSI_FLAG_FINAL; /* final chunk */ 2132fcf3ce44SJohn Forte } 2133fcf3ce44SJohn Forte 2134fcf3ce44SJohn Forte /* setup data */ 2135fcf3ce44SJohn Forte data = bp->b_un.b_addr + offset; 2136fcf3ce44SJohn Forte 2137fcf3ce44SJohn Forte /* 2138fcf3ce44SJohn Forte * Keep track of how much data we have 2139fcf3ce44SJohn Forte * transfer so far and how much is remaining. 2140fcf3ce44SJohn Forte */ 2141fcf3ce44SJohn Forte remainder -= chunk; 2142fcf3ce44SJohn Forte offset += chunk; 2143fcf3ce44SJohn Forte 2144fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2145fcf3ce44SJohn Forte (iscsi_hdr_t *)&idhp, data, 2146fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2147fcf3ce44SJohn Forte 2148fcf3ce44SJohn Forte if (ISCSI_SUCCESS(rval)) { 2149fcf3ce44SJohn Forte KSTAT_ADD_CONN_TX_BYTES(icp, chunk); 2150fcf3ce44SJohn Forte } else { 2151fcf3ce44SJohn Forte break; 2152fcf3ce44SJohn Forte } 2153fcf3ce44SJohn Forte } 2154fcf3ce44SJohn Forte 2155fcf3ce44SJohn Forte return (rval); 2156fcf3ce44SJohn Forte } 2157fcf3ce44SJohn Forte 2158fcf3ce44SJohn Forte 2159fcf3ce44SJohn Forte /* 2160fcf3ce44SJohn Forte * iscsi_tx_nop - 2161fcf3ce44SJohn Forte * 2162fcf3ce44SJohn Forte */ 2163fcf3ce44SJohn Forte static iscsi_status_t 2164fcf3ce44SJohn Forte iscsi_tx_nop(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2165fcf3ce44SJohn Forte { 2166fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2167fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2168fcf3ce44SJohn Forte iscsi_nop_out_hdr_t inohp; 2169fcf3ce44SJohn Forte 2170fcf3ce44SJohn Forte ASSERT(isp != NULL); 2171fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2172fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2173fcf3ce44SJohn Forte ASSERT(icp != NULL); 2174fcf3ce44SJohn Forte 2175fcf3ce44SJohn Forte bzero(&inohp, sizeof (iscsi_nop_out_hdr_t)); 2176fcf3ce44SJohn Forte inohp.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; 2177fcf3ce44SJohn Forte inohp.flags = ISCSI_FLAG_FINAL; 2178fcf3ce44SJohn Forte inohp.itt = icmdp->cmd_itt; 2179fcf3ce44SJohn Forte inohp.ttt = icmdp->cmd_ttt; 2180fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 2181fcf3ce44SJohn Forte inohp.cmdsn = htonl(isp->sess_cmdsn); 2182fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 2183fcf3ce44SJohn Forte inohp.expstatsn = htonl(icp->conn_expstatsn); 2184fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 2185fcf3ce44SJohn Forte 2186fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2187fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2188fcf3ce44SJohn Forte 2189fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2190fcf3ce44SJohn Forte (iscsi_hdr_t *)&inohp, NULL, 2191fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2192fcf3ce44SJohn Forte 2193fcf3ce44SJohn Forte return (rval); 2194fcf3ce44SJohn Forte } 2195fcf3ce44SJohn Forte 2196fcf3ce44SJohn Forte 2197fcf3ce44SJohn Forte /* 2198fcf3ce44SJohn Forte * iscsi_tx_abort - 2199fcf3ce44SJohn Forte * 2200fcf3ce44SJohn Forte */ 2201fcf3ce44SJohn Forte static iscsi_status_t 2202fcf3ce44SJohn Forte iscsi_tx_abort(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2203fcf3ce44SJohn Forte { 2204fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2205fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2206fcf3ce44SJohn Forte iscsi_scsi_task_mgt_hdr_t istmh; 2207fcf3ce44SJohn Forte 2208fcf3ce44SJohn Forte ASSERT(isp != NULL); 2209fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2210fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2211fcf3ce44SJohn Forte ASSERT(icp != NULL); 2212fcf3ce44SJohn Forte 2213fcf3ce44SJohn Forte bzero(&istmh, sizeof (iscsi_scsi_task_mgt_hdr_t)); 2214fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 2215fcf3ce44SJohn Forte istmh.cmdsn = htonl(isp->sess_cmdsn); 2216fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 2217fcf3ce44SJohn Forte istmh.expstatsn = htonl(icp->conn_expstatsn); 2218fcf3ce44SJohn Forte icp->conn_laststatsn = icp->conn_expstatsn; 2219fcf3ce44SJohn Forte istmh.itt = icmdp->cmd_itt; 2220fcf3ce44SJohn Forte istmh.opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE; 2221fcf3ce44SJohn Forte istmh.function = ISCSI_FLAG_FINAL | ISCSI_TM_FUNC_ABORT_TASK; 2222fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(istmh.lun, 2223fcf3ce44SJohn Forte icmdp->cmd_un.abort.icmdp->cmd_un.scsi.lun); 2224fcf3ce44SJohn Forte istmh.rtt = icmdp->cmd_un.abort.icmdp->cmd_itt; 2225fcf3ce44SJohn Forte 2226fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2227fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2228fcf3ce44SJohn Forte 2229fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2230fcf3ce44SJohn Forte (iscsi_hdr_t *)&istmh, NULL, 2231fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2232fcf3ce44SJohn Forte 2233fcf3ce44SJohn Forte return (rval); 2234fcf3ce44SJohn Forte } 2235fcf3ce44SJohn Forte 2236fcf3ce44SJohn Forte 2237fcf3ce44SJohn Forte /* 2238fcf3ce44SJohn Forte * iscsi_tx_reset - 2239fcf3ce44SJohn Forte * 2240fcf3ce44SJohn Forte */ 2241fcf3ce44SJohn Forte static iscsi_status_t 2242fcf3ce44SJohn Forte iscsi_tx_reset(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2243fcf3ce44SJohn Forte { 2244fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2245fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2246fcf3ce44SJohn Forte iscsi_scsi_task_mgt_hdr_t istmh; 2247fcf3ce44SJohn Forte 2248fcf3ce44SJohn Forte ASSERT(isp != NULL); 2249fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2250fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2251fcf3ce44SJohn Forte ASSERT(icp != NULL); 2252fcf3ce44SJohn Forte 2253fcf3ce44SJohn Forte bzero(&istmh, sizeof (iscsi_scsi_task_mgt_hdr_t)); 2254fcf3ce44SJohn Forte istmh.opcode = ISCSI_OP_SCSI_TASK_MGT_MSG | ISCSI_OP_IMMEDIATE; 2255fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 2256fcf3ce44SJohn Forte istmh.cmdsn = htonl(isp->sess_cmdsn); 2257fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 2258fcf3ce44SJohn Forte istmh.expstatsn = htonl(icp->conn_expstatsn); 2259fcf3ce44SJohn Forte istmh.itt = icmdp->cmd_itt; 2260fcf3ce44SJohn Forte 2261fcf3ce44SJohn Forte switch (icmdp->cmd_un.reset.level) { 2262fcf3ce44SJohn Forte case RESET_LUN: 2263fcf3ce44SJohn Forte istmh.function = ISCSI_FLAG_FINAL | 2264fcf3ce44SJohn Forte ISCSI_TM_FUNC_LOGICAL_UNIT_RESET; 2265fcf3ce44SJohn Forte ISCSI_LUN_BYTE_COPY(istmh.lun, icmdp->cmd_lun->lun_num); 2266fcf3ce44SJohn Forte break; 2267fcf3ce44SJohn Forte case RESET_TARGET: 2268fcf3ce44SJohn Forte case RESET_BUS: 2269fcf3ce44SJohn Forte istmh.function = ISCSI_FLAG_FINAL | 2270fcf3ce44SJohn Forte ISCSI_TM_FUNC_TARGET_WARM_RESET; 2271fcf3ce44SJohn Forte break; 2272fcf3ce44SJohn Forte default: 2273fcf3ce44SJohn Forte /* unsupported / unknown level */ 2274fcf3ce44SJohn Forte ASSERT(FALSE); 2275fcf3ce44SJohn Forte break; 2276fcf3ce44SJohn Forte } 2277fcf3ce44SJohn Forte 2278fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2279fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2280fcf3ce44SJohn Forte 2281fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2282fcf3ce44SJohn Forte (iscsi_hdr_t *)&istmh, NULL, 2283fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2284fcf3ce44SJohn Forte 2285fcf3ce44SJohn Forte return (rval); 2286fcf3ce44SJohn Forte } 2287fcf3ce44SJohn Forte 2288fcf3ce44SJohn Forte 2289fcf3ce44SJohn Forte /* 2290fcf3ce44SJohn Forte * iscsi_tx_logout - 2291fcf3ce44SJohn Forte * 2292fcf3ce44SJohn Forte */ 2293fcf3ce44SJohn Forte static iscsi_status_t 2294fcf3ce44SJohn Forte iscsi_tx_logout(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2295fcf3ce44SJohn Forte { 2296fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2297fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2298fcf3ce44SJohn Forte iscsi_logout_hdr_t ilh; 2299fcf3ce44SJohn Forte 2300fcf3ce44SJohn Forte ASSERT(isp != NULL); 2301fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2302fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2303fcf3ce44SJohn Forte ASSERT(icp != NULL); 2304fcf3ce44SJohn Forte 2305fcf3ce44SJohn Forte bzero(&ilh, sizeof (iscsi_logout_hdr_t)); 2306fcf3ce44SJohn Forte ilh.opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE; 2307fcf3ce44SJohn Forte ilh.flags = ISCSI_FLAG_FINAL | ISCSI_LOGOUT_REASON_CLOSE_SESSION; 2308fcf3ce44SJohn Forte ilh.itt = icmdp->cmd_itt; 2309fcf3ce44SJohn Forte ilh.cid = icp->conn_cid; 2310fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 2311fcf3ce44SJohn Forte ilh.cmdsn = htonl(isp->sess_cmdsn); 2312fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 2313fcf3ce44SJohn Forte ilh.expstatsn = htonl(icp->conn_expstatsn); 2314fcf3ce44SJohn Forte 2315fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2316fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2317fcf3ce44SJohn Forte 2318fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2319fcf3ce44SJohn Forte (iscsi_hdr_t *)&ilh, NULL, 2320fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2321fcf3ce44SJohn Forte 2322fcf3ce44SJohn Forte return (rval); 2323fcf3ce44SJohn Forte } 2324fcf3ce44SJohn Forte 2325fcf3ce44SJohn Forte /* 2326fcf3ce44SJohn Forte * iscsi_tx_text - setup iSCSI text request header and send PDU with 2327fcf3ce44SJohn Forte * data given in the buffer attached to the command. For a single 2328fcf3ce44SJohn Forte * text request, the target may need to send its response in multiple 2329fcf3ce44SJohn Forte * text response. In this case, empty text requests are sent after 2330fcf3ce44SJohn Forte * each received response to notify the target the initiator is ready 2331fcf3ce44SJohn Forte * for more response. For the initial request, the data_len field in 2332fcf3ce44SJohn Forte * the text specific portion of a command is set to the amount of data 2333fcf3ce44SJohn Forte * the initiator wants to send as part of the request. If additional 2334fcf3ce44SJohn Forte * empty text requests are required for long responses, the data_len 2335fcf3ce44SJohn Forte * field is set to 0 by the iscsi_handle_text function. 2336fcf3ce44SJohn Forte */ 2337fcf3ce44SJohn Forte static iscsi_status_t 2338fcf3ce44SJohn Forte iscsi_tx_text(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2339fcf3ce44SJohn Forte { 2340fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2341fcf3ce44SJohn Forte iscsi_conn_t *icp = NULL; 2342fcf3ce44SJohn Forte iscsi_text_hdr_t ith; 2343fcf3ce44SJohn Forte 2344fcf3ce44SJohn Forte ASSERT(isp != NULL); 2345fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2346fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2347fcf3ce44SJohn Forte ASSERT(icp != NULL); 2348fcf3ce44SJohn Forte 2349fcf3ce44SJohn Forte bzero(&ith, sizeof (iscsi_text_hdr_t)); 2350fcf3ce44SJohn Forte ith.opcode = ISCSI_OP_TEXT_CMD; 2351fcf3ce44SJohn Forte ith.flags = ISCSI_FLAG_FINAL; 2352fcf3ce44SJohn Forte hton24(ith.dlength, icmdp->cmd_un.text.data_len); 2353fcf3ce44SJohn Forte ith.itt = icmdp->cmd_itt; 2354fcf3ce44SJohn Forte ith.ttt = icmdp->cmd_un.text.ttt; 2355fcf3ce44SJohn Forte mutex_enter(&isp->sess_cmdsn_mutex); 2356fcf3ce44SJohn Forte ith.cmdsn = htonl(isp->sess_cmdsn); 2357fcf3ce44SJohn Forte isp->sess_cmdsn++; 2358fcf3ce44SJohn Forte ith.expstatsn = htonl(icp->conn_expstatsn); 2359fcf3ce44SJohn Forte mutex_exit(&isp->sess_cmdsn_mutex); 2360fcf3ce44SJohn Forte bcopy(icmdp->cmd_un.text.lun, ith.rsvd4, sizeof (ith.rsvd4)); 2361fcf3ce44SJohn Forte 2362fcf3ce44SJohn Forte /* release pending queue mutex across the network call */ 2363fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2364fcf3ce44SJohn Forte 2365fcf3ce44SJohn Forte rval = iscsi_net->sendpdu(icp->conn_socket, 2366fcf3ce44SJohn Forte (iscsi_hdr_t *)&ith, icmdp->cmd_un.text.buf, 2367fcf3ce44SJohn Forte ISCSI_CONN_TO_NET_DIGEST(icp)); 2368fcf3ce44SJohn Forte 2369fcf3ce44SJohn Forte return (rval); 2370fcf3ce44SJohn Forte } 2371fcf3ce44SJohn Forte 2372fcf3ce44SJohn Forte /* 2373fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2374fcf3ce44SJohn Forte * | End of protocol send routines | 2375fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2376fcf3ce44SJohn Forte */ 2377fcf3ce44SJohn Forte 2378fcf3ce44SJohn Forte /* 2379fcf3ce44SJohn Forte * iscsi_handle_r2t - 2380fcf3ce44SJohn Forte */ 2381fcf3ce44SJohn Forte static void 2382fcf3ce44SJohn Forte iscsi_handle_r2t(iscsi_conn_t *icp, iscsi_cmd_t *icmdp, 2383fcf3ce44SJohn Forte uint32_t offset, uint32_t length, uint32_t ttt) 2384fcf3ce44SJohn Forte { 2385fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 2386fcf3ce44SJohn Forte iscsi_cmd_t *new_icmdp = NULL; 2387fcf3ce44SJohn Forte 2388fcf3ce44SJohn Forte ASSERT(icp != NULL); 2389fcf3ce44SJohn Forte isp = icp->conn_sess; 2390fcf3ce44SJohn Forte ASSERT(isp != NULL); 2391fcf3ce44SJohn Forte 2392fcf3ce44SJohn Forte /* 2393fcf3ce44SJohn Forte * the sosendmsg from a previous r2t can be slow to return; 2394fcf3ce44SJohn Forte * the array may have sent another r2t at this point, so 2395fcf3ce44SJohn Forte * wait until the first one finishes and signals us. 2396fcf3ce44SJohn Forte */ 2397fcf3ce44SJohn Forte while (icmdp->cmd_un.scsi.r2t_icmdp != NULL) { 2398fcf3ce44SJohn Forte ASSERT(icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED); 2399fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2400fcf3ce44SJohn Forte } 2401fcf3ce44SJohn Forte /* 2402fcf3ce44SJohn Forte * try to create an R2T task to send it later. If we can't, 2403fcf3ce44SJohn Forte * we're screwed, and the command will eventually time out 2404fcf3ce44SJohn Forte * and be retried by the SCSI layer. 2405fcf3ce44SJohn Forte */ 2406fcf3ce44SJohn Forte new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2407fcf3ce44SJohn Forte new_icmdp->cmd_type = ISCSI_CMD_TYPE_R2T; 2408fcf3ce44SJohn Forte new_icmdp->cmd_un.r2t.icmdp = icmdp; 2409fcf3ce44SJohn Forte new_icmdp->cmd_un.r2t.offset = offset; 2410fcf3ce44SJohn Forte new_icmdp->cmd_un.r2t.length = length; 2411fcf3ce44SJohn Forte new_icmdp->cmd_ttt = ttt; 2412fcf3ce44SJohn Forte new_icmdp->cmd_itt = icmdp->cmd_itt; 2413fcf3ce44SJohn Forte new_icmdp->cmd_lun = icmdp->cmd_lun; 2414fcf3ce44SJohn Forte icmdp->cmd_un.scsi.r2t_icmdp = new_icmdp; 2415fcf3ce44SJohn Forte 2416fcf3ce44SJohn Forte /* 2417fcf3ce44SJohn Forte * pending queue mutex is already held by the 2418fcf3ce44SJohn Forte * tx_thread or rtt_rsp function. 2419fcf3ce44SJohn Forte */ 2420fcf3ce44SJohn Forte iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp); 2421fcf3ce44SJohn Forte } 2422fcf3ce44SJohn Forte 2423fcf3ce44SJohn Forte 2424fcf3ce44SJohn Forte /* 2425fcf3ce44SJohn Forte * iscsi_handle_abort - 2426fcf3ce44SJohn Forte * 2427fcf3ce44SJohn Forte */ 2428fcf3ce44SJohn Forte void 2429fcf3ce44SJohn Forte iscsi_handle_abort(void *arg) 2430fcf3ce44SJohn Forte { 2431fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 2432fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = (iscsi_cmd_t *)arg; 2433fcf3ce44SJohn Forte iscsi_cmd_t *new_icmdp; 2434fcf3ce44SJohn Forte iscsi_conn_t *icp; 2435fcf3ce44SJohn Forte 2436fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2437fcf3ce44SJohn Forte icp = icmdp->cmd_conn; 2438fcf3ce44SJohn Forte ASSERT(icp != NULL); 2439fcf3ce44SJohn Forte isp = icp->conn_sess; 2440fcf3ce44SJohn Forte ASSERT(isp != NULL); 2441fcf3ce44SJohn Forte 2442fcf3ce44SJohn Forte /* there should only be one abort */ 2443fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL); 2444fcf3ce44SJohn Forte 2445fcf3ce44SJohn Forte new_icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2446fcf3ce44SJohn Forte new_icmdp->cmd_type = ISCSI_CMD_TYPE_ABORT; 2447fcf3ce44SJohn Forte new_icmdp->cmd_lun = icmdp->cmd_lun; 2448fcf3ce44SJohn Forte new_icmdp->cmd_un.abort.icmdp = icmdp; 2449fcf3ce44SJohn Forte new_icmdp->cmd_conn = icmdp->cmd_conn; 2450fcf3ce44SJohn Forte icmdp->cmd_un.scsi.abort_icmdp = new_icmdp; 2451fcf3ce44SJohn Forte 2452fcf3ce44SJohn Forte /* pending queue mutex is already held by timeout_checks */ 2453fcf3ce44SJohn Forte iscsi_cmd_state_machine(new_icmdp, ISCSI_CMD_EVENT_E1, isp); 2454fcf3ce44SJohn Forte } 2455fcf3ce44SJohn Forte 2456fcf3ce44SJohn Forte 2457fcf3ce44SJohn Forte /* 2458fcf3ce44SJohn Forte * iscsi_handle_nop - 2459fcf3ce44SJohn Forte * 2460fcf3ce44SJohn Forte */ 2461fcf3ce44SJohn Forte static void 2462fcf3ce44SJohn Forte iscsi_handle_nop(iscsi_conn_t *icp, uint32_t itt, uint32_t ttt) 2463fcf3ce44SJohn Forte { 2464fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL; 2465fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 2466fcf3ce44SJohn Forte 2467fcf3ce44SJohn Forte ASSERT(icp != NULL); 2468fcf3ce44SJohn Forte isp = icp->conn_sess; 2469fcf3ce44SJohn Forte ASSERT(isp != NULL); 2470fcf3ce44SJohn Forte 2471fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_NOSLEEP); 2472fcf3ce44SJohn Forte if (icmdp == NULL) { 2473fcf3ce44SJohn Forte return; 2474fcf3ce44SJohn Forte } 2475fcf3ce44SJohn Forte 2476fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_NOP; 2477fcf3ce44SJohn Forte icmdp->cmd_itt = itt; 2478fcf3ce44SJohn Forte icmdp->cmd_ttt = ttt; 2479fcf3ce44SJohn Forte icmdp->cmd_lun = NULL; 2480fcf3ce44SJohn Forte icp->conn_nop_lbolt = ddi_get_lbolt(); 2481fcf3ce44SJohn Forte 2482fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2483fcf3ce44SJohn Forte } 2484fcf3ce44SJohn Forte 2485fcf3ce44SJohn Forte /* 2486fcf3ce44SJohn Forte * iscsi_handle_reset - 2487fcf3ce44SJohn Forte * 2488fcf3ce44SJohn Forte */ 2489fcf3ce44SJohn Forte iscsi_status_t 2490fcf3ce44SJohn Forte iscsi_handle_reset(iscsi_sess_t *isp, int level, iscsi_lun_t *ilp) 2491fcf3ce44SJohn Forte { 2492fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2493fcf3ce44SJohn Forte iscsi_conn_t *icp; 2494fcf3ce44SJohn Forte iscsi_cmd_t icmd; 2495fcf3ce44SJohn Forte 2496fcf3ce44SJohn Forte ASSERT(isp != NULL); 2497fcf3ce44SJohn Forte 2498fcf3ce44SJohn Forte bzero(&icmd, sizeof (iscsi_cmd_t)); 2499fcf3ce44SJohn Forte icmd.cmd_sig = ISCSI_SIG_CMD; 2500fcf3ce44SJohn Forte icmd.cmd_state = ISCSI_CMD_STATE_FREE; 2501fcf3ce44SJohn Forte icmd.cmd_type = ISCSI_CMD_TYPE_RESET; 2502fcf3ce44SJohn Forte icmd.cmd_lun = ilp; 2503fcf3ce44SJohn Forte icmd.cmd_un.reset.level = level; 2504fcf3ce44SJohn Forte icmd.cmd_result = ISCSI_STATUS_SUCCESS; 2505fcf3ce44SJohn Forte icmd.cmd_completed = B_FALSE; 2506fcf3ce44SJohn Forte mutex_init(&icmd.cmd_mutex, NULL, MUTEX_DRIVER, NULL); 2507fcf3ce44SJohn Forte cv_init(&icmd.cmd_completion, NULL, CV_DRIVER, NULL); 2508fcf3ce44SJohn Forte /* 2509fcf3ce44SJohn Forte * If we received an IO and we are not in the 2510fcf3ce44SJohn Forte * LOGGED_IN state we are in the process of 2511fcf3ce44SJohn Forte * failing. Just respond that we are BUSY. 2512fcf3ce44SJohn Forte */ 2513fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 2514fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 2515fcf3ce44SJohn Forte /* We aren't connected to the target fake success */ 2516fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2517fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 2518fcf3ce44SJohn Forte } 2519fcf3ce44SJohn Forte 2520fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2521fcf3ce44SJohn Forte iscsi_cmd_state_machine(&icmd, ISCSI_CMD_EVENT_E1, isp); 2522fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2523fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2524fcf3ce44SJohn Forte 2525fcf3ce44SJohn Forte /* stall until completed */ 2526fcf3ce44SJohn Forte mutex_enter(&icmd.cmd_mutex); 2527fcf3ce44SJohn Forte while (icmd.cmd_completed == B_FALSE) { 2528fcf3ce44SJohn Forte cv_wait(&icmd.cmd_completion, &icmd.cmd_mutex); 2529fcf3ce44SJohn Forte } 2530fcf3ce44SJohn Forte mutex_exit(&icmd.cmd_mutex); 2531fcf3ce44SJohn Forte 2532fcf3ce44SJohn Forte /* copy rval */ 2533fcf3ce44SJohn Forte rval = icmd.cmd_result; 2534fcf3ce44SJohn Forte 2535fcf3ce44SJohn Forte if (rval == ISCSI_STATUS_SUCCESS) { 2536fcf3ce44SJohn Forte /* 2537fcf3ce44SJohn Forte * Reset was successful. We need to flush 2538fcf3ce44SJohn Forte * all active IOs. 2539fcf3ce44SJohn Forte */ 2540fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 2541fcf3ce44SJohn Forte icp = isp->sess_conn_list; 2542fcf3ce44SJohn Forte while (icp != NULL) { 2543fcf3ce44SJohn Forte iscsi_cmd_t *t_icmdp = NULL; 2544fcf3ce44SJohn Forte 2545fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 2546fcf3ce44SJohn Forte t_icmdp = icp->conn_queue_active.head; 2547fcf3ce44SJohn Forte while (t_icmdp != NULL) { 2548fcf3ce44SJohn Forte iscsi_cmd_state_machine(t_icmdp, 2549fcf3ce44SJohn Forte ISCSI_CMD_EVENT_E7, isp); 2550fcf3ce44SJohn Forte t_icmdp = icp->conn_queue_active.head; 2551fcf3ce44SJohn Forte } 2552fcf3ce44SJohn Forte 2553fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 2554fcf3ce44SJohn Forte icp = icp->conn_next; 2555fcf3ce44SJohn Forte } 2556fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 2557fcf3ce44SJohn Forte } 2558fcf3ce44SJohn Forte 2559fcf3ce44SJohn Forte /* clean up */ 2560fcf3ce44SJohn Forte cv_destroy(&icmd.cmd_completion); 2561fcf3ce44SJohn Forte mutex_destroy(&icmd.cmd_mutex); 2562fcf3ce44SJohn Forte 2563fcf3ce44SJohn Forte return (rval); 2564fcf3ce44SJohn Forte } 2565fcf3ce44SJohn Forte 2566fcf3ce44SJohn Forte 2567fcf3ce44SJohn Forte /* 2568fcf3ce44SJohn Forte * iscsi_handle_logout - This function will issue a logout for 2569fcf3ce44SJohn Forte * the session from a specific connection. 2570fcf3ce44SJohn Forte */ 2571fcf3ce44SJohn Forte iscsi_status_t 2572fcf3ce44SJohn Forte iscsi_handle_logout(iscsi_conn_t *icp) 2573fcf3ce44SJohn Forte { 2574fcf3ce44SJohn Forte iscsi_sess_t *isp; 2575fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 2576fcf3ce44SJohn Forte int rval; 2577fcf3ce44SJohn Forte 2578fcf3ce44SJohn Forte ASSERT(icp != NULL); 2579fcf3ce44SJohn Forte isp = icp->conn_sess; 2580fcf3ce44SJohn Forte ASSERT(isp != NULL); 2581fcf3ce44SJohn Forte ASSERT(isp->sess_hba != NULL); 2582fcf3ce44SJohn Forte 2583fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2584fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2585fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_LOGOUT; 2586fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2587fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2588fcf3ce44SJohn Forte 2589fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2590fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2591fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2592fcf3ce44SJohn Forte 2593fcf3ce44SJohn Forte /* 2594fcf3ce44SJohn Forte * release connection state mutex to avoid a deadlock. This 2595fcf3ce44SJohn Forte * function is called from within the connection state 2596fcf3ce44SJohn Forte * machine with the lock held. When the logout response is 2597fcf3ce44SJohn Forte * received another call to the connection state machine 2598fcf3ce44SJohn Forte * occurs which causes the deadlock 2599fcf3ce44SJohn Forte */ 2600fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 2601fcf3ce44SJohn Forte 2602fcf3ce44SJohn Forte /* stall until completed */ 2603fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2604fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 2605fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2606fcf3ce44SJohn Forte } 2607fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2608fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 2609fcf3ce44SJohn Forte 2610fcf3ce44SJohn Forte /* copy rval */ 2611fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2612fcf3ce44SJohn Forte 2613fcf3ce44SJohn Forte /* 2614fcf3ce44SJohn Forte * another way to do this would be to send t17 unconditionally, 2615fcf3ce44SJohn Forte * but then the _rx_ thread would get bumped out with a receive 2616fcf3ce44SJohn Forte * error, and send another t17. 2617fcf3ce44SJohn Forte */ 2618fcf3ce44SJohn Forte if (rval != ISCSI_STATUS_SUCCESS) { 2619fcf3ce44SJohn Forte (void) iscsi_conn_state_machine(icp, ISCSI_CONN_EVENT_T17); 2620fcf3ce44SJohn Forte } 2621fcf3ce44SJohn Forte 2622fcf3ce44SJohn Forte /* clean up */ 2623fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2624fcf3ce44SJohn Forte 2625fcf3ce44SJohn Forte return (rval); 2626fcf3ce44SJohn Forte } 2627fcf3ce44SJohn Forte 2628fcf3ce44SJohn Forte /* 2629fcf3ce44SJohn Forte * iscsi_handle_text - main control function for iSCSI text requests. This 2630fcf3ce44SJohn Forte * function handles allocating the command, sending initial text request, and 2631fcf3ce44SJohn Forte * handling long response sequence. 2632fcf3ce44SJohn Forte * If a data overflow condition occurs, iscsi_handle_text continues to 2633fcf3ce44SJohn Forte * receive responses until the all data has been recieved. This allows 2634fcf3ce44SJohn Forte * the full data length to be returned to the caller. 2635fcf3ce44SJohn Forte */ 2636fcf3ce44SJohn Forte iscsi_status_t 2637fcf3ce44SJohn Forte iscsi_handle_text(iscsi_conn_t *icp, char *buf, uint32_t buf_len, 2638fcf3ce44SJohn Forte uint32_t data_len, uint32_t *rx_data_len) 2639fcf3ce44SJohn Forte { 2640fcf3ce44SJohn Forte iscsi_sess_t *isp; 2641fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 2642fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2643fcf3ce44SJohn Forte 2644fcf3ce44SJohn Forte ASSERT(icp != NULL); 2645fcf3ce44SJohn Forte ASSERT(buf != NULL); 2646fcf3ce44SJohn Forte ASSERT(rx_data_len != NULL); 2647fcf3ce44SJohn Forte 2648fcf3ce44SJohn Forte isp = icp->conn_sess; 2649fcf3ce44SJohn Forte ASSERT(isp != NULL); 2650fcf3ce44SJohn Forte 2651fcf3ce44SJohn Forte /* 2652fcf3ce44SJohn Forte * Ensure data for text request command is not greater 2653fcf3ce44SJohn Forte * than the negotiated maximum receive data seqment length. 2654fcf3ce44SJohn Forte * 2655fcf3ce44SJohn Forte * Although iSCSI allows for long text requests (multiple 2656fcf3ce44SJohn Forte * pdus), this function places a restriction on text 2657fcf3ce44SJohn Forte * requests to ensure it is handled by a single PDU. 2658fcf3ce44SJohn Forte */ 2659fcf3ce44SJohn Forte if (data_len > icp->conn_params.max_xmit_data_seg_len) { 2660fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED); 2661fcf3ce44SJohn Forte } 2662fcf3ce44SJohn Forte 2663fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(icp, KM_SLEEP); 2664fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2665fcf3ce44SJohn Forte 2666fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_TEXT; 2667fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2668d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE; 2669fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2670fcf3ce44SJohn Forte 2671fcf3ce44SJohn Forte icmdp->cmd_un.text.buf = buf; 2672fcf3ce44SJohn Forte icmdp->cmd_un.text.buf_len = buf_len; 2673fcf3ce44SJohn Forte icmdp->cmd_un.text.offset = 0; 2674fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = data_len; 2675fcf3ce44SJohn Forte icmdp->cmd_un.text.total_rx_len = 0; 2676fcf3ce44SJohn Forte icmdp->cmd_un.text.ttt = ISCSI_RSVD_TASK_TAG; 2677fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_INITIAL_REQ; 2678fcf3ce44SJohn Forte 2679fcf3ce44SJohn Forte long_text_response: 2680fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 2681fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 2682fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2683fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2684fcf3ce44SJohn Forte return (ISCSI_STATUS_NO_CONN_LOGGED_IN); 2685fcf3ce44SJohn Forte } 2686fcf3ce44SJohn Forte 2687fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2688fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2689fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2690fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2691fcf3ce44SJohn Forte 2692fcf3ce44SJohn Forte /* stall until completed */ 2693fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2694fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 2695fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2696fcf3ce44SJohn Forte } 2697fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2698fcf3ce44SJohn Forte 2699fcf3ce44SJohn Forte /* 2700fcf3ce44SJohn Forte * check if error occured. If data overflow occured, continue on 2701fcf3ce44SJohn Forte * to ensure we get all data so that the full data length can be 2702fcf3ce44SJohn Forte * returned to the user 2703fcf3ce44SJohn Forte */ 2704fcf3ce44SJohn Forte if ((icmdp->cmd_result != ISCSI_STATUS_SUCCESS) && 2705fcf3ce44SJohn Forte (icmdp->cmd_result != ISCSI_STATUS_DATA_OVERFLOW)) { 2706fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi: SendTarget discovery failed (%d)", 2707fcf3ce44SJohn Forte icmdp->cmd_result); 2708fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2709fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2710fcf3ce44SJohn Forte return (rval); 2711fcf3ce44SJohn Forte } 2712fcf3ce44SJohn Forte 2713fcf3ce44SJohn Forte /* check if this was a partial text PDU */ 2714fcf3ce44SJohn Forte if (icmdp->cmd_un.text.stage != ISCSI_CMD_TEXT_FINAL_RSP) { 2715fcf3ce44SJohn Forte /* 2716fcf3ce44SJohn Forte * If a paritial text rexponse received, send an empty 2717fcf3ce44SJohn Forte * text request. This follows the behaviour specified 2718fcf3ce44SJohn Forte * in RFC3720 regarding long text responses. 2719fcf3ce44SJohn Forte */ 2720d233de7eSJack Meng icmdp->cmd_misc_flags &= ~ISCSI_CMD_MISCFLAG_FREE; 2721fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2722fcf3ce44SJohn Forte icmdp->cmd_un.text.data_len = 0; 2723fcf3ce44SJohn Forte icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_CONTINUATION; 2724fcf3ce44SJohn Forte goto long_text_response; 2725fcf3ce44SJohn Forte } 2726fcf3ce44SJohn Forte 2727fcf3ce44SJohn Forte /* 2728fcf3ce44SJohn Forte * set total received data length. If data overflow this would be 2729fcf3ce44SJohn Forte * amount of data that would have been received if buffer large 2730fcf3ce44SJohn Forte * enough. 2731fcf3ce44SJohn Forte */ 2732fcf3ce44SJohn Forte *rx_data_len = icmdp->cmd_un.text.total_rx_len; 2733fcf3ce44SJohn Forte 2734fcf3ce44SJohn Forte /* copy rval */ 2735fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2736fcf3ce44SJohn Forte 2737fcf3ce44SJohn Forte /* clean up */ 2738fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2739fcf3ce44SJohn Forte 2740fcf3ce44SJohn Forte return (rval); 2741fcf3ce44SJohn Forte } 2742fcf3ce44SJohn Forte 2743fcf3ce44SJohn Forte /* 2744fcf3ce44SJohn Forte * iscsi_handle_passthru - This function is used to send a uscsi_cmd 2745fcf3ce44SJohn Forte * to a specific target lun. This routine is used for internal purposes 2746fcf3ce44SJohn Forte * during enumeration and via the ISCSI_USCSICMD IOCTL. We restrict 2747fcf3ce44SJohn Forte * the CDBs that can be issued to a target/lun to INQUIRY, REPORT_LUNS, 2748fcf3ce44SJohn Forte * and READ_CAPACITY for security purposes. 2749fcf3ce44SJohn Forte * 2750fcf3ce44SJohn Forte * The logic here is broken into three phases. 2751fcf3ce44SJohn Forte * 1) Allocate and initialize a pkt/icmdp 2752fcf3ce44SJohn Forte * 2) Send the pkt/icmdp 2753fcf3ce44SJohn Forte * 3) cv_wait for completion 2754fcf3ce44SJohn Forte */ 2755fcf3ce44SJohn Forte iscsi_status_t 2756fcf3ce44SJohn Forte iscsi_handle_passthru(iscsi_sess_t *isp, uint16_t lun, struct uscsi_cmd *ucmdp) 2757fcf3ce44SJohn Forte { 2758fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_SUCCESS; 2759fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 2760fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 2761fcf3ce44SJohn Forte struct buf *bp = NULL; 2762fcf3ce44SJohn Forte struct scsi_arq_status *arqstat = NULL; 2763fcf3ce44SJohn Forte int rqlen = SENSE_LENGTH; 2764fcf3ce44SJohn Forte 2765fcf3ce44SJohn Forte ASSERT(isp != NULL); 2766fcf3ce44SJohn Forte ASSERT(ucmdp != NULL); 2767fcf3ce44SJohn Forte 2768fcf3ce44SJohn Forte /* 2769fcf3ce44SJohn Forte * If the caller didn't provide a sense buffer we need 2770fcf3ce44SJohn Forte * to allocation one to get the scsi status. 2771fcf3ce44SJohn Forte */ 2772fcf3ce44SJohn Forte if (ucmdp->uscsi_rqlen > SENSE_LENGTH) { 2773fcf3ce44SJohn Forte rqlen = ucmdp->uscsi_rqlen; 2774fcf3ce44SJohn Forte } 2775fcf3ce44SJohn Forte 2776fcf3ce44SJohn Forte /* 2777fcf3ce44SJohn Forte * Step 1. Setup structs - KM_SLEEP will always succeed 2778fcf3ce44SJohn Forte */ 2779fcf3ce44SJohn Forte bp = kmem_zalloc(sizeof (struct buf), KM_SLEEP); 2780fcf3ce44SJohn Forte ASSERT(bp != NULL); 2781fcf3ce44SJohn Forte pkt = kmem_zalloc(sizeof (struct scsi_pkt), KM_SLEEP); 2782fcf3ce44SJohn Forte ASSERT(pkt != NULL); 2783fcf3ce44SJohn Forte icmdp = iscsi_cmd_alloc(NULL, KM_SLEEP); 2784fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2785fcf3ce44SJohn Forte 2786fcf3ce44SJohn Forte /* setup bp structure */ 2787fcf3ce44SJohn Forte bp->b_flags = B_READ; 2788fcf3ce44SJohn Forte bp->b_bcount = ucmdp->uscsi_buflen; 2789fcf3ce44SJohn Forte bp->b_un.b_addr = ucmdp->uscsi_bufaddr; 2790fcf3ce44SJohn Forte 2791fcf3ce44SJohn Forte /* setup scsi_pkt structure */ 2792fcf3ce44SJohn Forte pkt->pkt_ha_private = icmdp; 2793fcf3ce44SJohn Forte pkt->pkt_scbp = kmem_zalloc(rqlen, KM_SLEEP); 2794fcf3ce44SJohn Forte pkt->pkt_cdbp = kmem_zalloc(ucmdp->uscsi_cdblen, KM_SLEEP); 2795fcf3ce44SJohn Forte /* callback routine for passthru, will wake cv_wait */ 2796fcf3ce44SJohn Forte pkt->pkt_comp = iscsi_handle_passthru_callback; 2797fcf3ce44SJohn Forte pkt->pkt_time = ucmdp->uscsi_timeout; 2798fcf3ce44SJohn Forte 2799fcf3ce44SJohn Forte /* setup iscsi_cmd structure */ 2800fcf3ce44SJohn Forte icmdp->cmd_lun = NULL; 2801fcf3ce44SJohn Forte icmdp->cmd_type = ISCSI_CMD_TYPE_SCSI; 2802fcf3ce44SJohn Forte icmdp->cmd_un.scsi.lun = lun; 2803fcf3ce44SJohn Forte icmdp->cmd_un.scsi.pkt = pkt; 2804fcf3ce44SJohn Forte icmdp->cmd_un.scsi.bp = bp; 2805fcf3ce44SJohn Forte bcopy(ucmdp->uscsi_cdb, pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 2806fcf3ce44SJohn Forte icmdp->cmd_un.scsi.cmdlen = ucmdp->uscsi_cdblen; 2807fcf3ce44SJohn Forte icmdp->cmd_un.scsi.statuslen = rqlen; 2808fcf3ce44SJohn Forte icmdp->cmd_crc_error_seen = B_FALSE; 2809fcf3ce44SJohn Forte icmdp->cmd_completed = B_FALSE; 2810fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2811fcf3ce44SJohn Forte 2812fcf3ce44SJohn Forte /* 2813fcf3ce44SJohn Forte * Step 2. Push IO onto pending queue. If we aren't in 2814fcf3ce44SJohn Forte * FULL_FEATURE we need to fail the IO. 2815fcf3ce44SJohn Forte */ 2816fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 2817fcf3ce44SJohn Forte if (!ISCSI_SESS_STATE_FULL_FEATURE(isp->sess_state)) { 2818fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2819fcf3ce44SJohn Forte 2820fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2821fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 2822fcf3ce44SJohn Forte kmem_free(pkt->pkt_scbp, rqlen); 2823fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt)); 2824fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf)); 2825fcf3ce44SJohn Forte 2826fcf3ce44SJohn Forte return (ISCSI_STATUS_CMD_FAILED); 2827fcf3ce44SJohn Forte } 2828fcf3ce44SJohn Forte 2829fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 2830fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E1, isp); 2831fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 2832fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 2833fcf3ce44SJohn Forte 2834fcf3ce44SJohn Forte /* 2835fcf3ce44SJohn Forte * Step 3. Wait on cv_wait for completion routine 2836fcf3ce44SJohn Forte */ 2837fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2838fcf3ce44SJohn Forte while (icmdp->cmd_completed == B_FALSE) { 2839fcf3ce44SJohn Forte cv_wait(&icmdp->cmd_completion, &icmdp->cmd_mutex); 2840fcf3ce44SJohn Forte } 2841fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2842fcf3ce44SJohn Forte 2843fcf3ce44SJohn Forte /* copy rval */ 2844fcf3ce44SJohn Forte rval = icmdp->cmd_result; 2845fcf3ce44SJohn Forte 2846fcf3ce44SJohn Forte ucmdp->uscsi_resid = pkt->pkt_resid; 2847fcf3ce44SJohn Forte 2848fcf3ce44SJohn Forte /* update scsi status */ 2849fcf3ce44SJohn Forte arqstat = (struct scsi_arq_status *)pkt->pkt_scbp; 2850fcf3ce44SJohn Forte ucmdp->uscsi_status = ((char *)&arqstat->sts_status)[0]; 2851fcf3ce44SJohn Forte 2852fcf3ce44SJohn Forte /* copy request sense buffers if caller gave space */ 2853fcf3ce44SJohn Forte if ((ucmdp->uscsi_rqlen > 0) && 2854fcf3ce44SJohn Forte (ucmdp->uscsi_rqbuf != NULL)) { 2855fcf3ce44SJohn Forte bcopy(arqstat, ucmdp->uscsi_rqbuf, 2856fcf3ce44SJohn Forte MIN(sizeof (struct scsi_arq_status), rqlen)); 2857fcf3ce44SJohn Forte } 2858fcf3ce44SJohn Forte 2859fcf3ce44SJohn Forte /* clean up */ 2860fcf3ce44SJohn Forte iscsi_cmd_free(icmdp); 2861fcf3ce44SJohn Forte kmem_free(pkt->pkt_cdbp, ucmdp->uscsi_cdblen); 2862fcf3ce44SJohn Forte kmem_free(pkt->pkt_scbp, rqlen); 2863fcf3ce44SJohn Forte kmem_free(pkt, sizeof (struct scsi_pkt)); 2864fcf3ce44SJohn Forte kmem_free(bp, sizeof (struct buf)); 2865fcf3ce44SJohn Forte 2866fcf3ce44SJohn Forte return (rval); 2867fcf3ce44SJohn Forte } 2868fcf3ce44SJohn Forte 2869fcf3ce44SJohn Forte 2870fcf3ce44SJohn Forte /* 2871fcf3ce44SJohn Forte * iscsi_handle_passthru_callback - 2872fcf3ce44SJohn Forte * 2873fcf3ce44SJohn Forte */ 2874fcf3ce44SJohn Forte static void 2875fcf3ce44SJohn Forte iscsi_handle_passthru_callback(struct scsi_pkt *pkt) 2876fcf3ce44SJohn Forte { 2877fcf3ce44SJohn Forte iscsi_cmd_t *icmdp = NULL; 2878fcf3ce44SJohn Forte 2879fcf3ce44SJohn Forte ASSERT(pkt != NULL); 2880fcf3ce44SJohn Forte icmdp = (iscsi_cmd_t *)pkt->pkt_ha_private; 2881fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2882fcf3ce44SJohn Forte 2883fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2884fcf3ce44SJohn Forte icmdp->cmd_completed = B_TRUE; 2885fcf3ce44SJohn Forte icmdp->cmd_result = ISCSI_STATUS_SUCCESS; 2886fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion); 2887fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2888fcf3ce44SJohn Forte 2889fcf3ce44SJohn Forte } 2890fcf3ce44SJohn Forte 2891fcf3ce44SJohn Forte /* 2892fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2893fcf3ce44SJohn Forte * | Beginning of completion routines | 2894fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 2895fcf3ce44SJohn Forte */ 2896fcf3ce44SJohn Forte 2897fcf3ce44SJohn Forte /* 2898fcf3ce44SJohn Forte * iscsi_ic_thread - 2899fcf3ce44SJohn Forte */ 2900fcf3ce44SJohn Forte void 2901fcf3ce44SJohn Forte iscsi_ic_thread(iscsi_thread_t *thread, void *arg) 2902fcf3ce44SJohn Forte { 2903fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg; 2904fcf3ce44SJohn Forte int ret; 2905fcf3ce44SJohn Forte iscsi_queue_t q; 2906fcf3ce44SJohn Forte iscsi_cmd_t *icmdp; 2907fcf3ce44SJohn Forte iscsi_cmd_t *next_icmdp; 2908fcf3ce44SJohn Forte 2909fcf3ce44SJohn Forte ASSERT(isp != NULL); 2910fcf3ce44SJohn Forte ASSERT(thread != NULL); 2911fcf3ce44SJohn Forte ASSERT(thread->signature == SIG_ISCSI_THREAD); 2912fcf3ce44SJohn Forte 2913fcf3ce44SJohn Forte for (;;) { 2914fcf3ce44SJohn Forte 2915fcf3ce44SJohn Forte /* 2916fcf3ce44SJohn Forte * We wait till iodone or somebody else wakes us up. 2917fcf3ce44SJohn Forte */ 2918fcf3ce44SJohn Forte ret = iscsi_thread_wait(thread, -1); 2919fcf3ce44SJohn Forte 2920fcf3ce44SJohn Forte /* 2921fcf3ce44SJohn Forte * The value should never be negative since we never timeout. 2922fcf3ce44SJohn Forte */ 2923fcf3ce44SJohn Forte ASSERT(ret >= 0); 2924fcf3ce44SJohn Forte 2925fcf3ce44SJohn Forte q.count = 0; 2926fcf3ce44SJohn Forte q.head = NULL; 2927fcf3ce44SJohn Forte q.tail = NULL; 2928fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_completion.mutex); 2929fcf3ce44SJohn Forte icmdp = isp->sess_queue_completion.head; 2930fcf3ce44SJohn Forte while (icmdp != NULL) { 2931fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next; 2932fcf3ce44SJohn Forte mutex_enter(&icmdp->cmd_mutex); 2933fcf3ce44SJohn Forte /* 2934fcf3ce44SJohn Forte * check if the associated r2t/abort has finished 2935fcf3ce44SJohn Forte * yet. If not, don't complete the command. 2936fcf3ce44SJohn Forte */ 2937fcf3ce44SJohn Forte if ((icmdp->cmd_un.scsi.r2t_icmdp == NULL) && 2938fcf3ce44SJohn Forte (icmdp->cmd_un.scsi.abort_icmdp == NULL)) { 2939fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2940fcf3ce44SJohn Forte (void) iscsi_dequeue_cmd(&isp-> 2941fcf3ce44SJohn Forte sess_queue_completion.head, 2942fcf3ce44SJohn Forte &isp->sess_queue_completion.tail, 2943fcf3ce44SJohn Forte icmdp); 2944fcf3ce44SJohn Forte --isp->sess_queue_completion.count; 2945fcf3ce44SJohn Forte iscsi_enqueue_cmd_head(&q.head, 2946fcf3ce44SJohn Forte &q.tail, icmdp); 2947fcf3ce44SJohn Forte } else 2948fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 2949fcf3ce44SJohn Forte icmdp = next_icmdp; 2950fcf3ce44SJohn Forte } 2951fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_completion.mutex); 2952fcf3ce44SJohn Forte icmdp = q.head; 2953fcf3ce44SJohn Forte while (icmdp != NULL) { 2954fcf3ce44SJohn Forte next_icmdp = icmdp->cmd_next; 2955fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E8, isp); 2956fcf3ce44SJohn Forte icmdp = next_icmdp; 2957fcf3ce44SJohn Forte } 2958fcf3ce44SJohn Forte 2959fcf3ce44SJohn Forte if (ret > 0) 2960fcf3ce44SJohn Forte /* Somebody woke us up to work */ 2961fcf3ce44SJohn Forte continue; 2962fcf3ce44SJohn Forte else 2963fcf3ce44SJohn Forte /* 2964fcf3ce44SJohn Forte * Somebody woke us up to kill ourselves. We will 2965fcf3ce44SJohn Forte * make sure, however that the completion queue is 2966fcf3ce44SJohn Forte * empty before leaving. After we've done that it 2967fcf3ce44SJohn Forte * is the originator of the signal that has to make 2968fcf3ce44SJohn Forte * sure no other SCSI command is posted. 2969fcf3ce44SJohn Forte */ 2970fcf3ce44SJohn Forte break; 2971fcf3ce44SJohn Forte } 2972fcf3ce44SJohn Forte 2973fcf3ce44SJohn Forte } 2974fcf3ce44SJohn Forte 2975fcf3ce44SJohn Forte /* 2976fcf3ce44SJohn Forte * iscsi_iodone - 2977fcf3ce44SJohn Forte * 2978fcf3ce44SJohn Forte */ 2979fcf3ce44SJohn Forte void 2980fcf3ce44SJohn Forte iscsi_iodone(iscsi_sess_t *isp, iscsi_cmd_t *icmdp) 2981fcf3ce44SJohn Forte { 2982fcf3ce44SJohn Forte struct scsi_pkt *pkt = NULL; 2983fcf3ce44SJohn Forte struct buf *bp = icmdp->cmd_un.scsi.bp; 2984fcf3ce44SJohn Forte 2985fcf3ce44SJohn Forte ASSERT(isp != NULL); 2986fcf3ce44SJohn Forte ASSERT(icmdp != NULL); 2987fcf3ce44SJohn Forte pkt = icmdp->cmd_un.scsi.pkt; 2988fcf3ce44SJohn Forte ASSERT(pkt != NULL); 2989fcf3ce44SJohn Forte 2990fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL); 2991fcf3ce44SJohn Forte ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL); 2992fcf3ce44SJohn Forte if (pkt->pkt_reason == CMD_CMPLT) { 2993fcf3ce44SJohn Forte if (bp) { 2994fcf3ce44SJohn Forte if (bp->b_flags & B_READ) { 2995fcf3ce44SJohn Forte KSTAT_SESS_RX_IO_DONE(isp, bp->b_bcount); 2996fcf3ce44SJohn Forte } else { 2997fcf3ce44SJohn Forte KSTAT_SESS_TX_IO_DONE(isp, bp->b_bcount); 2998fcf3ce44SJohn Forte } 2999fcf3ce44SJohn Forte } 3000fcf3ce44SJohn Forte } 3001fcf3ce44SJohn Forte 3002fcf3ce44SJohn Forte if (pkt->pkt_flags & FLAG_NOINTR) { 3003fcf3ce44SJohn Forte cv_broadcast(&icmdp->cmd_completion); 3004fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3005fcf3ce44SJohn Forte } else { 3006fcf3ce44SJohn Forte /* 3007fcf3ce44SJohn Forte * Release mutex. As soon as callback is 3008fcf3ce44SJohn Forte * issued the caller may destroy the command. 3009fcf3ce44SJohn Forte */ 3010fcf3ce44SJohn Forte mutex_exit(&icmdp->cmd_mutex); 3011fcf3ce44SJohn Forte /* 3012fcf3ce44SJohn Forte * We can't just directly call the pk_comp routine. In 3013fcf3ce44SJohn Forte * many error cases the target driver will use the calling 3014fcf3ce44SJohn Forte * thread to re-drive error handling (reset, retries...) 3015fcf3ce44SJohn Forte * back into the hba driver (iscsi). If the target redrives 3016fcf3ce44SJohn Forte * a reset back into the iscsi driver off this thead we have 3017fcf3ce44SJohn Forte * a chance of deadlocking. So instead use the io completion 3018fcf3ce44SJohn Forte * thread. 3019fcf3ce44SJohn Forte */ 3020fcf3ce44SJohn Forte (*icmdp->cmd_un.scsi.pkt->pkt_comp)(icmdp->cmd_un.scsi.pkt); 3021fcf3ce44SJohn Forte } 3022fcf3ce44SJohn Forte } 3023fcf3ce44SJohn Forte 3024fcf3ce44SJohn Forte /* 3025fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3026fcf3ce44SJohn Forte * | End of completion routines | 3027fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3028fcf3ce44SJohn Forte */ 3029fcf3ce44SJohn Forte 3030fcf3ce44SJohn Forte /* 3031fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3032fcf3ce44SJohn Forte * | Beginning of watchdog routines | 3033fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3034fcf3ce44SJohn Forte */ 3035fcf3ce44SJohn Forte 3036fcf3ce44SJohn Forte /* 3037fcf3ce44SJohn Forte * iscsi_watchdog_thread - 3038fcf3ce44SJohn Forte * 3039fcf3ce44SJohn Forte */ 3040fcf3ce44SJohn Forte void 3041fcf3ce44SJohn Forte iscsi_wd_thread(iscsi_thread_t *thread, void *arg) 3042fcf3ce44SJohn Forte { 3043fcf3ce44SJohn Forte iscsi_sess_t *isp = (iscsi_sess_t *)arg; 3044fcf3ce44SJohn Forte int rc = 1; 3045fcf3ce44SJohn Forte 3046fcf3ce44SJohn Forte ASSERT(isp != NULL); 3047fcf3ce44SJohn Forte 3048fcf3ce44SJohn Forte while (rc != NULL) { 3049fcf3ce44SJohn Forte 3050fcf3ce44SJohn Forte iscsi_timeout_checks(isp); 3051fcf3ce44SJohn Forte iscsi_nop_checks(isp); 3052fcf3ce44SJohn Forte 3053fcf3ce44SJohn Forte rc = iscsi_thread_wait(thread, SEC_TO_TICK(1)); 3054fcf3ce44SJohn Forte } 3055fcf3ce44SJohn Forte } 3056fcf3ce44SJohn Forte 3057fcf3ce44SJohn Forte /* 3058fcf3ce44SJohn Forte * iscsi_timeout_checks - 3059fcf3ce44SJohn Forte * 3060fcf3ce44SJohn Forte */ 3061fcf3ce44SJohn Forte static void 3062fcf3ce44SJohn Forte iscsi_timeout_checks(iscsi_sess_t *isp) 3063fcf3ce44SJohn Forte { 3064fcf3ce44SJohn Forte clock_t now = ddi_get_lbolt(); 3065fcf3ce44SJohn Forte iscsi_cmd_t *icmdp, *nicmdp; 3066fcf3ce44SJohn Forte iscsi_conn_t *icp; 3067fcf3ce44SJohn Forte 3068fcf3ce44SJohn Forte ASSERT(isp != NULL); 3069fcf3ce44SJohn Forte 3070fcf3ce44SJohn Forte /* PENDING */ 3071fcf3ce44SJohn Forte mutex_enter(&isp->sess_state_mutex); 3072fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3073fcf3ce44SJohn Forte for (icmdp = isp->sess_queue_pending.head; 3074fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) { 3075fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next; 3076fcf3ce44SJohn Forte 3077fcf3ce44SJohn Forte /* Skip entries with no timeout */ 3078fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0) 3079fcf3ce44SJohn Forte continue; 3080fcf3ce44SJohn Forte 3081fcf3ce44SJohn Forte /* 3082fcf3ce44SJohn Forte * Skip pending queue entries for cmd_type values that depend 3083fcf3ce44SJohn Forte * on having an open cmdsn window for successfull transition 3084fcf3ce44SJohn Forte * from pending to the active (i.e. ones that depend on 3085fcf3ce44SJohn Forte * sess_cmdsn .vs. sess_maxcmdsn). For them, the timer starts 3086fcf3ce44SJohn Forte * when they are successfully moved to the active queue by 3087fcf3ce44SJohn Forte * iscsi_cmd_state_pending() code. 3088fcf3ce44SJohn Forte */ 3089d233de7eSJack Meng /* 3090d233de7eSJack Meng * If the cmd is stuck, at least give it a chance 3091d233de7eSJack Meng * to timeout 3092d233de7eSJack Meng */ 3093d233de7eSJack Meng if (((icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) || 3094d233de7eSJack Meng (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT)) && 3095d233de7eSJack Meng !(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_STUCK)) 3096fcf3ce44SJohn Forte continue; 3097fcf3ce44SJohn Forte 3098fcf3ce44SJohn Forte /* Skip if timeout still in the future */ 3099fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout) 3100fcf3ce44SJohn Forte continue; 3101fcf3ce44SJohn Forte 3102fcf3ce44SJohn Forte /* timeout */ 3103fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp); 3104fcf3ce44SJohn Forte } 3105fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3106fcf3ce44SJohn Forte mutex_exit(&isp->sess_state_mutex); 3107fcf3ce44SJohn Forte 3108fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 3109fcf3ce44SJohn Forte icp = isp->sess_conn_list; 3110fcf3ce44SJohn Forte while (icp != NULL) { 3111fcf3ce44SJohn Forte 3112fcf3ce44SJohn Forte /* ACTIVE */ 3113fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 3114fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3115fcf3ce44SJohn Forte mutex_enter(&icp->conn_queue_active.mutex); 3116fcf3ce44SJohn Forte for (icmdp = icp->conn_queue_active.head; 3117fcf3ce44SJohn Forte icmdp; icmdp = nicmdp) { 3118fcf3ce44SJohn Forte nicmdp = icmdp->cmd_next; 3119fcf3ce44SJohn Forte 3120fcf3ce44SJohn Forte /* Skip entries with no timeout */ 3121fcf3ce44SJohn Forte if (icmdp->cmd_lbolt_timeout == 0) 3122fcf3ce44SJohn Forte continue; 3123fcf3ce44SJohn Forte 3124fcf3ce44SJohn Forte /* Skip if command is not active */ 3125fcf3ce44SJohn Forte if (icmdp->cmd_state != ISCSI_CMD_STATE_ACTIVE) 3126fcf3ce44SJohn Forte continue; 3127fcf3ce44SJohn Forte 3128fcf3ce44SJohn Forte /* Skip if timeout still in the future */ 3129fcf3ce44SJohn Forte if (now <= icmdp->cmd_lbolt_timeout) 3130fcf3ce44SJohn Forte continue; 3131fcf3ce44SJohn Forte 3132fcf3ce44SJohn Forte /* timeout */ 3133fcf3ce44SJohn Forte iscsi_cmd_state_machine(icmdp, ISCSI_CMD_EVENT_E6, isp); 3134fcf3ce44SJohn Forte } 3135fcf3ce44SJohn Forte mutex_exit(&icp->conn_queue_active.mutex); 3136fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3137fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 3138fcf3ce44SJohn Forte 3139fcf3ce44SJohn Forte icp = icp->conn_next; 3140fcf3ce44SJohn Forte } 3141fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 3142fcf3ce44SJohn Forte } 3143fcf3ce44SJohn Forte 3144fcf3ce44SJohn Forte /* 3145fcf3ce44SJohn Forte * iscsi_nop_checks - sends a NOP on idle connections 3146fcf3ce44SJohn Forte * 3147fcf3ce44SJohn Forte * This function walks the connections on a session and 3148fcf3ce44SJohn Forte * issues NOPs on those connections that are in FULL 3149fcf3ce44SJohn Forte * FEATURE mode and have not received data for the 3150fcf3ce44SJohn Forte * time period specified by iscsi_nop_delay (global). 3151fcf3ce44SJohn Forte */ 3152fcf3ce44SJohn Forte static void 3153fcf3ce44SJohn Forte iscsi_nop_checks(iscsi_sess_t *isp) 3154fcf3ce44SJohn Forte { 3155fcf3ce44SJohn Forte iscsi_conn_t *icp; 3156fcf3ce44SJohn Forte 3157fcf3ce44SJohn Forte ASSERT(isp != NULL); 3158fcf3ce44SJohn Forte 3159fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) { 3160fcf3ce44SJohn Forte return; 3161fcf3ce44SJohn Forte } 3162fcf3ce44SJohn Forte 3163fcf3ce44SJohn Forte rw_enter(&isp->sess_conn_list_rwlock, RW_READER); 3164fcf3ce44SJohn Forte icp = isp->sess_conn_act; 3165fcf3ce44SJohn Forte if (icp != NULL) { 3166fcf3ce44SJohn Forte 3167fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex); 3168fcf3ce44SJohn Forte if ((ISCSI_CONN_STATE_FULL_FEATURE(icp->conn_state)) && 3169fcf3ce44SJohn Forte (ddi_get_lbolt() > isp->sess_conn_act->conn_rx_lbolt + 3170fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay)) && (ddi_get_lbolt() > 3171fcf3ce44SJohn Forte isp->sess_conn_act->conn_nop_lbolt + 3172fcf3ce44SJohn Forte SEC_TO_TICK(iscsi_nop_delay))) { 3173fcf3ce44SJohn Forte 3174fcf3ce44SJohn Forte /* 3175fcf3ce44SJohn Forte * We haven't received anything from the 3176fcf3ce44SJohn Forte * target is a defined period of time, 3177fcf3ce44SJohn Forte * send NOP to see if the target is alive. 3178fcf3ce44SJohn Forte */ 3179fcf3ce44SJohn Forte mutex_enter(&isp->sess_queue_pending.mutex); 3180fcf3ce44SJohn Forte iscsi_handle_nop(isp->sess_conn_act, 3181fcf3ce44SJohn Forte 0, ISCSI_RSVD_TASK_TAG); 3182fcf3ce44SJohn Forte mutex_exit(&isp->sess_queue_pending.mutex); 3183fcf3ce44SJohn Forte } 3184fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex); 3185fcf3ce44SJohn Forte 3186fcf3ce44SJohn Forte icp = icp->conn_next; 3187fcf3ce44SJohn Forte } 3188fcf3ce44SJohn Forte rw_exit(&isp->sess_conn_list_rwlock); 3189fcf3ce44SJohn Forte } 3190fcf3ce44SJohn Forte 3191fcf3ce44SJohn Forte /* 3192fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3193fcf3ce44SJohn Forte * | End of wd routines | 3194fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 3195fcf3ce44SJohn Forte */ 3196