Home | History | Annotate | Download | only in iscsitgtd
      1  2314    mcneal /*
      2  2314    mcneal  * CDDL HEADER START
      3  2314    mcneal  *
      4  2314    mcneal  * The contents of this file are subject to the terms of the
      5  2314    mcneal  * Common Development and Distribution License (the "License").
      6  2314    mcneal  * You may not use this file except in compliance with the License.
      7  2314    mcneal  *
      8  2314    mcneal  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  2314    mcneal  * or http://www.opensolaris.org/os/licensing.
     10  2314    mcneal  * See the License for the specific language governing permissions
     11  2314    mcneal  * and limitations under the License.
     12  2314    mcneal  *
     13  2314    mcneal  * When distributing Covered Code, include this CDDL HEADER in each
     14  2314    mcneal  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  2314    mcneal  * If applicable, add the following below this CDDL HEADER, with the
     16  2314    mcneal  * fields enclosed by brackets "[]" replaced with your own identifying
     17  2314    mcneal  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  2314    mcneal  *
     19  2314    mcneal  * CDDL HEADER END
     20  2314    mcneal  */
     21  2314    mcneal 
     22  2314    mcneal /*
     23  6086  ts143224  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  2314    mcneal  * Use is subject to license terms.
     25  2314    mcneal  */
     26  2314    mcneal 
     27  2314    mcneal /*
     28  2314    mcneal  * This file contains methods to handle the iSCSI Full Feature Phase aspects
     29  2314    mcneal  * of the protocol.
     30  2314    mcneal  */
     31  2314    mcneal 
     32  2314    mcneal #include <unistd.h>
     33  2314    mcneal #include <poll.h>
     34  2314    mcneal #include <strings.h>
     35  2314    mcneal #include <stdlib.h>
     36  2314    mcneal #include <sys/types.h>
     37  2314    mcneal #include <assert.h>
     38  2314    mcneal #include <stdio.h>
     39  2314    mcneal #include <errno.h>
     40  2314    mcneal #include <utility.h>
     41  2314    mcneal #include <netinet/in.h>
     42  2314    mcneal #include <inttypes.h>
     43  3022    mcneal #include <sys/socket.h>
     44  2314    mcneal #include <sys/iscsi_protocol.h>
     45  2314    mcneal 
     46  4568       ahl #include <arpa/inet.h>
     47  4568       ahl 
     48  2314    mcneal #include "iscsi_ffp.h"
     49  2314    mcneal #include "iscsi_cmd.h"
     50  2314    mcneal #include "t10_spc.h"
     51  2314    mcneal #include "utility.h"
     52  4568       ahl #include "iscsi_provider_impl.h"
     53  2314    mcneal 
     54  2314    mcneal static Boolean_t handle_text_msg(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     55  2314    mcneal static Boolean_t handle_logout_msg(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     56  2314    mcneal static Boolean_t handle_scsi_cmd(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     57  2314    mcneal static Boolean_t handle_noop_cmd(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     58  2314    mcneal static Boolean_t handle_scsi_data(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     59  2314    mcneal static Boolean_t handle_task_mgt(iscsi_conn_t *, iscsi_hdr_t *, char *, int);
     60  2314    mcneal static Boolean_t dataout_delayed(iscsi_cmd_t *cmd, msg_type_t type);
     61  2314    mcneal void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer);
     62  2314    mcneal 
     63  2314    mcneal Boolean_t
     64  2314    mcneal iscsi_full_feature(iscsi_conn_t *c)
     65  2314    mcneal {
     66  2314    mcneal 	iscsi_hdr_t	h;
     67  2314    mcneal 	Boolean_t	rval		= False;
     68  4568       ahl 	char		debug[128];
     69  4568       ahl 	char		*ahs		= NULL;
     70  4568       ahl 	int		cc;
     71  4568       ahl 	int		ahslen;
     72  2314    mcneal 
     73  3022    mcneal 	if ((cc = recv(c->c_fd, &h, sizeof (h), MSG_WAITALL)) != sizeof (h)) {
     74  2314    mcneal 		if (errno == ECONNRESET) {
     75  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
     76  6913  ts143224 			    "CON%x  full_feature -- initiator reset socket\n",
     77  2314    mcneal 			    c->c_num);
     78  2314    mcneal 		} else {
     79  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
     80  6913  ts143224 			    "CON%x full_feature(got-%d, expect-%d), errno=%d\n",
     81  2314    mcneal 			    c->c_num, cc, sizeof (h), errno);
     82  2314    mcneal 		}
     83  2314    mcneal 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
     84  2314    mcneal 		conn_state(c, T8);
     85  2314    mcneal 		return (False);
     86  2314    mcneal 	}
     87  2314    mcneal 
     88  2314    mcneal 	/*
     89  2314    mcneal 	 * Look to see if there's an Additional Header Segment available.
     90  2314    mcneal 	 * If so, read it in.
     91  2314    mcneal 	 */
     92  2314    mcneal 	if ((ahslen = (h.hlength * sizeof (uint32_t))) != 0) {
     93  2314    mcneal 		if ((ahs = malloc(ahslen)) == NULL)
     94  2314    mcneal 			return (False);
     95  3022    mcneal 		if (recv(c->c_fd, ahs, ahslen, MSG_WAITALL) != ahslen) {
     96  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
     97  2314    mcneal 			    "CON%x  Failed to read in AHS", c->c_num);
     98  2314    mcneal 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
     99  6086  ts143224 			free(ahs);
    100  2314    mcneal 			return (False);
    101  2314    mcneal 		}
    102  2314    mcneal 	}
    103  2314    mcneal 
    104  7417       Tim 	(void) pthread_mutex_lock(&c->c_state_mutex);
    105  7520       Tim 	if (c->c_state != S5_LOGGED_IN && c->c_state != S7_LOGOUT_REQUESTED) {
    106  7417       Tim 		(void) snprintf(debug, sizeof (debug),
    107  7417       Tim 		    "CON%x  full_feature -- not in S5_LOGGED_IN state\n",
    108  7417       Tim 		    c->c_num);
    109  7417       Tim 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    110  7417       Tim 		if (ahs != NULL)
    111  7417       Tim 			free(ahs);
    112  7417       Tim 		(void) pthread_mutex_unlock(&c->c_state_mutex);
    113  7417       Tim 		return (False);
    114  7417       Tim 	}
    115  7417       Tim 	(void) pthread_mutex_unlock(&c->c_state_mutex);
    116  7417       Tim 
    117  7417       Tim 	if (c->c_header_digest == True) {
    118  4568       ahl 		uint32_t	crc_actual;
    119  4568       ahl 		uint32_t	crc_calculated;
    120  2314    mcneal 
    121  3022    mcneal 		(void) recv(c->c_fd, (char *)&crc_actual,
    122  3022    mcneal 		    sizeof (crc_actual), MSG_WAITALL);
    123  2314    mcneal 		crc_calculated = iscsi_crc32c((void *)&h, sizeof (h));
    124  2314    mcneal 		if (ahslen)
    125  2314    mcneal 			crc_calculated = iscsi_crc32c_continued(ahs,
    126  2314    mcneal 			    ahslen, crc_calculated);
    127  2314    mcneal 		if (crc_actual != crc_calculated) {
    128  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
    129  2314    mcneal 			    "CON%x  CRC error: actual 0x%x v. calc 0x%x",
    130  2314    mcneal 			    c->c_num, crc_actual, crc_calculated);
    131  2314    mcneal 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    132  6086  ts143224 			if (ahs != NULL)
    133  6086  ts143224 				free(ahs);
    134  2314    mcneal 			return (False);
    135  2314    mcneal 		}
    136  2314    mcneal 	}
    137  2314    mcneal 
    138  2314    mcneal 	if (c->c_sess->s_type == SessionDiscovery) {
    139  2314    mcneal 		switch (h.opcode & ISCSI_OPCODE_MASK) {
    140  2314    mcneal 		default:
    141  2314    mcneal 			/*
    142  2314    mcneal 			 * Need to handle the error case here.
    143  2314    mcneal 			 */
    144  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
    145  2314    mcneal 			    "CON%x  Wrong opcode for Discovery, %d",
    146  2314    mcneal 			    c->c_num, h.opcode & ISCSI_OPCODE_MASK);
    147  2314    mcneal 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    148  2314    mcneal 			rval = False;
    149  2314    mcneal 			break;
    150  2314    mcneal 
    151  2314    mcneal 		case ISCSI_OP_LOGOUT_CMD:
    152  2314    mcneal 			/*
    153  2314    mcneal 			 * This will transition from S5_LOGGED_IN
    154  2314    mcneal 			 * to S6_IN_LOGOUT to S1_FREE;
    155  2314    mcneal 			 */
    156  2314    mcneal 			rval = handle_logout_msg(c, &h, ahs, ahslen);
    157  2314    mcneal 			break;
    158  2314    mcneal 
    159  2314    mcneal 		case ISCSI_OP_TEXT_CMD:
    160  2314    mcneal 			rval = handle_text_msg(c, &h, ahs, ahslen);
    161  2314    mcneal 			break;
    162  2314    mcneal 		}
    163  2314    mcneal 	} else {
    164  6086  ts143224 		iscsi_cmd_remove(c, ntohl(h.expstatsn));
    165  2314    mcneal 		switch (h.opcode & ISCSI_OPCODE_MASK) {
    166  2314    mcneal 		case ISCSI_OP_NOOP_OUT:
    167  2314    mcneal 			rval = handle_noop_cmd(c, &h, ahs, ahslen);
    168  2314    mcneal 			break;
    169  2314    mcneal 
    170  2314    mcneal 		case ISCSI_OP_SCSI_CMD:
    171  2314    mcneal 			rval = handle_scsi_cmd(c, &h, ahs, ahslen);
    172  2314    mcneal 			break;
    173  2314    mcneal 
    174  2314    mcneal 		case ISCSI_OP_SCSI_TASK_MGT_MSG:
    175  2314    mcneal 			rval = handle_task_mgt(c, &h, ahs, ahslen);
    176  2314    mcneal 			break;
    177  2314    mcneal 
    178  2314    mcneal 		case ISCSI_OP_LOGIN_CMD:
    179  2314    mcneal 			/*
    180  2314    mcneal 			 * This is an illegal state transition. Should
    181  2314    mcneal 			 * we drop the connection?
    182  2314    mcneal 			 */
    183  2314    mcneal 			break;
    184  2314    mcneal 
    185  2314    mcneal 		case ISCSI_OP_TEXT_CMD:
    186  2314    mcneal 			rval = handle_text_msg(c, &h, ahs, ahslen);
    187  2314    mcneal 			break;
    188  2314    mcneal 
    189  2314    mcneal 		case ISCSI_OP_SCSI_DATA:
    190  2314    mcneal 			rval = handle_scsi_data(c, &h, ahs, ahslen);
    191  2314    mcneal 			break;
    192  2314    mcneal 
    193  2314    mcneal 		case ISCSI_OP_LOGOUT_CMD:
    194  2314    mcneal 			/*
    195  2314    mcneal 			 * This will transition from S5_LOGGED_IN
    196  2314    mcneal 			 * to S6_IN_LOGOUT.
    197  2314    mcneal 			 */
    198  2314    mcneal 			rval = handle_logout_msg(c, &h, ahs, ahslen);
    199  2314    mcneal 			break;
    200  2314    mcneal 
    201  2314    mcneal 		case ISCSI_OP_SNACK_CMD:
    202  2314    mcneal 		default:
    203  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
    204  2314    mcneal 			    "CON%x  Opcode: %d not handled",
    205  2314    mcneal 			    c->c_num, h.opcode & ISCSI_OPCODE_MASK);
    206  2314    mcneal 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    207  2314    mcneal 			conn_state(c, T8);
    208  2314    mcneal 			rval = True;
    209  2314    mcneal 			break;
    210  2314    mcneal 		}
    211  2314    mcneal 	}
    212  2314    mcneal 
    213  2314    mcneal 	if (ahs != NULL)
    214  2314    mcneal 		free(ahs);
    215  2314    mcneal 	return (rval);
    216  2314    mcneal }
    217  2314    mcneal 
    218  2314    mcneal /*ARGSUSED*/
    219  2314    mcneal static Boolean_t
    220  2314    mcneal handle_task_mgt(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    221  2314    mcneal {
    222  2314    mcneal 	iscsi_scsi_task_mgt_hdr_t	*hp = (iscsi_scsi_task_mgt_hdr_t *)p;
    223  2314    mcneal 	iscsi_scsi_task_mgt_rsp_hdr_t	*rsp;
    224  2314    mcneal 	iscsi_cmd_t			*cmd;
    225  2314    mcneal 	uint32_t			lun;
    226  2314    mcneal 	Boolean_t			lu_reset	= False;
    227  2314    mcneal 
    228  4568       ahl 	if (spc_decode_lu_addr(&hp->lun[0], 8, &lun) == False)
    229  2314    mcneal 		return (False);
    230  2314    mcneal 
    231  4568       ahl 	if (ISCSI_TASK_COMMAND_ENABLED()) {
    232  4568       ahl 		uiscsiproto_t info;
    233  4568       ahl 
    234  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    235  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    236  4568       ahl 
    237  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    238  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    239  4568       ahl 		info.uip_lun = lun;
    240  4568       ahl 
    241  4568       ahl 		info.uip_itt = hp->itt;
    242  4568       ahl 		info.uip_ttt = hp->itt;
    243  4568       ahl 
    244  4568       ahl 		info.uip_cmdsn = ntohl(hp->cmdsn);
    245  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    246  4568       ahl 		info.uip_datasn = ntohl(hp->expdatasn);
    247  4568       ahl 
    248  4568       ahl 		info.uip_datalen = ntoh24(hp->dlength);
    249  4568       ahl 		info.uip_flags = 0;
    250  4568       ahl 
    251  4568       ahl 		ISCSI_TASK_COMMAND(&info);
    252  4568       ahl 	}
    253  4568       ahl 
    254  4568       ahl 	if ((rsp = calloc(1, sizeof (*rsp))) == NULL)
    255  2314    mcneal 		return (False);
    256  2314    mcneal 
    257  2314    mcneal 	rsp->opcode	= ISCSI_OP_SCSI_TASK_MGT_RSP;
    258  2314    mcneal 	rsp->flags	= ISCSI_FLAG_FINAL;
    259  2314    mcneal 	rsp->itt	= hp->itt;
    260  4822  ts143224 
    261  4822  ts143224 	(void) pthread_mutex_lock(&c->c_mutex);
    262  4822  ts143224 	rsp->statsn	= htonl(c->c_statsn++);
    263  4822  ts143224 	(void) pthread_mutex_unlock(&c->c_mutex);
    264  2314    mcneal 
    265  2314    mcneal 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    266  2314    mcneal 	if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn)
    267  2314    mcneal 		c->c_sess->s_seencmdsn = ntohl(hp->cmdsn);
    268  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    269  2314    mcneal 
    270  2314    mcneal 	queue_prt(c->c_mgmtq, Q_CONN_NONIO,
    271  3077    mcneal 	    "CON%x  PDU(Task Mgt): %s, cmdsn 0x%x\n",
    272  2314    mcneal 	    c->c_num,
    273  2314    mcneal 	    task_to_str(hp->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK),
    274  2314    mcneal 	    ntohl(hp->cmdsn));
    275  2314    mcneal 
    276  2314    mcneal 	switch (hp->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK) {
    277  2314    mcneal 	case ISCSI_TM_FUNC_ABORT_TASK:
    278  2314    mcneal 		queue_prt(c->c_mgmtq, Q_CONN_NONIO,
    279  3077    mcneal 		    "CON%x  Abort ITT 0x%x\n", c->c_num, hp->rtt);
    280  2314    mcneal 		if ((cmd = iscsi_cmd_find(c, hp->rtt, FindITT)) == NULL) {
    281  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    282  2314    mcneal 			    "CON%x  Invalid AbortTask rtt 0x%x\n",
    283  2314    mcneal 			    c->c_num, hp->rtt);
    284  2314    mcneal 			rsp->response = SCSI_TCP_TM_RESP_NO_TASK;
    285  2314    mcneal 		} else {
    286  6913  ts143224 			(void) pthread_mutex_lock(&c->c_mutex);
    287  2314    mcneal 			iscsi_cmd_cancel(c, cmd);
    288  6913  ts143224 			(void) pthread_mutex_unlock(&c->c_mutex);
    289  2314    mcneal 			rsp->response = SCSI_TCP_TM_RESP_COMPLETE;
    290  2314    mcneal 		}
    291  2314    mcneal 		break;
    292  2314    mcneal 
    293  2314    mcneal 	case ISCSI_TM_FUNC_ABORT_TASK_SET:
    294  2314    mcneal 		/* ---- This is actually "Function not support" ---- */
    295  2314    mcneal 		rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS;
    296  2314    mcneal 		break;
    297  2314    mcneal 
    298  2314    mcneal 	case ISCSI_TM_FUNC_CLEAR_ACA:
    299  2314    mcneal 		/* ---- This is actually "Function not support" ---- */
    300  2314    mcneal 		rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS;
    301  2314    mcneal 		break;
    302  2314    mcneal 
    303  2314    mcneal 	case ISCSI_TM_FUNC_CLEAR_TASK_SET:
    304  2314    mcneal 		/* ---- This is actually "Function not support" ---- */
    305  2314    mcneal 		rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS;
    306  2314    mcneal 		break;
    307  2314    mcneal 
    308  2314    mcneal 	case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
    309  2314    mcneal 		lu_reset	= True;
    310  2314    mcneal 	/*FALLTHRU*/
    311  2314    mcneal 	case ISCSI_TM_FUNC_TARGET_WARM_RESET:
    312  2314    mcneal 		(void) pthread_mutex_lock(&c->c_mutex);
    313  2314    mcneal 		for (cmd = c->c_cmd_head; cmd; cmd = cmd->c_next) {
    314  2314    mcneal 			if (((hp->function &
    315  2314    mcneal 			    ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK) ==
    316  2314    mcneal 			    ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
    317  2314    mcneal 			    (lun == cmd->c_lun)) {
    318  6913  ts143224 				iscsi_cmd_cancel(c, cmd);
    319  2314    mcneal 
    320  2314    mcneal 			}
    321  2314    mcneal 		}
    322  2314    mcneal 		(void) pthread_mutex_unlock(&c->c_mutex);
    323  2314    mcneal 
    324  2314    mcneal 		if (lu_reset == True)
    325  2314    mcneal 			queue_message_set(c->c_sessq, 0, msg_reset_lu,
    326  2314    mcneal 			    (void *)(uintptr_t)lun);
    327  2314    mcneal 		else
    328  2314    mcneal 			queue_message_set(c->c_sessq, 0, msg_reset_targ, 0);
    329  2314    mcneal 		rsp->response = SCSI_TCP_TM_RESP_COMPLETE;
    330  2314    mcneal 		break;
    331  2314    mcneal 
    332  2314    mcneal 	case ISCSI_TM_FUNC_TARGET_COLD_RESET:
    333  2314    mcneal 		/*
    334  2314    mcneal 		 * According to the specification a cold reset should
    335  2314    mcneal 		 * close *all* connections on the target, not just those
    336  2314    mcneal 		 * for this current session.
    337  2314    mcneal 		 */
    338  2314    mcneal 		queue_message_set(c->c_sessq, 0, msg_reset_targ, (void *)1);
    339  2314    mcneal 		conn_state(c, T8);
    340  2314    mcneal 		break;
    341  2314    mcneal 
    342  2314    mcneal 	case ISCSI_TM_FUNC_TASK_REASSIGN:
    343  2314    mcneal 	default:
    344  2314    mcneal 		/* ---- This is actually "Function not support" ---- */
    345  2314    mcneal 		rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS;
    346  2314    mcneal 		break;
    347  2314    mcneal 	}
    348  2314    mcneal 
    349  2314    mcneal 	(void) pthread_mutex_lock(&c->c_state_mutex);
    350  2314    mcneal 	if (c->c_state == S5_LOGGED_IN)
    351  2314    mcneal 		queue_message_set(c->c_dataq,
    352  2314    mcneal 		    hp->opcode & ISCSI_OP_IMMEDIATE ? Q_HIGH : 0,
    353  2314    mcneal 		    msg_send_pkt, rsp);
    354  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_state_mutex);
    355  2314    mcneal 	return (True);
    356  2314    mcneal }
    357  2314    mcneal 
    358  2314    mcneal /*ARGSUSED*/
    359  2314    mcneal static Boolean_t
    360  2314    mcneal handle_noop_cmd(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    361  2314    mcneal {
    362  2314    mcneal 	iscsi_nop_out_hdr_t	*hp = (iscsi_nop_out_hdr_t *)p;
    363  2314    mcneal 	iscsi_nop_in_hdr_t	*in;
    364  2314    mcneal 
    365  4568       ahl 	if (ISCSI_NOP_RECEIVE_ENABLED()) {
    366  4568       ahl 		uiscsiproto_t info;
    367  4568       ahl 
    368  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    369  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    370  4568       ahl 
    371  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    372  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    373  4568       ahl 		info.uip_lun = 0;
    374  4568       ahl 
    375  4568       ahl 		info.uip_itt = hp->itt;
    376  4568       ahl 		info.uip_ttt = hp->ttt;
    377  4568       ahl 
    378  4568       ahl 		info.uip_cmdsn = ntohl(hp->cmdsn);
    379  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    380  4568       ahl 		info.uip_datasn = 0;
    381  4568       ahl 
    382  4568       ahl 		info.uip_datalen = ntoh24(hp->dlength);
    383  4568       ahl 		info.uip_flags = hp->flags;
    384  4568       ahl 
    385  4568       ahl 		ISCSI_NOP_RECEIVE(&info);
    386  4568       ahl 	}
    387  4568       ahl 
    388  3545    mcneal 	/*
    389  3545    mcneal 	 * Just an answer to our ping
    390  3545    mcneal 	 */
    391  3545    mcneal 	if (hp->ttt != ISCSI_RSVD_TASK_TAG)
    392  3545    mcneal 		return (True);
    393  3545    mcneal 
    394  4568       ahl 	if ((in = calloc(1, sizeof (*in))) == NULL) {
    395  2314    mcneal 		queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    396  4568       ahl 		    "CON%x  NopIn -- failed to malloc space for header",
    397  2314    mcneal 		    c->c_num);
    398  2314    mcneal 		return (False);
    399  2314    mcneal 	}
    400  2314    mcneal 
    401  2314    mcneal 	in->opcode = ISCSI_OP_NOOP_IN;
    402  2314    mcneal 	in->flags = ISCSI_FLAG_FINAL;
    403  2314    mcneal 	/*
    404  2314    mcneal 	 * Need to handle possible data associated with NOP-Out
    405  2314    mcneal 	 */
    406  2314    mcneal 	bcopy(hp->lun, in->lun, 8);
    407  2314    mcneal 	in->itt		= hp->itt;
    408  2314    mcneal 	in->ttt		= ISCSI_RSVD_TASK_TAG;
    409  2314    mcneal 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    410  2314    mcneal 	if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn)
    411  2314    mcneal 		c->c_sess->s_seencmdsn = ntohl(hp->cmdsn);
    412  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    413  2314    mcneal 
    414  2314    mcneal 	(void) pthread_mutex_lock(&c->c_state_mutex);
    415  2314    mcneal 	if (c->c_state == S5_LOGGED_IN)
    416  2314    mcneal 		queue_message_set(c->c_dataq,
    417  2314    mcneal 		    hp->opcode & ISCSI_OP_IMMEDIATE ? Q_HIGH : 0,
    418  2314    mcneal 		    msg_send_pkt, in);
    419  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_state_mutex);
    420  2314    mcneal 	return (True);
    421  2314    mcneal }
    422  2314    mcneal 
    423  2314    mcneal /*ARGSUSED*/
    424  2314    mcneal static Boolean_t
    425  2314    mcneal handle_scsi_data(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    426  2314    mcneal {
    427  2314    mcneal 	iscsi_data_hdr_t	*hp = (iscsi_data_hdr_t *)p;
    428  2314    mcneal 	int			dlen = ntoh24(hp->dlength);
    429  2314    mcneal 	iscsi_cmd_t		*cmd;
    430  4568       ahl 
    431  4568       ahl 	if (ISCSI_DATA_RECEIVE_ENABLED()) {
    432  4568       ahl 		uiscsiproto_t info;
    433  4568       ahl 
    434  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    435  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    436  4568       ahl 
    437  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    438  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    439  4568       ahl 		info.uip_lun = 0;
    440  4568       ahl 
    441  4568       ahl 		info.uip_itt = hp->itt;
    442  4568       ahl 		info.uip_ttt = hp->itt;
    443  4568       ahl 
    444  4568       ahl 		info.uip_cmdsn = 0;
    445  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    446  4568       ahl 		info.uip_datasn = ntohl(hp->datasn);
    447  4568       ahl 
    448  4568       ahl 		info.uip_datalen = dlen;
    449  4568       ahl 		info.uip_flags = hp->flags;
    450  4568       ahl 
    451  4568       ahl 		ISCSI_DATA_RECEIVE(&info);
    452  4568       ahl 	}
    453  2314    mcneal 
    454  2314    mcneal 	if ((cmd = iscsi_cmd_find(c, hp->ttt, FindTTT)) == NULL) {
    455  2314    mcneal 		queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    456  3077    mcneal 		    "CON%x  failed to find ttt 0x%x\n", c->c_num, hp->ttt);
    457  2314    mcneal 		/*
    458  2314    mcneal 		 * Need to handle error case.
    459  2314    mcneal 		 */
    460  2314    mcneal 		return (False);
    461  2314    mcneal 	}
    462  2314    mcneal 	cmd->c_opcode = hp->opcode & ISCSI_OPCODE_MASK;
    463  2314    mcneal 
    464  2314    mcneal 	/*
    465  2314    mcneal 	 * assert(cmd->c_lun == hp->lun[1]);
    466  2314    mcneal 	 * Previously this check was done, but is caused a problem with
    467  2314    mcneal 	 * the RedHat initiator. There was a discussion on the IPS alias
    468  2314    mcneal 	 * around this very topic. Even though section 10.7.4 states:
    469  2314    mcneal 	 *    "If the Target Transfer Tag is provided, then the LUN field
    470  2314    mcneal 	 *    MUST hold a valid value and be consistent with whatever was
    471  2314    mcneal 	 *    specified with the command; otherwise, the LUN field is
    472  2314    mcneal 	 *    reserved."
    473  2314    mcneal 	 * Everyone agreed though that for a DataOut command the LUN field
    474  2314    mcneal 	 * wasn't required to be valid because the TTT gives the Target
    475  2314    mcneal 	 * enough information to complete the command.
    476  2314    mcneal 	 */
    477  2314    mcneal 	assert(cmd->c_allegiance == c);
    478  2314    mcneal 	assert(cmd->c_itt == hp->itt);
    479  2314    mcneal 
    480  2314    mcneal 	cmd->c_offset_out	= ntohl(hp->offset);
    481  2314    mcneal 	cmd->c_data_len		= dlen;
    482  2314    mcneal 	(void) pthread_mutex_lock(&c->c_mutex);
    483  2314    mcneal 	(void) pthread_mutex_lock(&c->c_state_mutex);
    484  2314    mcneal 	if (c->c_state == S5_LOGGED_IN) {
    485  3213    mcneal 		if (cmd->c_state != CmdCanceled) {
    486  3077    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T4);
    487  3213    mcneal 		}
    488  2314    mcneal 	}
    489  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_state_mutex);
    490  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_mutex);
    491  2314    mcneal 
    492  2314    mcneal #ifdef FULL_DEBUG
    493  2314    mcneal 	queue_prt(c->c_mgmtq, Q_CONN_IO,
    494  3077    mcneal 	    "CON%x  PDU(DataOut) TTT 0x%x, offset=0x%x, len=0x%x\n",
    495  2314    mcneal 	    c->c_num, cmd->c_ttt, cmd->c_t10_cmd->c_offset, dlen);
    496  2314    mcneal #endif
    497  2314    mcneal 
    498  2314    mcneal 	return (dataout_delayed(cmd, msg_cmd_data_out));
    499  2314    mcneal }
    500  2314    mcneal 
    501  2314    mcneal static Boolean_t
    502  2314    mcneal handle_scsi_cmd(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    503  2314    mcneal {
    504  2314    mcneal 	iscsi_scsi_cmd_hdr_t	*hp	= (iscsi_scsi_cmd_hdr_t *)p;
    505  2314    mcneal 	int			dlen	= ntoh24(hp->dlength);
    506  2314    mcneal 	iscsi_cmd_t		*cmd;
    507  2314    mcneal 
    508  2314    mcneal 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    509  2314    mcneal 	if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn)
    510  2314    mcneal 		c->c_sess->s_seencmdsn = ntohl(hp->cmdsn);
    511  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    512  2314    mcneal 
    513  2314    mcneal 	if ((cmd = iscsi_cmd_alloc(c, hp->opcode & ISCSI_OPCODE_MASK)) == NULL)
    514  2314    mcneal 		return (False);
    515  2314    mcneal 
    516  2314    mcneal 	bcopy(hp->scb, cmd->c_scb_default, sizeof (cmd->c_scb_default));
    517  2314    mcneal 	cmd->c_scb	= cmd->c_scb_default;
    518  2314    mcneal 	cmd->c_scb_len	= sizeof (cmd->c_scb_default);
    519  2314    mcneal 	cmd->c_data_len	= dlen;
    520  2314    mcneal 
    521  2314    mcneal 	if (ahslen) {
    522  2314    mcneal 
    523  2314    mcneal 		/*
    524  2314    mcneal 		 * Additional Header Section ----
    525  2314    mcneal 		 *
    526  2314    mcneal 		 * For Object Storage Devices the SCB is quite large. On
    527  2314    mcneal 		 * the order of 140 bytes which means the data must be
    528  2314    mcneal 		 * found in the AHS.
    529  2314    mcneal 		 */
    530  4568       ahl 		uint16_t	hslen;
    531  4568       ahl 		uint16_t	next_seg;
    532  2314    mcneal 		uint8_t		hstyp;
    533  2314    mcneal 
    534  2314    mcneal 		do {
    535  2314    mcneal 			/*
    536  2314    mcneal 			 * Find this header segment's length and type
    537  2314    mcneal 			 */
    538  2314    mcneal 			bcopy(ahs, &hslen, sizeof (hslen));
    539  2314    mcneal 			hslen = ntohs(hslen);
    540  2314    mcneal 			hstyp = ahs[2];
    541  2314    mcneal 
    542  2314    mcneal 			switch (hstyp) {
    543  2314    mcneal 			/* ---- Extended CDB ---- */
    544  2314    mcneal 			case 1:
    545  2314    mcneal 				/*
    546  2314    mcneal 				 * The hslen accounts for the reserved
    547  2314    mcneal 				 * data byte in the segment. So the first
    548  2314    mcneal 				 * sixteen bytes are in hp->scb with the
    549  2314    mcneal 				 * remainder here. By only adding 15 bytes
    550  2314    mcneal 				 * we allocate the correct amount of space
    551  2314    mcneal 				 */
    552  2314    mcneal 				cmd->c_scb_extended = malloc(hslen + 15);
    553  2314    mcneal 				cmd->c_scb_len = hslen + 15;
    554  2314    mcneal 				if (cmd->c_scb_extended == NULL)
    555  2314    mcneal 					return (False);
    556  2314    mcneal 
    557  2314    mcneal 				/*
    558  2314    mcneal 				 * First 16 bytes of extended SCB are
    559  2314    mcneal 				 * found in the normal location.
    560  2314    mcneal 				 */
    561  2314    mcneal 				bcopy(hp->scb, cmd->c_scb_extended, 16);
    562  2314    mcneal 				bcopy(&ahs[4], &cmd->c_scb_extended[16],
    563  2314    mcneal 				    hslen - 16);
    564  2314    mcneal 				cmd->c_scb = cmd->c_scb_extended;
    565  2314    mcneal 				break;
    566  2314    mcneal 
    567  2314    mcneal 			/* ---- Expected bidirectional read data len ---- */
    568  2314    mcneal 			case 2:
    569  2314    mcneal 				/*
    570  2314    mcneal 				 * We shouldn't need this since we're
    571  2314    mcneal 				 * not prealloc'ing resources. If that should
    572  2314    mcneal 				 * change or the need for error checking
    573  2314    mcneal 				 * here's the spot to locate the data.
    574  2314    mcneal 				 */
    575  2314    mcneal 				break;
    576  2314    mcneal 			}
    577  2314    mcneal 
    578  2314    mcneal 			/*
    579  2314    mcneal 			 * hslen contains the effective length in bytes of
    580  2314    mcneal 			 * segment, excluding type and length (not including
    581  2314    mcneal 			 * padding). Each segment is padded to a 4 byte
    582  2314    mcneal 			 * boundary.
    583  2314    mcneal 			 */
    584  4568       ahl 			next_seg = ((hslen + sizeof (hslen) +
    585  4568       ahl 			    sizeof (hstyp) + 3) & ~3);
    586  4568       ahl 			ahs += next_seg;
    587  4568       ahl 			ahslen -= next_seg;
    588  2314    mcneal 
    589  2314    mcneal 		} while (ahslen);
    590  2314    mcneal 	}
    591  2314    mcneal 
    592  2314    mcneal 	/*
    593  2314    mcneal 	 * XXX Need to handle error case better.
    594  2314    mcneal 	 */
    595  2314    mcneal 	if (spc_decode_lu_addr(&hp->lun[0], sizeof (hp->lun), &cmd->c_lun) ==
    596  2314    mcneal 	    False) {
    597  2314    mcneal 		return (False);
    598  4568       ahl 	}
    599  4568       ahl 
    600  4568       ahl 	if (ISCSI_SCSI_COMMAND_ENABLED()) {
    601  4568       ahl 		uiscsiproto_t info;
    602  4568       ahl 		uiscsicmd_t uc;
    603  4568       ahl 
    604  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    605  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    606  4568       ahl 
    607  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    608  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    609  4568       ahl 		info.uip_lun = cmd->c_lun;
    610  4568       ahl 
    611  4568       ahl 		info.uip_itt = hp->itt;
    612  4568       ahl 		info.uip_ttt = ISCSI_RSVD_TASK_TAG;
    613  4568       ahl 
    614  4568       ahl 		info.uip_cmdsn = ntohl(hp->cmdsn);
    615  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    616  4568       ahl 		info.uip_datasn = 0;
    617  4568       ahl 
    618  4568       ahl 		info.uip_datalen = dlen;
    619  4568       ahl 		info.uip_flags = hp->flags;
    620  4568       ahl 
    621  4568       ahl 		uc.uic_len = cmd->c_scb_len;
    622  4568       ahl 		uc.uic_cdb = cmd->c_scb;
    623  4568       ahl 
    624  4568       ahl 		ISCSI_SCSI_COMMAND(&info, &uc);
    625  2314    mcneal 	}
    626  2314    mcneal 
    627  2314    mcneal 	cmd->c_itt		= hp->itt;
    628  2314    mcneal 	cmd->c_cmdsn		= ntohl(hp->cmdsn);
    629  3452    mcneal 	cmd->c_dlen_expected	= ntohl(hp->data_length);
    630  2314    mcneal 	cmd->c_writeop		= hp->flags & ISCSI_FLAG_CMD_WRITE ?
    631  2314    mcneal 	    True : False;
    632  2314    mcneal 
    633  2314    mcneal #ifdef FULL_DEBUG
    634  2314    mcneal 	queue_prt(c->c_mgmtq, Q_CONN_IO,
    635  3213    mcneal 	    "CON%x  PDU(SCSI Cmd, TA=%d) CmdSN 0x%x ITT 0x%x TTT 0x%x "
    636  3213    mcneal 	    "LUN[%02x] id=%p\n", c->c_num,
    637  3213    mcneal 	    hp->flags & ISCSI_FLAG_CMD_ATTR_MASK, cmd->c_cmdsn, cmd->c_itt,
    638  3213    mcneal 	    cmd->c_ttt, cmd->c_lun, cmd);
    639  2314    mcneal #endif
    640  3213    mcneal 
    641  2314    mcneal 	if (dlen && (hp->flags & ISCSI_FLAG_CMD_WRITE)) {
    642  2314    mcneal 		/*
    643  2314    mcneal 		 * NOTE: This should only occur if ImmediateData==Yes.
    644  2314    mcneal 		 * We can handle this even if the initiator violates
    645  2314    mcneal 		 * the specification so no need to worry. Use the rule
    646  2314    mcneal 		 * of "Be strict in what is sent, but lenient in what
    647  2314    mcneal 		 * is accepted."
    648  2314    mcneal 		 */
    649  2314    mcneal 		return (dataout_delayed(cmd, msg_cmd_send));
    650  2314    mcneal 	} else {
    651  2314    mcneal 		(void) pthread_mutex_lock(&c->c_state_mutex);
    652  2314    mcneal 		if (c->c_state == S5_LOGGED_IN)
    653  2314    mcneal 			queue_message_set(c->c_sessq, 0,
    654  2314    mcneal 			    msg_cmd_send, (void *)cmd);
    655  2314    mcneal 		(void) pthread_mutex_unlock(&c->c_state_mutex);
    656  2314    mcneal 		return (True);
    657  2314    mcneal 	}
    658  2314    mcneal }
    659  2314    mcneal 
    660  2314    mcneal /*
    661  2314    mcneal  * []----
    662  2314    mcneal  * | handle_text_msg -- process incoming test parameters
    663  2314    mcneal  * |
    664  2314    mcneal  * | NOTE: Need to handle continuation packets sent by the initiator.
    665  2314    mcneal  * []----
    666  2314    mcneal  */
    667  2314    mcneal /*ARGSUSED*/
    668  2314    mcneal static Boolean_t
    669  2314    mcneal handle_text_msg(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    670  2314    mcneal {
    671  2314    mcneal 	iscsi_text_rsp_hdr_t	rsp;
    672  2314    mcneal 	iscsi_text_hdr_t	*hp		= (iscsi_text_hdr_t *)p;
    673  2314    mcneal 	char			*text		= NULL;
    674  2314    mcneal 	int			text_length	= 0;
    675  2314    mcneal 	Boolean_t		release_at_end	= False;
    676  4568       ahl 	int			dlen		= ntoh24(hp->dlength);
    677  4568       ahl 
    678  4568       ahl 	if (ISCSI_TEXT_COMMAND_ENABLED()) {
    679  4568       ahl 		uiscsiproto_t info;
    680  4568       ahl 		char nil = '\0';
    681  4568       ahl 
    682  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    683  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    684  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    685  4568       ahl 
    686  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    687  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    688  4568       ahl 		info.uip_target = &nil;
    689  4568       ahl 		info.uip_lun = 0;
    690  4568       ahl 
    691  4568       ahl 		info.uip_itt = hp->itt;
    692  4568       ahl 		info.uip_ttt = hp->ttt;
    693  4568       ahl 
    694  4568       ahl 		info.uip_cmdsn = ntohl(hp->cmdsn);
    695  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    696  4568       ahl 		info.uip_datasn = 0;
    697  4568       ahl 
    698  4568       ahl 		info.uip_datalen = dlen;
    699  4568       ahl 		info.uip_flags = hp->flags;
    700  4568       ahl 
    701  4568       ahl 		ISCSI_TEXT_COMMAND(&info);
    702  4568       ahl 	}
    703  2314    mcneal 
    704  2314    mcneal 	bzero(&rsp, sizeof (rsp));
    705  2314    mcneal 	rsp.opcode	= ISCSI_OP_TEXT_RSP;
    706  2314    mcneal 	rsp.itt		= hp->itt;
    707  2314    mcneal 
    708  3077    mcneal 	queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x  PDU(Text Message)\n",
    709  4568       ahl 	    c->c_num);
    710  2314    mcneal 
    711  2314    mcneal 	/*
    712  2314    mcneal 	 * Need to determine if this incoming text PDU is an initial message
    713  2314    mcneal 	 * or a continuation.
    714  2314    mcneal 	 */
    715  2314    mcneal 	if (hp->ttt == ISCSI_RSVD_TASK_TAG) {
    716  2314    mcneal 
    717  2314    mcneal 		/* ---- Initial text PDU, so parse the incoming data ---- */
    718  4568       ahl 		if (parse_text(c, dlen, &text, &text_length, NULL) == False) {
    719  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    720  3077    mcneal 			    "Failed to parse Text\n");
    721  2314    mcneal 			if (text) {
    722  2314    mcneal 				/*
    723  2314    mcneal 				 * It's possible that we started to create
    724  2314    mcneal 				 * a response, but yet an error occurred.
    725  2314    mcneal 				 * Release the partial text response if that
    726  2314    mcneal 				 * occurred.
    727  2314    mcneal 				 */
    728  2314    mcneal 				free(text);
    729  2314    mcneal 			}
    730  2314    mcneal 			return (False);
    731  2314    mcneal 		}
    732  2314    mcneal 
    733  2314    mcneal 		/*
    734  2314    mcneal 		 * 10.11.4 --
    735  2314    mcneal 		 * When the target receives a Text Request with the Target
    736  2314    mcneal 		 * Transfer Tag set to the reserved value of 0xffffffff, it
    737  2314    mcneal 		 * resets its internal information (resets state) associated
    738  2314    mcneal 		 * with the given Initiator Task Tag (restarts the negotiation).
    739  2314    mcneal 		 */
    740  2314    mcneal 		if (c->c_text_area != NULL)
    741  2314    mcneal 			free(c->c_text_area);
    742  2314    mcneal 
    743  2314    mcneal 		c->c_text_area = text;
    744  2314    mcneal 		if (text_length > c->c_max_recv_data) {
    745  2314    mcneal 
    746  2314    mcneal 			/*
    747  2314    mcneal 			 * Too much data to send at once, break it up into
    748  2314    mcneal 			 * multiple transfers.
    749  2314    mcneal 			 */
    750  2314    mcneal 			rsp.flags	= ISCSI_FLAG_TEXT_CONTINUE;
    751  2314    mcneal 			rsp.ttt		= 1;
    752  2314    mcneal 			c->c_text_len	= text_length;
    753  2314    mcneal 			text_length	= c->c_max_recv_data;
    754  2314    mcneal 			c->c_text_sent	= text_length;
    755  2314    mcneal 		} else {
    756  2314    mcneal 			rsp.flags	= ISCSI_FLAG_FINAL;
    757  2314    mcneal 			rsp.ttt		= ISCSI_RSVD_TASK_TAG;
    758  2314    mcneal 			release_at_end	= True;
    759  2314    mcneal 		}
    760  2314    mcneal 	} else {
    761  2314    mcneal 
    762  2314    mcneal 		/* ---- Continuation of previous text request ---- */
    763  2314    mcneal 		text_length	= c->c_text_len - c->c_text_sent;
    764  2314    mcneal 		text		= c->c_text_area + c->c_text_sent;
    765  2314    mcneal 		if (text_length > c->c_max_recv_data) {
    766  2314    mcneal 			rsp.flags	= ISCSI_FLAG_TEXT_CONTINUE;
    767  2314    mcneal 			rsp.ttt		= 1;
    768  2314    mcneal 			text_length	= c->c_max_recv_data;
    769  2314    mcneal 			c->c_text_sent	+= text_length;
    770  2314    mcneal 		} else {
    771  2314    mcneal 			rsp.flags	= ISCSI_FLAG_FINAL;
    772  2314    mcneal 			rsp.ttt		= ISCSI_RSVD_TASK_TAG;
    773  2314    mcneal 			release_at_end	= True;
    774  2314    mcneal 		}
    775  2314    mcneal 	}
    776  2314    mcneal 
    777  2314    mcneal 	queue_prt(c->c_mgmtq, Q_CONN_NONIO,
    778  3077    mcneal 	    "CON%x  Text PDU: flags=0x%02x, ttt=0x%08x, len=%d\n",
    779  2314    mcneal 	    c->c_num, rsp.flags, rsp.ttt, text_length);
    780  2314    mcneal 
    781  2314    mcneal 	hton24(rsp.dlength, text_length);
    782  2314    mcneal 	(void) pthread_mutex_lock(&c->c_mutex);
    783  2314    mcneal 	rsp.statsn	= htonl(c->c_statsn++);
    784  2314    mcneal 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    785  2314    mcneal 	if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn)
    786  2314    mcneal 		c->c_sess->s_seencmdsn = ntohl(hp->cmdsn);
    787  2314    mcneal 	rsp.maxcmdsn	= htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn);
    788  2314    mcneal 	rsp.expcmdsn	= htonl(c->c_sess->s_seencmdsn + 1);
    789  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    790  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_mutex);
    791  2314    mcneal 
    792  4568       ahl 	if (ISCSI_TEXT_RESPONSE_ENABLED()) {
    793  4568       ahl 		uiscsiproto_t info;
    794  4568       ahl 		char nil = '\0';
    795  4568       ahl 
    796  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    797  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    798  4568       ahl 
    799  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    800  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    801  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    802  4568       ahl 		info.uip_target = &nil;
    803  4568       ahl 		info.uip_lun = 0;
    804  4568       ahl 
    805  4568       ahl 		info.uip_itt = rsp.itt;
    806  4568       ahl 		info.uip_ttt = rsp.ttt;
    807  4568       ahl 
    808  4568       ahl 		info.uip_cmdsn = ntohl(rsp.expcmdsn);
    809  4568       ahl 		info.uip_statsn = ntohl(rsp.statsn);
    810  4568       ahl 		info.uip_datasn = 0;
    811  4568       ahl 
    812  4568       ahl 		info.uip_datalen = text_length;
    813  4568       ahl 		info.uip_flags = rsp.flags;
    814  4568       ahl 
    815  4568       ahl 		ISCSI_TEXT_RESPONSE(&info);
    816  4568       ahl 	}
    817  4568       ahl 
    818  2314    mcneal 	send_iscsi_pkt(c, (iscsi_hdr_t *)&rsp, text);
    819  2314    mcneal 
    820  2314    mcneal 	if (release_at_end == True) {
    821  2314    mcneal 		free(c->c_text_area);
    822  2314    mcneal 		c->c_text_area = NULL;
    823  2314    mcneal 	}
    824  2314    mcneal 	return (True);
    825  2314    mcneal }
    826  2314    mcneal 
    827  2314    mcneal /*ARGSUSED*/
    828  2314    mcneal static Boolean_t
    829  2314    mcneal handle_logout_msg(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen)
    830  2314    mcneal {
    831  2314    mcneal 	iscsi_logout_rsp_hdr_t	*rsp;
    832  2314    mcneal 	iscsi_logout_hdr_t	*hp = (iscsi_logout_hdr_t *)p;
    833  2314    mcneal 	char			debug[80];
    834  2314    mcneal 
    835  4568       ahl 	if (ISCSI_LOGOUT_COMMAND_ENABLED()) {
    836  4568       ahl 		uiscsiproto_t info;
    837  4568       ahl 		char nil = '\0';
    838  2314    mcneal 
    839  4568       ahl 		info.uip_target_addr = &c->c_target_sockaddr;
    840  4568       ahl 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    841  2314    mcneal 
    842  4568       ahl 		info.uip_target = c->c_sess->s_t_name;
    843  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    844  4568       ahl 		info.uip_initiator = c->c_sess->s_i_name;
    845  4568       ahl 		info.uip_target = &nil;
    846  4568       ahl 		info.uip_lun = 0;
    847  2314    mcneal 
    848  4568       ahl 		info.uip_itt = hp->itt;
    849  4568       ahl 		info.uip_ttt = ISCSI_RSVD_TASK_TAG;
    850  2314    mcneal 
    851  4568       ahl 		info.uip_cmdsn = ntohl(hp->cmdsn);
    852  4568       ahl 		info.uip_statsn = ntohl(hp->expstatsn);
    853  4568       ahl 		info.uip_datasn = 0;
    854  2314    mcneal 
    855  4568       ahl 		info.uip_datalen = ntoh24(hp->dlength);
    856  4568       ahl 		info.uip_flags = hp->flags;
    857  2314    mcneal 
    858  4568       ahl 		ISCSI_LOGOUT_COMMAND(&info);
    859  4568       ahl 	}
    860  4568       ahl 
    861  4568       ahl 	if ((rsp = calloc(1, sizeof (*rsp))) == NULL)
    862  2314    mcneal 		return (False);
    863  4568       ahl 
    864  4568       ahl 	(void) snprintf(debug, sizeof (debug),
    865  4568       ahl 	    "CON%x  PDU(Logout Request)", c->c_num);
    866  4568       ahl 	queue_str(c->c_mgmtq, Q_CONN_NONIO, msg_log, debug);
    867  4568       ahl 
    868  4568       ahl 	(void) pthread_mutex_lock(&c->c_mutex);
    869  4568       ahl 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    870  4568       ahl 	if (hp->cmdsn > c->c_sess->s_seencmdsn)
    871  4568       ahl 		c->c_sess->s_seencmdsn = htonl(hp->cmdsn);
    872  4568       ahl 	rsp->expcmdsn = htonl(c->c_sess->s_seencmdsn + 1);
    873  4568       ahl 	rsp->maxcmdsn = htonl(iscsi_cmd_window(c) +
    874  4568       ahl 	    c->c_sess->s_seencmdsn);
    875  4568       ahl 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    876  4568       ahl 	(void) pthread_mutex_unlock(&c->c_mutex);
    877  4568       ahl 
    878  4568       ahl 	rsp->opcode	= ISCSI_OP_LOGOUT_RSP;
    879  4568       ahl 	rsp->flags	= ISCSI_FLAG_FINAL;
    880  4568       ahl 	rsp->itt	= hp->itt;
    881  4568       ahl 	(void) pthread_mutex_lock(&c->c_mutex);
    882  4568       ahl 	rsp->statsn	= htonl(c->c_statsn++);
    883  4568       ahl 	(void) pthread_mutex_unlock(&c->c_mutex);
    884  4568       ahl 
    885  4568       ahl 	c->c_last_pkg	= (iscsi_hdr_t *)rsp;
    886  4568       ahl 
    887  4568       ahl 	/*
    888  4568       ahl 	 * Call the state transition last. This will send out
    889  4568       ahl 	 * an asynchronous message to shutdown the session and STE.
    890  4568       ahl 	 * Once that's complete a shutdown reply will be sent to
    891  4568       ahl 	 * the transmit connection thread. That will cause another
    892  4568       ahl 	 * transition to T13 which expects to send out this logout
    893  4568       ahl 	 * response.
    894  4568       ahl 	 */
    895  4568       ahl 	if (c->c_state == S7_LOGOUT_REQUESTED)
    896  4568       ahl 		conn_state(c, T10);
    897  4568       ahl 	else
    898  4568       ahl 		conn_state(c, T9);
    899  4568       ahl 
    900  4568       ahl 	return (True);
    901  2314    mcneal }
    902  2314    mcneal 
    903  2314    mcneal /*
    904  3077    mcneal  * dataout_delayed -- possibly copy data from initiator
    905  2314    mcneal  *
    906  2314    mcneal  * If DataDigests are enabled copy the data from the socket into a buffer
    907  2314    mcneal  * and perform the CRC check now.
    908  2314    mcneal  *
    909  2314    mcneal  * If MaxConnections==1 don't copy the data now and wait until the STE is
    910  2314    mcneal  * ready to copy the data directly from the socket to it's final location.
    911  2314    mcneal  * This is extremely beneficial when using mmap'd data.
    912  2314    mcneal  * NOTE:
    913  2314    mcneal  *    (1) For this to work we must not use the queues and instead
    914  2314    mcneal  *        call the STE functions directly. If the queues are used
    915  2314    mcneal  *        this routine must pause until STE processes the data to
    916  2314    mcneal  *        prevent this thread from attempting to read data from
    917  2314    mcneal  *        the socket as if it's the next PDU header.
    918  2314    mcneal  *    (2) Currently we don't call STE directly. To prevent a performance
    919  2314    mcneal  *        issue we'll have the code in place to support calling
    920  2314    mcneal  *        STE directly, but any time MaxConnections is greater than 0
    921  2314    mcneal  *        we'll copy the buffer. This will be removed at some future
    922  2314    mcneal  *        point.
    923  2314    mcneal  */
    924  2314    mcneal static Boolean_t
    925  2314    mcneal dataout_delayed(iscsi_cmd_t *cmd, msg_type_t type)
    926  2314    mcneal {
    927  2314    mcneal 	iscsi_conn_t	*c	= cmd->c_allegiance;
    928  4568       ahl 	int		dlen	= cmd->c_data_len;
    929  4568       ahl 	int		cc;
    930  4568       ahl 	uint32_t	crc_calc;
    931  4568       ahl 	uint32_t	crc_actual;
    932  2314    mcneal 	char		pad_buf[ISCSI_PAD_WORD_LEN - 1];
    933  2314    mcneal 	char		pad_len;
    934  2314    mcneal 	char		debug[80];
    935  2314    mcneal 
    936  2314    mcneal 	cmd->c_dataout_cb = dataout_callback;
    937  2314    mcneal 
    938  2314    mcneal 	if (cmd->c_data == NULL) {
    939  2314    mcneal 		if ((cmd->c_data = (char *)malloc(dlen)) == NULL) {
    940  2314    mcneal 			(void) pthread_mutex_lock(&c->c_mutex);
    941  3213    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
    942  2314    mcneal 			iscsi_cmd_free(c, cmd);
    943  2314    mcneal 			(void) pthread_mutex_unlock(&c->c_mutex);
    944  2314    mcneal 			return (False);
    945  2314    mcneal 		}
    946  2314    mcneal 		cmd->c_data_alloc = True;
    947  2314    mcneal 	}
    948  2314    mcneal 
    949  3022    mcneal 	if ((cc = recv(c->c_fd, cmd->c_data, dlen, MSG_WAITALL)) != dlen) {
    950  2314    mcneal 		if (errno == ECONNRESET) {
    951  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    952  2314    mcneal 			    "CON%x  dataout_delayed -- "
    953  3077    mcneal 			    "initiator reset socket\n", c->c_num);
    954  2314    mcneal 		} else {
    955  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    956  3077    mcneal 			    "CON%x  recv(got-%d, expect-%d), errno=%d\n",
    957  3022    mcneal 			    c->c_num, cc, dlen, errno);
    958  2314    mcneal 		}
    959  2314    mcneal 
    960  2314    mcneal 		(void) pthread_mutex_lock(&c->c_mutex);
    961  3213    mcneal 		t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
    962  2314    mcneal 		iscsi_cmd_free(c, cmd);
    963  2314    mcneal 		(void) pthread_mutex_unlock(&c->c_mutex);
    964  2314    mcneal 		conn_state(c, T8);
    965  2314    mcneal 		return (True);
    966  2314    mcneal 	}
    967  2314    mcneal 
    968  2314    mcneal 	pad_len = ((ISCSI_PAD_WORD_LEN -
    969  2314    mcneal 	    (dlen & (ISCSI_PAD_WORD_LEN - 1))) & (ISCSI_PAD_WORD_LEN - 1));
    970  2314    mcneal 
    971  2314    mcneal 	if (pad_len) {
    972  3022    mcneal 		if (recv(c->c_fd, pad_buf, pad_len, MSG_WAITALL) != pad_len) {
    973  2314    mcneal 			if (errno == ECONNRESET) {
    974  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    975  2314    mcneal 				    "CON%x  dataout_delayed -- "
    976  3077    mcneal 				    "initiator reset socket\n", c->c_num);
    977  2314    mcneal 			} else {
    978  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    979  3077    mcneal 				    "CON%x Pad Word read errno=%d\n", c->c_num,
    980  2314    mcneal 				    errno);
    981  2314    mcneal 			}
    982  2314    mcneal 
    983  2314    mcneal 			(void) pthread_mutex_lock(&c->c_mutex);
    984  3213    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
    985  2314    mcneal 			iscsi_cmd_free(c, cmd);
    986  2314    mcneal 			(void) pthread_mutex_unlock(&c->c_mutex);
    987  2314    mcneal 			conn_state(c, T8);
    988  2314    mcneal 			return (True);
    989  2314    mcneal 		}
    990  2314    mcneal 	}
    991  2314    mcneal 
    992  2314    mcneal 	if (c->c_data_digest == True) {
    993  3022    mcneal 		if (recv(c->c_fd, (char *)&crc_actual, sizeof (crc_actual),
    994  3022    mcneal 		    MSG_WAITALL) != sizeof (crc_actual)) {
    995  2314    mcneal 			if (errno == ECONNRESET) {
    996  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
    997  2314    mcneal 				    "CON%x  dataout_delayed -- "
    998  3077    mcneal 				    "initiator reset socket\n", c->c_num);
    999  2314    mcneal 			} else {
   1000  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
   1001  3077    mcneal 				    "CON%x  CRC32 read errno=%d\n", c->c_num,
   1002  2314    mcneal 				    errno);
   1003  2314    mcneal 			}
   1004  2314    mcneal 
   1005  2314    mcneal 			(void) pthread_mutex_lock(&c->c_mutex);
   1006  3213    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
   1007  2314    mcneal 			iscsi_cmd_free(c, cmd);
   1008  2314    mcneal 			(void) pthread_mutex_unlock(&c->c_mutex);
   1009  2314    mcneal 			conn_state(c, T8);
   1010  2314    mcneal 			return (True);
   1011  2314    mcneal 		}
   1012  2314    mcneal 		crc_calc = iscsi_crc32c((void *)cmd->c_data, dlen);
   1013  2314    mcneal 		if (crc_calc != crc_actual) {
   1014  2314    mcneal 
   1015  2314    mcneal 			(void) snprintf(debug, sizeof (debug),
   1016  2314    mcneal 			    "CON%x  CRC Error: actual %x vs. calc 0x%x",
   1017  2314    mcneal 			    c->c_num, crc_actual, crc_calc);
   1018  2314    mcneal 
   1019  2314    mcneal 			/*
   1020  2314    mcneal 			 * NOTE: Need to think about this one some more.
   1021  2314    mcneal 			 * Just because we get a data error doesn't mean
   1022  2314    mcneal 			 * we should drop the connection. Look at the
   1023  2314    mcneal 			 * spec and determine what's the appropriate
   1024  2314    mcneal 			 * error recovery for this issue.
   1025  2314    mcneal 			 */
   1026  2314    mcneal 			(void) pthread_mutex_lock(&c->c_mutex);
   1027  3213    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
   1028  2314    mcneal 			iscsi_cmd_free(c, cmd);
   1029  2314    mcneal 			(void) pthread_mutex_unlock(&c->c_mutex);
   1030  2314    mcneal 			conn_state(c, T8);
   1031  2314    mcneal 			return (True);
   1032  2314    mcneal 		}
   1033  2314    mcneal 	}
   1034  2314    mcneal 
   1035  3452    mcneal 	/*
   1036  3452    mcneal 	 * We'll update the offset with the amount of data that
   1037  3452    mcneal 	 * has been received. During a SCSI response PDU this value
   1038  3452    mcneal 	 * will be used to determine if there's an overrun condition.
   1039  3452    mcneal 	 */
   1040  3452    mcneal 	cmd->c_offset_out += dlen;
   1041  3452    mcneal 
   1042  2314    mcneal 	(void) pthread_mutex_lock(&c->c_mutex);
   1043  2314    mcneal 	(void) pthread_mutex_lock(&c->c_state_mutex);
   1044  2314    mcneal 	if (c->c_state == S5_LOGGED_IN) {
   1045  2314    mcneal 		if ((cmd->c_state == CmdCanceled) &&
   1046  3213    mcneal 		    (type == msg_cmd_data_out))
   1047  3077    mcneal 			t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
   1048  3213    mcneal 		else
   1049  2314    mcneal 			queue_message_set(c->c_sessq, 0, type, (void *)cmd);
   1050  2314    mcneal 	} else if (cmd->c_state == CmdCanceled) {
   1051  3077    mcneal 		t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5);
   1052  2314    mcneal 	}
   1053  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_state_mutex);
   1054  2314    mcneal 	(void) pthread_mutex_unlock(&c->c_mutex);
   1055  2314    mcneal 
   1056  2314    mcneal 	/*
   1057  2314    mcneal 	 * The else case here is if we're calling STE directly and the data
   1058  2314    mcneal 	 * will be read from the socket when STE is ready for it.
   1059  2314    mcneal 	 */
   1060  2314    mcneal 
   1061  2314    mcneal 	return (True);
   1062  2314    mcneal }
   1063  2314    mcneal 
   1064  2314    mcneal /*
   1065  2314    mcneal  * []----
   1066  2314    mcneal  * | dataout_callback -- copy data from socket to emulation buffer
   1067  2314    mcneal  * []----
   1068  2314    mcneal  */
   1069  2314    mcneal void
   1070  2314    mcneal dataout_callback(t10_cmd_t *t, char *data, size_t *xfer)
   1071  2314    mcneal {
   1072  2314    mcneal 	iscsi_cmd_t	*cmd	= (iscsi_cmd_t *)T10_TRANS_ID(t);
   1073  2314    mcneal 	iscsi_conn_t	*c	= cmd->c_allegiance;
   1074  4568       ahl 	int		dlen	= cmd->c_data_len;
   1075  4568       ahl 	int		cc;
   1076  2314    mcneal 	char		pad_buf[ISCSI_PAD_WORD_LEN - 1];
   1077  2314    mcneal 	char		pad_len = 0;
   1078  2314    mcneal 
   1079  2314    mcneal 	pad_len = ((ISCSI_PAD_WORD_LEN -
   1080  2314    mcneal 	    (dlen & (ISCSI_PAD_WORD_LEN - 1))) &
   1081  2314    mcneal 	    (ISCSI_PAD_WORD_LEN - 1));
   1082  2314    mcneal 
   1083  2314    mcneal 
   1084  2314    mcneal 	if (T10_DATA(t) != NULL) {
   1085  2314    mcneal 		assert(T10_DATA(t) == cmd->c_data);
   1086  2314    mcneal 		assert(cmd->c_data_alloc == True);
   1087  2314    mcneal 		free(T10_DATA(t));
   1088  2314    mcneal 		T10_DATA(t)		= NULL;
   1089  2314    mcneal 		cmd->c_data		= NULL;
   1090  2314    mcneal 		cmd->c_data_alloc	= False;
   1091  2314    mcneal 		return;
   1092  2314    mcneal 	}
   1093  2314    mcneal 
   1094  3022    mcneal 	if ((cc = recv(c->c_fd, data, dlen, MSG_WAITALL)) != dlen) {
   1095  2314    mcneal 		if (errno == ECONNRESET) {
   1096  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
   1097  3077    mcneal 			    "CON%x  data_callback -- initiator reset socket\n",
   1098  2314    mcneal 			    c->c_num);
   1099  2314    mcneal 		} else {
   1100  2314    mcneal 			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
   1101  3022    mcneal 			    "CON%x  recv(got-%d, expect-%d) errno=%d",
   1102  2314    mcneal 			    c->c_num, cc, dlen, errno);
   1103  2314    mcneal 		}
   1104  2314    mcneal 
   1105  2314    mcneal 		conn_state(c, T8);
   1106  2314    mcneal 		goto finish;
   1107  2314    mcneal 	}
   1108  2314    mcneal 
   1109  2314    mcneal 	if (pad_len) {
   1110  3022    mcneal 		if (recv(c->c_fd, pad_buf, pad_len, MSG_WAITALL) != pad_len) {
   1111  2314    mcneal 			if (errno == ECONNRESET) {
   1112  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
   1113  2314    mcneal 				    "CON%x  data_callback -- "
   1114  3077    mcneal 				    "initiator reset socket\n", c->c_num);
   1115  2314    mcneal 			} else {
   1116  2314    mcneal 				queue_prt(c->c_mgmtq, Q_CONN_ERRS,
   1117  2314    mcneal 				    "CON%x data_callback -- "
   1118  3077    mcneal 				    "pad read errno=%d\n", c->c_num, errno);
   1119  2314    mcneal 			}
   1120  2314    mcneal 			conn_state(c, T8);
   1121  2314    mcneal 			goto finish;
   1122  2314    mcneal 		}
   1123  2314    mcneal 	}
   1124  2314    mcneal 
   1125  2314    mcneal finish:
   1126  2314    mcneal 	*xfer = cc;
   1127  2314    mcneal 	/* ---- Send msg that receive side of the connection can go ---- */
   1128  2314    mcneal 	(void) sema_post(&c->c_datain);
   1129  2314    mcneal }
   1130