1/*
2 * IMPORTANT:  READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3 * By downloading, copying, installing or using the software you agree
4 * to this license.  If you do not agree to this license, do not
5 * download, install, copy or use the software.
6 *
7 * Intel License Agreement
8 *
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * -Redistributions of source code must retain the above copyright
17 *  notice, this list of conditions and the following disclaimer.
18 *
19 * -Redistributions in binary form must reproduce the above copyright
20 *  notice, this list of conditions and the following disclaimer in the
21 *  documentation and/or other materials provided with the
22 *  distribution.
23 *
24 * -The name of Intel Corporation may not be used to endorse or
25 *  promote products derived from this software without specific prior
26 *  written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL INTEL
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41#include "config.h"
42
43#ifdef HAVE_STDLIB_H
44#include <stdlib.h>
45#endif
46
47#ifdef HAVE_NETINET_IN_H
48#include <netinet/in.h>
49#endif
50
51#ifdef HAVE_SYS_UIO_H
52#include <sys/uio.h>
53#endif
54
55#ifdef HAVE_STRING_H
56#include <string.h>
57#endif
58
59#ifdef HAVE_INTTYPES_H
60#include <inttypes.h>
61#endif
62
63#include "iscsiprotocol.h"
64#include "iscsiutil.h"
65
66
67/*
68 * Task Command
69 */
70
71int
72iscsi_task_cmd_encap(uint8_t *header, iscsi_task_cmd_t * cmd)
73{
74	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
75	iscsi_trace(TRACE_ISCSI_ARGS, "Function:  %u\n", cmd->function);
76	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:       %" PRIu64 "\n", cmd->lun);
77	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", cmd->tag);
78	iscsi_trace(TRACE_ISCSI_ARGS, "Ref Tag:   %#x\n", cmd->ref_tag);
79	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
80	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
81	iscsi_trace(TRACE_ISCSI_ARGS, "RefCmdSN:  %u\n", cmd->RefCmdSN);
82	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN: %u\n", cmd->ExpDataSN);
83
84	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
85
86	header[0] |= ISCSI_TASK_CMD;	/* Opcode */
87	if (cmd->immediate) {
88		header[0] |= 0x40;	/* Immediate bit  */
89	}
90	header[1] = cmd->function & 0x80;	/* Function  */
91	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
92	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
93	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->ref_tag);	/* Reference Tag */
94	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
95	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
96	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->RefCmdSN);	/* RefCmdSN */
97	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->ExpDataSN);	/* ExpDataSN */
98
99	return 0;
100}
101
102int
103iscsi_task_cmd_decap(uint8_t *header, iscsi_task_cmd_t * cmd)
104{
105	const char	*errmsg;
106	uint8_t		 zeros[16];
107
108	if (ISCSI_OPCODE(header) != ISCSI_TASK_CMD) {
109		iscsi_err(__FILE__, __LINE__, "Opcode");
110		return 1;
111	}
112	cmd->immediate = ((header[0] & 0x40) == 0x40);
113	cmd->function = header[1] & 0x80;
114	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));
115	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
116	cmd->ref_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));
117	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
118	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
119	cmd->RefCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
120	cmd->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));
121
122	errmsg = NULL;
123	(void) memset(zeros, 0x0, sizeof(zeros));
124	if ((header[1] & 0x80) != 0x80) {
125		errmsg = "Byte 1 bit 0";
126	} else if (header[2] != 0) {
127		errmsg = "Byte 2";
128	} else if (header[3] != 0) {
129		errmsg = "Byte 3";
130	} else if (memcmp(header + 4, zeros, 4) != 0) {
131		errmsg = "Bytes 4-7";
132	} else if (memcmp(header + 40, zeros, 8) != 0) {
133		errmsg = "Bytes 40-47";
134	}
135	if (errmsg) {
136		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
137		NO_CLEANUP;
138		return 1;
139	}
140
141	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
142	iscsi_trace(TRACE_ISCSI_ARGS, "Function:  %u\n", cmd->function);
143	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:       %" PRIu64 "\n", cmd->lun);
144	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", cmd->tag);
145	iscsi_trace(TRACE_ISCSI_ARGS, "Ref Tag:   %#x\n", cmd->ref_tag);
146	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
147	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
148	iscsi_trace(TRACE_ISCSI_ARGS, "RefCmdSN:  %u\n", cmd->RefCmdSN);
149	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN: %u\n", cmd->ExpDataSN);
150	return 0;
151}
152
153/*
154 * Task Response
155 */
156
157int
158iscsi_task_rsp_encap(uint8_t *header, iscsi_task_rsp_t * rsp)
159{
160	uint32_t        length;
161
162	iscsi_trace(TRACE_ISCSI_ARGS, "Response:  %u\n", rsp->response);
163	iscsi_trace(TRACE_ISCSI_ARGS, "Length:    %u\n", rsp->length);
164	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", rsp->tag);
165	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:    %u\n", rsp->StatSN);
166	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:  %u\n", rsp->ExpCmdSN);
167	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:  %u\n", rsp->MaxCmdSN);
168
169	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
170
171	header[0] |= ISCSI_TASK_RSP;	/* Opcode */
172	header[1] |= 0x80;	/* Byte 1 bit 0  */
173	header[2] = rsp->response;	/* Response */
174	length = (rsp->length & 0x00ffffff);	/* Length */
175	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);
176	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);
177	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);
178	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);
179	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);
180	return 0;
181}
182
183int
184iscsi_task_rsp_decap(uint8_t *header, iscsi_task_rsp_t * rsp)
185{
186	const char	*errmsg;
187	uint8_t		 zeros[16];
188
189	if (ISCSI_OPCODE(header) != ISCSI_TASK_RSP) {
190		iscsi_err(__FILE__, __LINE__, "Opcode");
191		return 1;
192	}
193	rsp->response = header[2];
194	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
195	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
196	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
197	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
198	errmsg = NULL;
199	(void) memset(zeros, 0x0, sizeof(zeros));
200	if ((header[0] & 0x00) != 0x00) {
201		errmsg = "Byte 0 bits 0-1";
202	} else if ((header[1] & 0x80) != 0x80) {
203		errmsg = "Byte 1 bit 0";
204	} else if (header[3] != 0) {
205		errmsg = "Byte 3";
206	} else if (memcmp(header + 4, zeros, 12) != 0) {
207		errmsg = "Bytes 4-15";
208	} else if (memcmp(header + 20, zeros, 4) != 0) {
209		errmsg = "Bytes 20-23";
210	} else if (memcmp(header + 36, zeros, 12) != 0) {
211		errmsg = "Bytes 36-47";
212	}
213	if (errmsg) {
214		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
215		NO_CLEANUP;
216		return 1;
217	}
218	iscsi_trace(TRACE_ISCSI_ARGS, "Response:  %u\n", rsp->response);
219	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", rsp->tag);
220	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:    %u\n", rsp->StatSN);
221	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:  %u\n", rsp->ExpCmdSN);
222	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:  %u\n", rsp->MaxCmdSN);
223	return 0;
224}
225
226/*
227 * NOP-Out
228 */
229
230int
231iscsi_nop_out_encap(uint8_t *header, iscsi_nop_out_args_t * cmd)
232{
233
234	uint32_t        length;
235
236	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
237	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
238	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
239	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
240	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
241	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
242	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
243
244	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
245
246	header[0] = ISCSI_NOP_OUT;	/* Opcode */
247	if (cmd->immediate) {
248		header[0] |= 0x40;	/* Immediate bit */
249	}
250	header[1] |= 0x80;	/* Byte 1 bit 0 and Reserved */
251	length = (cmd->length & 0x00ffffff);	/* Length  */
252	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length  */
253	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
254	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
255	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Target Transfer Tag  */
256	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
257	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
258
259	return 0;
260}
261
262int
263iscsi_nop_out_decap(uint8_t *header, iscsi_nop_out_args_t * cmd)
264{
265	const char	*errmsg;
266	uint8_t		 zeros[16];
267
268	if (ISCSI_OPCODE(header) != ISCSI_NOP_OUT) {
269		iscsi_err(__FILE__, __LINE__, "Opcode");
270		return 1;
271	}
272	cmd->immediate = ((header[0] & 0x40) == 0x40);	/* Immediate bit  */
273	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
274	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
275	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
276	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Target Tranfer Tag */
277	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
278	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
279
280	errmsg = NULL;
281	(void) memset(zeros, 0x0, sizeof(zeros));
282	if (header[1] != 0x80) {
283		errmsg = "Byte 1";
284	} else if (memcmp(header + 2, zeros, 3) != 0) {
285		errmsg = "Bytes 2-4";
286	} else if (memcmp(header + 32, zeros, 16) != 0) {
287		errmsg = "Bytes 32-47";
288	}
289	if (errmsg) {
290		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
291		NO_CLEANUP;
292		return 1;
293	}
294	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
295	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
296	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
297	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
298	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
299	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
300	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
301	return 0;
302}
303
304/*
305 * NOP-In
306 */
307
308int
309iscsi_nop_in_encap(uint8_t *header, iscsi_nop_in_args_t * cmd)
310{
311	uint32_t        length;
312
313	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
314	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
315	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
316	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
317	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
318	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
319	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
320
321	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
322
323	header[0] = 0x00 | ISCSI_NOP_IN;	/* Opcode  */
324	header[1] |= 0x80;	/* Reserved */
325	length = (cmd->length & 0x00ffffff);	/* Length */
326	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
327	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
328	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
329	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Target Transfer Tag        */
330	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
331	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
332	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
333
334	return 0;
335}
336
337int
338iscsi_nop_in_decap(uint8_t *header, iscsi_nop_in_args_t * cmd)
339{
340	const char	*errmsg;
341	uint8_t		 zeros[16];
342
343	if (ISCSI_OPCODE(header) != ISCSI_NOP_IN) {
344		iscsi_err(__FILE__, __LINE__, "Opcode");
345		return 1;
346	}
347	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
348	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
349	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
350	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Target Transfer Tag */
351	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
352	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
353	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
354
355	errmsg = NULL;
356	(void) memset(zeros, 0x0, sizeof(zeros));
357	if ((header[0] & 0xc0) != 0x00) {
358		errmsg = "Byte 0, bits 0-1";
359	} else if (header[1] != 0x80) {
360		errmsg = "Byte 1";
361	} else if (memcmp(header + 2, zeros, 3) != 0) {
362		errmsg = "Bytes 2-4";
363	} else if (memcmp(header + 36, zeros, 12) != 0) {
364		errmsg = "Bytes 36-47";
365	}
366	if (errmsg) {
367		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
368		NO_CLEANUP;
369		return 1;
370	}
371	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
372	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
373	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
374	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
375	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
376	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
377	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
378	return 0;
379}
380
381/*
382 * Text Command
383 */
384
385int
386iscsi_text_cmd_encap(uint8_t *header, iscsi_text_cmd_args_t * cmd)
387{
388	uint32_t        length;
389
390	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
391	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", cmd->final);
392	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", cmd->cont);
393	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
394	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
395	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
396	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
397	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
398	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
399
400	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
401
402	header[0] |= ISCSI_TEXT_CMD;	/* Opcode */
403	if (cmd->immediate) {
404		header[0] |= 0x40;	/* Immediate bit */
405	}
406	if (cmd->final) {
407		header[1] |= 0x80;	/* Final bit */
408	}
409	if (cmd->cont) {
410		header[1] |= 0x40;	/* Continue bit */
411	}
412	length = (cmd->length & 0x00ffffff);	/* Length */
413	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
414	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
415	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
416	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
417	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
418	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
419
420	return 0;
421}
422
423int
424iscsi_text_cmd_decap(uint8_t *header, iscsi_text_cmd_args_t * cmd)
425{
426	const char	*errmsg;
427	uint8_t		 zeros[16];
428
429	if (ISCSI_OPCODE(header) != ISCSI_TEXT_CMD) {
430		iscsi_err(__FILE__, __LINE__, "Opcode");
431		return 1;
432	}
433	cmd->immediate = ((header[0] & 0x40) == 0x40);	/* Immediate bit  */
434	cmd->final = ((header[1] & 0x80) == 0x80);	/* Final bit */
435	cmd->cont = ((header[1] & 0x40) == 0x40);	/* Continue bit */
436	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
437	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
438	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
439	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
440	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
441	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
442
443	errmsg = NULL;
444	(void) memset(zeros, 0x0, sizeof(zeros));
445	if ((header[1] & 0x00) != 0x00) {
446		errmsg = "Byte 1, bits 2-7";
447	} else if (memcmp(header + 2, zeros, 3) != 0) {
448		errmsg = "Bytes 2-4";
449	} else if (memcmp(header + 8, zeros, 8) != 0) {
450		errmsg = "Bytes 8-15";
451	} else if (memcmp(header + 32, zeros, 16) != 0) {
452		errmsg = "Bytes 32-47";
453	}
454	if (errmsg) {
455		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
456		NO_CLEANUP;
457		return 1;
458	}
459	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
460	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", cmd->final);
461	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", cmd->cont);
462	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
463	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
464	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
465	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
466	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
467	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
468
469	return 0;
470}
471
472/*
473 * Text Response
474 */
475
476int
477iscsi_text_rsp_encap(uint8_t *header, iscsi_text_rsp_args_t * rsp)
478{
479	uint32_t        length;
480
481	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", rsp->final);
482	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", rsp->cont);
483	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", rsp->length);
484	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", rsp->lun);
485	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", rsp->tag);
486	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", rsp->transfer_tag);
487	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", rsp->StatSN);
488	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", rsp->ExpCmdSN);
489	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", rsp->MaxCmdSN);
490
491	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
492	header[0] |= 0x00 | ISCSI_TEXT_RSP;	/* Opcode */
493	if (rsp->final) {
494		header[1] |= 0x80;	/* Final bit */
495	}
496	if (rsp->cont) {
497		header[1] |= 0x40;	/* Continue */
498	}
499	length = (rsp->length & 0x00ffffff);	/* Length */
500	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
501	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(rsp->lun);	/* LUN */
502	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag */
503	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(rsp->transfer_tag);	/* Transfer Tag */
504	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
505	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
506	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
507
508	return 0;
509}
510
511int
512iscsi_text_rsp_decap(uint8_t *header, iscsi_text_rsp_args_t * rsp)
513{
514	const char	*errmsg;
515	uint8_t		 zeros[16];
516
517	if (ISCSI_OPCODE(header) != ISCSI_TEXT_RSP) {
518		iscsi_err(__FILE__, __LINE__, "Opcode");
519		return 1;
520	}
521	rsp->final = ((header[1] & 0x80) == 0x80);	/* Final bit  */
522	rsp->cont = ((header[1] & 0x40) == 0x40);	/* Continue bit */
523	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
524	rsp->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
525	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
526	rsp->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
527	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
528	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
529	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
530
531	errmsg = NULL;
532	(void) memset(zeros, 0x0, sizeof(zeros));
533	if ((header[1] & 0x3f) != 0x00) {
534		errmsg = "Byte 1, bits 2-7";
535	} else if (memcmp(header + 2, zeros, 3) != 0) {
536		errmsg = "Bytes 2-4";
537	} else if (memcmp(header + 8, zeros, 8) != 0) {
538		errmsg = "Bytes 8-15";
539	} else if (memcmp(header + 36, zeros, 12) != 0) {
540		errmsg = "Bytes 36-47";
541	}
542	if (errmsg) {
543		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
544		NO_CLEANUP;
545		return 1;
546	}
547	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", rsp->final);
548	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", rsp->cont);
549	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", rsp->length);
550	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", rsp->lun);
551	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", rsp->tag);
552	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", rsp->transfer_tag);
553	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", rsp->StatSN);
554	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", rsp->ExpCmdSN);
555	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", rsp->MaxCmdSN);
556
557	return 0;
558}
559
560/*
561 * Login Command
562 */
563
564int
565iscsi_login_cmd_encap(uint8_t *header, iscsi_login_cmd_args_t * cmd)
566{
567	uint32_t        length;
568
569	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", cmd->transit);
570	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", cmd->cont);
571	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", cmd->csg);
572	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", cmd->nsg);
573	iscsi_trace(TRACE_ISCSI_ARGS, "Version_min:       %u\n", cmd->version_min);
574	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", cmd->version_max);
575	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
576	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
577	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", cmd->isid);
578	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %hu\n", cmd->tsih);
579	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
580	iscsi_trace(TRACE_ISCSI_ARGS, "CID:               %hu\n", cmd->cid);
581	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
582	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
583
584	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
585
586	header[0] |= 0x40 | ISCSI_LOGIN_CMD;	/* Opcode  */
587	if (cmd->transit) {
588		header[1] |= 0x80;	/* Transit */
589	}
590	if (cmd->cont) {
591		header[1] |= 0x40;	/* Continue */
592	}
593	header[1] |= ((cmd->csg) << 2) & 0x0c;	/* CSG */
594	header[1] |= (cmd->nsg) & 0x03;	/* NSG */
595	header[2] = cmd->version_max;	/* Version-Max  */
596	header[3] = cmd->version_min;	/* Version-Min  */
597	header[4] = cmd->AHSlength;	/* TotalAHSLength */
598	length = (cmd->length & 0x00ffffff);	/* Length  */
599	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length  */
600	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->isid);	/* ISID */
601	*((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(cmd->tsih);	/* TSIH */
602	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Task Tag */
603	*((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid);	/* CID */
604	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
605	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
606
607	return 0;
608}
609
610int
611iscsi_login_cmd_decap(uint8_t *header, iscsi_login_cmd_args_t * cmd)
612{
613	const char	*errmsg;
614	uint8_t		 zeros[16];
615
616	if (ISCSI_OPCODE(header) != ISCSI_LOGIN_CMD) {
617		iscsi_err(__FILE__, __LINE__, "Opcode");
618		return 1;
619	}
620	cmd->transit = (header[1] & 0x80) ? 1 : 0;	/* Transit */
621	cmd->cont = (header[1] & 0x40) ? 1 : 0;	/* Continue */
622	cmd->csg = (header[1] & 0x0cU) >> 2;	/* CSG */
623	cmd->nsg = header[1] & 0x03;	/* NSG */
624	cmd->version_max = header[2];	/* Version-Max  */
625	cmd->version_min = header[3];	/* Version-Min  */
626	cmd->AHSlength = header[4];	/* TotalAHSLength */
627	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
628	cmd->isid = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* ISID */
629	cmd->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14)));	/* TSIH */
630	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
631	cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20)));	/* CID */
632	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN  */
633	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
634
635	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", cmd->transit);
636	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", cmd->cont);
637	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", cmd->csg);
638	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", cmd->nsg);
639	iscsi_trace(TRACE_ISCSI_ARGS, "Version_min:       %u\n", cmd->version_min);
640	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", cmd->version_max);
641	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
642	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
643	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", cmd->isid);
644	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %hu\n", cmd->tsih);
645	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
646	iscsi_trace(TRACE_ISCSI_ARGS, "CID:               %hu\n", cmd->cid);
647	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
648	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
649
650	errmsg = NULL;
651	(void) memset(zeros, 0x0, sizeof(zeros));
652	if (((header[1] & 0x30U) >> 4U) != 0x0) {
653		errmsg = "Byte 1, bits 2-3";
654	} else if (memcmp(header + 22, zeros, 2) != 0) {
655		errmsg = "Bytes 22-23";
656	} else if (memcmp(header + 32, zeros, 16) != 0) {
657		errmsg = "Bytes 32-47";
658	}
659	if (errmsg) {
660		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
661		NO_CLEANUP;
662		return 1;
663	}
664	if (cmd->transit) {
665		if (cmd->nsg <= cmd->csg) {
666			return -1;
667		}
668		if ((cmd->nsg != 0) && (cmd->nsg != 1) && (cmd->nsg != 3)) {
669			return -1;
670		}
671	}
672	return 0;
673}
674
675/*
676 * Login Response
677 */
678
679int
680iscsi_login_rsp_encap(uint8_t *header, iscsi_login_rsp_args_t * rsp)
681{
682
683	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", rsp->transit);
684	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", rsp->cont);
685	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", rsp->csg);
686	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", rsp->nsg);
687	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", rsp->version_max);
688	iscsi_trace(TRACE_ISCSI_ARGS, "Version_active:    %u\n", rsp->version_active);
689	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", rsp->AHSlength);
690	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", rsp->length);
691	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", rsp->isid);
692	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %u\n", rsp->tsih);
693	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", rsp->tag);
694	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", rsp->StatSN);
695	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", rsp->ExpCmdSN);
696	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", rsp->MaxCmdSN);
697	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Class:      %u\n", rsp->status_class);
698	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Detail:     %u\n", rsp->status_detail);
699
700	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
701
702	header[0] |= 0x00 | ISCSI_LOGIN_RSP;	/* Opcode  */
703	if (rsp->transit) {
704		header[1] |= 0x80;	/* Transit  */
705	}
706	if (rsp->cont) {
707		header[1] |= 0x40;	/* Continue */
708	}
709	header[1] |= ((rsp->csg) << 2) & 0x0c;	/* CSG */
710	if (rsp->transit) {
711		header[1] |= (rsp->nsg) & 0x03;	/* NSG */
712	}
713	header[2] = rsp->version_max;	/* Version-max */
714	header[3] = rsp->version_active;	/* Version-active */
715	header[4] = rsp->AHSlength;	/* TotalAHSLength */
716	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* Length */
717	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(rsp->isid);	/* ISID */
718	*((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(rsp->tsih);	/* TSIH */
719	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag  */
720	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatRn */
721	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
722	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
723	header[36] = rsp->status_class;	/* Status-Class */
724	header[37] = rsp->status_detail;	/* Status-Detail */
725
726	return 0;
727}
728
729int
730iscsi_login_rsp_decap(uint8_t *header, iscsi_login_rsp_args_t * rsp)
731{
732	const char	*errmsg;
733	uint8_t		 zeros[8];
734
735	if (ISCSI_OPCODE(header) != ISCSI_LOGIN_RSP) {
736		iscsi_err(__FILE__, __LINE__, "Opcode");
737		return 1;
738	}
739	rsp->transit = (header[1] & 0x80U) >> 7;	/* Transit  */
740	rsp->cont = (header[1] & 0x40U) >> 6;	/* Continue */
741	rsp->csg = (header[1] & 0x0cU) >> 2;	/* CSG  */
742	rsp->nsg = header[1] & 0x03;	/* NSG  */
743	rsp->version_max = header[2];	/* Version-max */
744	rsp->version_active = header[3];	/* Version-active */
745	rsp->AHSlength = header[4];	/* TotalAHSLength */
746	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
747	rsp->isid = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* ISID */
748	rsp->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14)));	/* TSIH */
749
750	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
751	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
752	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
753	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
754	rsp->status_class = header[36];	/* Status-Class */
755	rsp->status_detail = header[37];	/* Status-Detail */
756
757	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", rsp->transit);
758	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", rsp->cont);
759	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", rsp->csg);
760	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", rsp->nsg);
761
762	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", rsp->version_max);
763	iscsi_trace(TRACE_ISCSI_ARGS, "Version_active:    %u\n", rsp->version_active);
764	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", rsp->AHSlength);
765	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", rsp->length);
766	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", rsp->isid);
767	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %u\n", rsp->tsih);
768	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", rsp->tag);
769	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", rsp->StatSN);
770	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", rsp->ExpCmdSN);
771	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", rsp->MaxCmdSN);
772	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Class:      %u\n", rsp->status_class);
773	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Detail:     %u\n", rsp->status_detail);
774	errmsg = NULL;
775	(void) memset(zeros, 0x0, sizeof(zeros));
776	if (((header[1] & 0x30U) >> 4U) != 0x0) {
777		errmsg = "Byte 1, bits 2-3";
778	} else if (memcmp(header + 20, zeros, 4) != 0) {
779		errmsg = "Bytes 20-23";
780	} else if (memcmp(header + 38, zeros, 2) != 0) {
781		errmsg = "Bytes 38-39";
782	} else if (memcmp(header + 40, zeros, 8) != 0) {
783		errmsg = "Bytes 40-47";
784	}
785	if (errmsg) {
786		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
787		NO_CLEANUP;
788		return 1;
789	}
790	return 0;
791}
792
793/*
794 * Logout Command
795 */
796
797int
798iscsi_logout_cmd_encap(uint8_t *header, iscsi_logout_cmd_args_t * cmd)
799{
800
801	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
802	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:    %u\n", cmd->reason);
803	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:  %#x\n", cmd->tag);
804	iscsi_trace(TRACE_ISCSI_ARGS, "CID:       %hu\n", cmd->cid);
805	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
806	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
807
808	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
809
810	header[0] = ISCSI_LOGOUT_CMD;	/* Opcode */
811	if (cmd->immediate) {
812		header[0] |= 0x40;	/* Immediate */
813	}
814	header[1] = cmd->reason | 0x80;	/* Reason  */
815	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
816	*((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid);	/* CID */
817	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
818	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN  */
819
820	return 0;
821}
822
823int
824iscsi_logout_cmd_decap(uint8_t *header, iscsi_logout_cmd_args_t * cmd)
825{
826	const char	*errmsg;
827	uint8_t		 zeros[16];
828
829	if (ISCSI_OPCODE(header) != ISCSI_LOGOUT_CMD) {
830		iscsi_err(__FILE__, __LINE__, "Opcode");
831		return 1;
832	}
833	cmd->immediate = (header[0] & 0x40) ? 1 : 0;	/* Immediate */
834	cmd->reason = header[1] & 0x7f;	/* Reason */
835	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
836	cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20)));	/* CID */
837	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
838	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
839
840	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
841	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:    %u\n", cmd->reason);
842	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:  %#x\n", cmd->tag);
843
844	iscsi_trace(TRACE_ISCSI_ARGS, "CID:       %hu\n", cmd->cid);
845	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
846	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
847	errmsg = NULL;
848	(void) memset(zeros, 0x0, sizeof(zeros));
849	if ((unsigned)(header[0]) >> 0x7U != 0) {
850		errmsg = "Byte 0, bit 0";
851	} else if ((unsigned)(header[1]) >> 7U != 1) {
852		errmsg = "Byte 1, bit 0";
853	} else if (header[2] != 0) {
854		errmsg = "Byte 2";
855	} else if (header[3] != 0) {
856		errmsg = "Byte 3";
857	} else if (memcmp(header + 4, zeros, 12) != 0) {
858		errmsg = "Bytes 4-7";
859	} else if (memcmp(header + 22, zeros, 2) != 0) {
860		errmsg = "Bytes 22-23";
861	} else if (memcmp(header + 32, zeros, 16) != 0) {
862		errmsg = "Bytes 32-47";
863	}
864	if (errmsg) {
865		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
866		NO_CLEANUP;
867		return 1;
868	}
869	return 0;
870}
871
872/*
873 * Logout Response
874 */
875
876int
877iscsi_logout_rsp_encap(uint8_t *header, iscsi_logout_rsp_args_t * rsp)
878{
879
880	iscsi_trace(TRACE_ISCSI_ARGS, "Response:    %u\n", rsp->response);
881	iscsi_trace(TRACE_ISCSI_ARGS, "Length:      %u\n", rsp->length);
882	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:    %#x\n", rsp->tag);
883	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:      %u\n", rsp->StatSN);
884	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:    %u\n", rsp->ExpCmdSN);
885	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:    %u\n", rsp->MaxCmdSN);
886
887	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Wait:   %hu\n", rsp->Time2Wait);
888	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Retain: %hu\n", rsp->Time2Retain);
889
890	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
891
892	header[0] |= 0x00 | ISCSI_LOGOUT_RSP;	/* Opcode  */
893	header[1] |= 0x80;	/* Reserved  */
894	header[2] = rsp->response;	/* Response */
895	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* Length */
896	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag */
897	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
898	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
899	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
900	*((uint16_t *) (void *) (header + 40)) = ISCSI_HTONS(rsp->Time2Wait);	/* Time2Wait */
901	*((uint16_t *) (void *) (header + 42)) = ISCSI_HTONS(rsp->Time2Retain);	/* Time2Retain */
902
903	return 0;
904}
905
906int
907iscsi_logout_rsp_decap(uint8_t *header, iscsi_logout_rsp_args_t * rsp)
908{
909	const char	*errmsg;
910	uint8_t		 zeros[16];
911
912	if (ISCSI_OPCODE(header) != ISCSI_LOGOUT_RSP) {
913		iscsi_err(__FILE__, __LINE__, "Opcode");
914		return 1;
915	}
916	rsp->response = header[2];	/* Response */
917	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
918	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
919	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
920	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
921	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
922	rsp->Time2Wait = ISCSI_NTOHS(*((uint32_t *) (void *) (header + 40)));	/* Time2Wait */
923	rsp->Time2Retain = ISCSI_NTOHS(*((uint32_t *) (void *) (header + 42)));	/* Time2Retain */
924
925	errmsg = NULL;
926	(void) memset(zeros, 0x0, sizeof(zeros));
927	if ((header[0] & 0x20) != 0x20) {
928		errmsg = "Byte 0, bits 0-1";
929	} else if ((header[1] & 0x80) != 0x80) {
930		errmsg = "Byte 1, bit 0";
931	} else if (header[3] != 0) {
932		errmsg = "Byte 3";
933	} else if (memcmp(header + 4, zeros, 12) != 0) {
934		errmsg = "Bytes 4-15";
935	} else if (memcmp(header + 20, zeros, 4) != 0) {
936		errmsg = "Bytes 20-23";
937	} else if (memcmp(header + 36, zeros, 4) != 0) {
938		errmsg = "Bytes 36-39";
939	} else if (memcmp(header + 44, zeros, 4) != 0) {
940		errmsg = "Bytes 44-47";
941	}
942	if (errmsg) {
943		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
944		NO_CLEANUP;
945		return 1;
946	}
947	iscsi_trace(TRACE_ISCSI_ARGS, "Response:    %u\n", rsp->response);
948	iscsi_trace(TRACE_ISCSI_ARGS, "Length:      %u\n", rsp->length);
949	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:    %#x\n", rsp->tag);
950	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:      %u\n", rsp->StatSN);
951	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:    %u\n", rsp->ExpCmdSN);
952	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:    %u\n", rsp->MaxCmdSN);
953	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Wait:   %hu\n", rsp->Time2Wait);
954	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Retain: %hu\n", rsp->Time2Retain);
955
956	return 0;
957}
958
959/*
960 * SCSI Command
961 */
962
963int
964iscsi_scsi_cmd_encap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd)
965{
966
967	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:         %d\n", cmd->immediate);
968	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
969	iscsi_trace(TRACE_ISCSI_ARGS, "Input:             %d\n", cmd->input);
970	iscsi_trace(TRACE_ISCSI_ARGS, "Output:            %d\n", cmd->output);
971	iscsi_trace(TRACE_ISCSI_ARGS, "ATTR:              %d\n", cmd->attr);
972	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->ahs_len);
973	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
974	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
975	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
976	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Length:   %u\n", cmd->trans_len);
977	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
978	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
979	iscsi_trace(TRACE_ISCSI_ARGS, "CDB:               %#x\n", cmd->cdb[0]);
980
981	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
982
983	header[0] |= ISCSI_SCSI_CMD;	/* Opcode */
984	if (cmd->immediate) {
985		header[0] |= 0x40;	/* Immediate */
986	}
987	if (cmd->final) {
988		header[1] |= 0x80;	/* Final */
989	}
990	if (cmd->input) {
991		header[1] |= 0x40;	/* Input bit */
992	}
993	if (cmd->output) {
994		header[1] |= 0x20;	/* Output bit */
995	}
996	header[1] |= cmd->attr & 0x07;	/* ATTR  */
997	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* DataSegmentLength */
998	header[4] = cmd->ahs_len;	/* TotalAHSLength  */
999	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
1000	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Task Tag  */
1001	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->trans_len);	/* Expected Transfer
1002								 * Length */
1003	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
1004	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
1005	memcpy(header + 32, cmd->cdb, 16);	/* CDB */
1006
1007	return 0;
1008}
1009
1010int
1011iscsi_scsi_cmd_decap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd)
1012{
1013	const char	*errmsg;
1014
1015	if (ISCSI_OPCODE(header) != ISCSI_SCSI_CMD) {
1016		iscsi_err(__FILE__, __LINE__, "Opcode");
1017		return 1;
1018	}
1019	cmd->immediate = (header[0] & 0x40) ? 1 : 0;	/* Immediate */
1020	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1021	cmd->input = (header[1] & 0x40) ? 1 : 0;	/* Input */
1022	cmd->output = (header[1] & 0x20) ? 1 : 0;	/* Output */
1023	cmd->attr = header[1] & 0x07;	/* ATTR  */
1024	cmd->ahs_len = header[4];
1025	header[4] = 0x00;
1026	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* DataSegmentLength */
1027	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1028	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
1029	cmd->trans_len = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Expected Transfer
1030								 * Length */
1031	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN  */
1032	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
1033	cmd->cdb = header + 32;	/* CDB */
1034
1035	errmsg = NULL;
1036	if ((header[1] & 0x18) != 0x0) {
1037		errmsg = "Byte 1, bits 3-4";
1038	} else if (header[2] != 0) {
1039		errmsg = "Byte 2";
1040	} else if (header[3] != 0) {
1041		errmsg = "Byte 3";
1042	}
1043	if (errmsg) {
1044		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1045		NO_CLEANUP;
1046		return 1;
1047	}
1048	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:         %d\n", cmd->immediate);
1049	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1050	iscsi_trace(TRACE_ISCSI_ARGS, "Input:             %d\n", cmd->input);
1051	iscsi_trace(TRACE_ISCSI_ARGS, "Output:            %d\n", cmd->output);
1052	iscsi_trace(TRACE_ISCSI_ARGS, "ATTR:              %d\n", cmd->attr);
1053	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->ahs_len);
1054	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1055	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
1056	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
1057	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Length:   %u\n", cmd->trans_len);
1058	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
1059	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
1060	iscsi_trace(TRACE_ISCSI_ARGS, "CDB:               %#x\n", cmd->cdb[0]);
1061
1062	return 0;
1063}
1064
1065/*
1066 * SCSI Response
1067 */
1068
1069int
1070iscsi_scsi_rsp_encap(uint8_t *header, iscsi_scsi_rsp_t * rsp)
1071{
1072
1073	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Overflow:       %d\n", rsp->bidi_overflow);
1074	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Underflow:      %d\n", rsp->bidi_underflow);
1075	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:            %d\n", rsp->overflow);
1076	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:           %d\n", rsp->underflow);
1077	iscsi_trace(TRACE_ISCSI_ARGS, "iSCSI Response:      %u\n", rsp->response);
1078	iscsi_trace(TRACE_ISCSI_ARGS, "SCSI Status:         %u\n", rsp->status);
1079	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:   %u\n", rsp->length);
1080	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:            %#x\n", rsp->tag);
1081	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:              %u\n", rsp->StatSN);
1082	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:            %u\n", rsp->ExpCmdSN);
1083	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:            %u\n", rsp->MaxCmdSN);
1084	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN:           %u\n", rsp->ExpDataSN);
1085	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt);
1086	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:      %u\n", rsp->basic_res_cnt);
1087
1088	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1089
1090	header[0] |= 0x00 | ISCSI_SCSI_RSP;	/* Opcode  */
1091	header[1] |= 0x80;	/* Byte 1 bit 7 */
1092	if (rsp->bidi_overflow) {
1093		header[1] |= 0x10;	/* Bidi overflow */
1094	}
1095	if (rsp->bidi_underflow) {
1096		header[1] |= 0x08;	/* Bidi underflow */
1097	}
1098	if (rsp->overflow) {
1099		header[1] |= 0x04;	/* Overflow */
1100	}
1101	if (rsp->underflow) {
1102		header[1] |= 0x02;	/* Underflow  */
1103	}
1104	header[2] = rsp->response;	/* iSCSI Response */
1105	header[3] = rsp->status;/* SCSI Status */
1106	header[4] = rsp->ahs_len;	/* TotalAHSLength  */
1107	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* DataSegmentLength */
1108	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Task Tag */
1109	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
1110	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
1111	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
1112	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(rsp->ExpDataSN);	/* ExpDataSN  */
1113	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(rsp->bidi_res_cnt);	/* Bidi Residual Count */
1114	*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(rsp->basic_res_cnt);	/* Residual Count */
1115
1116	return 0;
1117}
1118
1119int
1120iscsi_scsi_rsp_decap(uint8_t *header, iscsi_scsi_rsp_t * rsp)
1121{
1122	const char	*errmsg;
1123
1124	if (ISCSI_OPCODE(header) != ISCSI_SCSI_RSP) {
1125		iscsi_err(__FILE__, __LINE__, "Opcode");
1126		return 1;
1127	}
1128	rsp->bidi_overflow = (header[1] & 0x10) ? 1 : 0;	/* Bidi overflow */
1129	rsp->bidi_underflow = (header[1] & 0x08) ? 1 : 0;	/* Bidi underflow */
1130	rsp->overflow = (header[1] & 0x04) ? 1 : 0;	/* Overflow */
1131	rsp->underflow = (header[1] & 0x02) ? 1 : 0;	/* Underflow */
1132
1133	rsp->response = header[2];	/* iSCSI Response */
1134	rsp->status = header[3];/* SCSI Status */
1135	rsp->ahs_len = header[4];	/* TotalAHSLength  */
1136	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* DataSegmentLength */
1137	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag  */
1138	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
1139	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN  */
1140	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1141	rsp->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* ExpDataSN  */
1142	rsp->bidi_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Bidi Residual Count  */
1143	rsp->basic_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));	/* Residual Count */
1144
1145	errmsg = NULL;
1146	if ((header[0] & 0xc0) != 0x0) {
1147		errmsg = "Byte 0, bits 0-1";
1148	} else if ((header[1] & 0x80) != 0x80) {
1149		errmsg = "Byte 1, bit 0";
1150	} else if (rsp->bidi_res_cnt != 0) {
1151		errmsg = "bidi_res_cnt";
1152	} else if (rsp->bidi_overflow != 0) {
1153		errmsg = "bidi_overflow";
1154	} else if (rsp->bidi_underflow != 0) {
1155		errmsg = "bidi_underflow";
1156	} else if (rsp->overflow != 0) {
1157		errmsg = "overflow";
1158	}
1159	if (errmsg) {
1160		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1161		NO_CLEANUP;
1162		return 1;
1163	}
1164	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Overflow:       %d\n", rsp->bidi_overflow);
1165	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Underflow:      %d\n", rsp->bidi_underflow);
1166	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:            %d\n", rsp->overflow);
1167	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:           %d\n", rsp->underflow);
1168	iscsi_trace(TRACE_ISCSI_ARGS, "iSCSI Response:      %u\n", rsp->response);
1169	iscsi_trace(TRACE_ISCSI_ARGS, "SCSI Status:         %u\n", rsp->status);
1170	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:   %u\n", rsp->length);
1171	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:            %#x\n", rsp->tag);
1172	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:      %u\n", rsp->basic_res_cnt);
1173	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:              %u\n", rsp->StatSN);
1174	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:            %u\n", rsp->ExpCmdSN);
1175	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:            %u\n", rsp->MaxCmdSN);
1176	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN:           %u\n", rsp->ExpDataSN);
1177	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt);
1178
1179	return 0;
1180}
1181
1182
1183/*
1184 * Ready To Transfer
1185 */
1186
1187int
1188iscsi_r2t_encap(uint8_t *header, iscsi_r2t_t * cmd)
1189{
1190	uint32_t        length;
1191
1192	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
1193	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
1194	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
1195	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
1196	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
1197	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
1198	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
1199	iscsi_trace(TRACE_ISCSI_ARGS, "R2TSN:        %u\n", cmd->R2TSN);
1200	iscsi_trace(TRACE_ISCSI_ARGS, "Offset:       %u\n", cmd->offset);
1201	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
1202
1203	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1204
1205	header[0] |= 0x00 | ISCSI_R2T;	/* Opcode  */
1206	header[1] |= 0x80;
1207	length = (cmd->AHSlength & 0x00ffffff);	/* AHSLength */
1208	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* AHSLength */
1209	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
1210	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
1211	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1212	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN  */
1213	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
1214	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
1215	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->R2TSN);	/* R2TSN */
1216	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1217	*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->length);	/* Transfer Length */
1218
1219	return 0;
1220}
1221
1222int
1223iscsi_r2t_decap(uint8_t *header, iscsi_r2t_t * cmd)
1224{
1225	const char	*errmsg;
1226	uint8_t		 zeros[12];
1227
1228	if (ISCSI_OPCODE(header) != ISCSI_R2T) {
1229		iscsi_err(__FILE__, __LINE__, "Opcode");
1230		return 1;
1231	}
1232	cmd->AHSlength = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* TotalAHSLength */
1233	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1234	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
1235	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));
1236	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
1237	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
1238	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
1239	cmd->R2TSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));
1240	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));
1241	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));
1242
1243	errmsg = NULL;
1244	(void) memset(zeros, 0x0, sizeof(zeros));
1245	if ((header[1] & 0x7f) != 0x0) {
1246		errmsg = "Byte 1, bits 1-7";
1247	} else if (header[2] != 0) {
1248		errmsg = "Byte 2";
1249	} else if (header[3] != 0) {
1250		errmsg = "Byte 3";
1251	} else if (memcmp(header + 4, zeros, 12) != 0) {
1252		errmsg = "Bytes 4-15";
1253	}
1254	if (errmsg) {
1255		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1256		NO_CLEANUP;
1257		return 1;
1258	}
1259	iscsi_trace(TRACE_ISCSI_ARGS, "AHSLength:    %u\n", cmd->AHSlength);
1260	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
1261	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
1262	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
1263	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
1264	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
1265	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
1266	iscsi_trace(TRACE_ISCSI_ARGS, "R2TSN:        %u\n", cmd->R2TSN);
1267	iscsi_trace(TRACE_ISCSI_ARGS, "Offset:       %u\n", cmd->offset);
1268	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
1269	return 0;
1270}
1271
1272/*
1273 * SCSI Write Data
1274 */
1275
1276int
1277iscsi_write_data_encap(uint8_t *header, iscsi_write_data_t * cmd)
1278{
1279
1280	iscsi_trace(TRACE_ISCSI_ARGS, "Final:              %u\n", cmd->final);
1281	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:  %u\n", cmd->length);
1282	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:                %" PRIu64 "\n", cmd->lun);
1283	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:           %#x\n", cmd->tag);
1284	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:       %#x\n", cmd->transfer_tag);
1285	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:          %u\n", cmd->ExpStatSN);
1286	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:             %u\n", cmd->DataSN);
1287	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset:      %u\n", cmd->offset);
1288
1289	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1290	header[0] = 0x00 | ISCSI_WRITE_DATA;	/* Opcode  */
1291	if (cmd->final) {
1292		header[1] |= 0x80;	/* Final */
1293	}
1294	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length */
1295	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
1296	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
1297	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1298	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
1299	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN */
1300	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1301
1302	return 0;
1303}
1304
1305int
1306iscsi_write_data_decap(uint8_t *header, iscsi_write_data_t * cmd)
1307{
1308	const char	*errmsg;
1309	uint8_t		 zeros[16];
1310
1311	if (ISCSI_OPCODE(header) != ISCSI_WRITE_DATA) {
1312		iscsi_err(__FILE__, __LINE__, "Opcode");
1313		return 1;
1314	}
1315	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1316	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1317	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1318	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
1319	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
1320	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN  */
1321	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN    */
1322	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Buffer Offset */
1323
1324	errmsg = NULL;
1325	(void) memset(zeros, 0x0, sizeof(zeros));
1326	if ((header[1] & 0x7f) != 0x0) {
1327		errmsg = "Byte 1, bits 1-7";
1328	} else if (header[2] != 0) {
1329		errmsg = "Byte 2";
1330	} else if (header[3] != 0) {
1331		errmsg = "Byte 3";
1332	} else if (header[4] != 0) {
1333		errmsg = "Byte 4";
1334	} else if (memcmp(header + 24, zeros, 4) != 0) {
1335		errmsg = "Bytes 24-27";
1336	} else if (memcmp(header + 32, zeros, 4) != 0) {
1337		errmsg = "Bytes 32-35";
1338	} else if (memcmp(header + 44, zeros, 4) != 0) {
1339		errmsg = "Bytes 44-47";
1340	}
1341	if (errmsg) {
1342		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1343		NO_CLEANUP;
1344		return 1;
1345	}
1346	iscsi_trace(TRACE_ISCSI_ARGS, "Final:              %u\n", cmd->final);
1347	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:  %u\n", cmd->length);
1348	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:                %" PRIu64 "\n", cmd->lun);
1349	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:           %#x\n", cmd->tag);
1350	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:       %#x\n", cmd->transfer_tag);
1351	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:          %u\n", cmd->ExpStatSN);
1352	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:             %u\n", cmd->DataSN);
1353	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset:      %u\n", cmd->offset);
1354
1355	return 0;
1356}
1357
1358/*
1359 * SCSI Read Data
1360 */
1361
1362int
1363iscsi_read_data_encap(uint8_t *header, iscsi_read_data_t * cmd)
1364{
1365
1366	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1367	iscsi_trace(TRACE_ISCSI_ARGS, "Acknowledge:       %d\n", cmd->ack);
1368	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:          %d\n", cmd->overflow);
1369	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:         %d\n", cmd->underflow);
1370	iscsi_trace(TRACE_ISCSI_ARGS, "S_bit:             %d\n", cmd->S_bit);
1371	iscsi_trace(TRACE_ISCSI_ARGS, "Status:            %u\n", cmd->status);
1372	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1373	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
1374	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->task_tag);
1375	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:      %#x\n", cmd->transfer_tag);
1376	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", cmd->StatSN);
1377	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", cmd->ExpCmdSN);
1378	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", cmd->MaxCmdSN);
1379	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:            %u\n", cmd->DataSN);
1380	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset      %u\n", cmd->offset);
1381	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:    %u\n", cmd->res_count);
1382
1383	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1384
1385	header[0] = 0x00 | ISCSI_READ_DATA;	/* Opcode  */
1386	if (cmd->final) {
1387		header[1] |= 0x80;	/* Final */
1388	}
1389	if (cmd->ack) {
1390		header[1] |= 0x40;	/* ACK */
1391	}
1392	if (cmd->overflow) {
1393		header[1] |= 0x04;	/* Overflow  */
1394	}
1395	if (cmd->underflow) {
1396		header[1] |= 0x02;	/* Underflow */
1397	}
1398	if (cmd->S_bit) {
1399		header[1] |= 0x01;	/* S Bit */
1400	}
1401	if (cmd->S_bit) {
1402		header[3] = cmd->status;	/* Status  */
1403	}
1404	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length */
1405	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun);	/* LUN */
1406	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->task_tag);	/* Task Tag */
1407	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1408	if (cmd->S_bit) {
1409		*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
1410	}
1411	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN  */
1412	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN  */
1413	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN  */
1414	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1415	if (cmd->S_bit) {
1416		*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->res_count);	/* Residual Count  */
1417	}
1418
1419	return 0;
1420}
1421
1422int
1423iscsi_read_data_decap(uint8_t *header, iscsi_read_data_t * cmd)
1424{
1425	const char	*errmsg;
1426	uint8_t		 zeros[16];
1427
1428	if (ISCSI_OPCODE(header) != ISCSI_READ_DATA) {
1429		iscsi_err(__FILE__, __LINE__, "Opcode");
1430		return 1;
1431	}
1432	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1433	cmd->ack = (header[1] & 0x40) ? 1 : 0;	/* Acknowledge */
1434	cmd->overflow = (header[1] & 0x04) ? 1 : 0;	/* Overflow  */
1435	cmd->underflow = (header[1] & 0x02) ? 1 : 0;	/* Underflow  */
1436	cmd->S_bit = (header[1] & 0x01) ? 1 : 0;	/* S Bit  */
1437	cmd->status = header[3];/* Status */
1438	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1439	cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN  */
1440	cmd->task_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
1441	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag  */
1442	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
1443	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN  */
1444	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1445	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN  */
1446	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Buffer Offset */
1447	cmd->res_count = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));	/* Residual Count  */
1448	errmsg = NULL;
1449	(void) memset(zeros, 0x0, sizeof(zeros));
1450	if ((header[0] & 0xc0) != 0x0) {
1451		errmsg = "Byte 0, bits 0-1";
1452	} else if ((header[1] & 0x38) != 0x0) {
1453		errmsg = "Byte 1, bits 2-4";
1454	} else if (header[2] != 0) {
1455		errmsg = "Byte 2";
1456	} else if (header[4] != 0) {
1457		errmsg = "Byte 4";
1458	} else if (memcmp(header + 8, zeros, 8) != 0) {
1459		errmsg = "Bytes 8-15";
1460	} else if (!cmd->underflow && memcmp(header + 44, zeros, 4) != 0) {
1461		errmsg = "Bytes 44-47";
1462	}
1463	if (errmsg) {
1464		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1465		NO_CLEANUP;
1466		return 1;
1467	}
1468	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1469	iscsi_trace(TRACE_ISCSI_ARGS, "Acknowledge:       %d\n", cmd->ack);
1470	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:          %d\n", cmd->overflow);
1471	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:         %d\n", cmd->underflow);
1472	iscsi_trace(TRACE_ISCSI_ARGS, "S_bit:             %d\n", cmd->S_bit);
1473	iscsi_trace(TRACE_ISCSI_ARGS, "Status:            %u\n", cmd->status);
1474	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1475	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->task_tag);
1476	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:    %u\n", cmd->res_count);
1477	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", cmd->StatSN);
1478	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", cmd->ExpCmdSN);
1479	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", cmd->MaxCmdSN);
1480	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:            %u\n", cmd->DataSN);
1481	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset      %u\n", cmd->offset);
1482	return 0;
1483}
1484
1485/*
1486 * Reject
1487 */
1488
1489int
1490iscsi_reject_encap(uint8_t *header, iscsi_reject_t * cmd)
1491{
1492
1493	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:   %u\n", cmd->reason);
1494	iscsi_trace(TRACE_ISCSI_ARGS, "Length:   %u\n", cmd->length);
1495	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:   %u\n", cmd->StatSN);
1496	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN: %u\n", cmd->ExpCmdSN);
1497	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN: %u\n", cmd->MaxCmdSN);
1498	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:   %u\n", cmd->DataSN);
1499
1500	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1501
1502	header[0] |= 0x00 | ISCSI_REJECT;	/* Opcode  */
1503	header[1] |= 0x80;
1504	header[2] = cmd->reason;/* Reason */
1505	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length  */
1506	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
1507	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
1508	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
1509	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN */
1510
1511	return 0;
1512}
1513
1514int
1515iscsi_reject_decap(uint8_t *header, iscsi_reject_t * cmd)
1516{
1517	const char	*errmsg;
1518	uint8_t		 zeros[8];
1519
1520	if (ISCSI_OPCODE(header) != ISCSI_REJECT) {
1521		iscsi_err(__FILE__, __LINE__, "Opcode");
1522		return 1;
1523	}
1524	cmd->reason = header[2];/* Reason */
1525	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1526	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
1527	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
1528	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
1529	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN */
1530
1531	errmsg = NULL;
1532	(void) memset(zeros, 0x0, sizeof(zeros));
1533	if ((header[0] & 0xc0) != 0x0) {
1534		errmsg = "Byte 0, bits 0-1";
1535	} else if ((header[1] & 0x7f) != 0x0) {
1536		errmsg = "Byte 1, bits 0-7";
1537	} else if (header[3] != 0) {
1538		errmsg = "Byte 3";
1539	} else if (header[4] != 0) {
1540		errmsg = "Byte 4";
1541	} else if (memcmp(header + 8, zeros, 8) != 0) {
1542		errmsg = "Bytes 8-15";
1543	} else if (memcmp(header + 20, zeros, 4) != 0) {
1544		errmsg = "Bytes 20-23";
1545	} else if (memcmp(header + 40, zeros, 8) != 0) {
1546		errmsg = "Bytes 40-47";
1547	}
1548	if (errmsg) {
1549		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1550		NO_CLEANUP;
1551		return 1;
1552	}
1553	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:   %u\n", cmd->reason);
1554	iscsi_trace(TRACE_ISCSI_ARGS, "Length:   %u\n", cmd->length);
1555	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:   %u\n", cmd->StatSN);
1556	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN: %u\n", cmd->ExpCmdSN);
1557	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN: %u\n", cmd->MaxCmdSN);
1558	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:   %u\n", cmd->DataSN);
1559	return 0;
1560}
1561
1562int
1563iscsi_amsg_decap(uint8_t *header, iscsi_async_msg_t * msg)
1564{
1565
1566	if (ISCSI_OPCODE(header) != ISCSI_ASYNC) {
1567		iscsi_err(__FILE__, __LINE__, "Opcode");
1568		return 1;
1569	}
1570	msg->AHSlength = header[4];	/* TotalAHSLength */
1571	msg->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1572	msg->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8)));	/* LUN  */
1573	msg->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
1574	msg->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
1575	msg->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1576	msg->AsyncEvent = header[36];	/* Async Event */
1577	msg->AsyncVCode = header[37];	/* Async Vendor Code */
1578
1579	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", msg->AHSlength);
1580	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", msg->length);
1581	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", msg->lun);
1582	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", msg->StatSN);
1583	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", msg->ExpCmdSN);
1584	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", msg->MaxCmdSN);
1585	iscsi_trace(TRACE_ISCSI_ARGS, "AsyncEvent:      %u\n", msg->AsyncEvent);
1586	iscsi_trace(TRACE_ISCSI_ARGS, "AsyncVCode:     %u\n", msg->AsyncVCode);
1587
1588	return 0;
1589}
1590