xref: /netbsd-src/sys/dev/iscsi/iscsi_globals.h (revision 325dc460fcb903ba21d515d6422d8abf39bc692e)
1 /*	$NetBSD: iscsi_globals.h,v 1.27 2022/09/13 13:09:16 mlelstv Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #ifndef _ISCSI_GLOBALS_H
32 #define _ISCSI_GLOBALS_H
33 
34 /*#include "opt_ddb.h" */
35 #define DDB 1
36 
37 /* Includes we need in all files */
38 
39 #include <sys/param.h>
40 #include <sys/mutex.h>
41 #include <sys/rwlock.h>
42 #include <sys/proc.h>
43 #include <sys/conf.h>
44 #include <sys/errno.h>
45 #include <sys/malloc.h>
46 #include <sys/scsiio.h>
47 #include <sys/kernel.h>
48 #include <sys/kthread.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 
52 #include <dev/scsipi/scsi_all.h>
53 #include <dev/scsipi/scsi_message.h>
54 #include <dev/scsipi/scsipi_all.h>
55 #include <dev/scsipi/scsiconf.h>
56 #include <dev/scsipi/scsipiconf.h>
57 
58 #include "iscsi.h"
59 #include "iscsi_pdu.h"
60 #include "iscsi_ioctl.h"
61 
62 /* ------------------------ Code selection constants ------------------------ */
63 
64 #define ISCSI_DEBUG      0
65 
66 /* -------------------------  Global Constants  ----------------------------- */
67 
68 /* Version information */
69 
70 #define INTERFACE_VERSION	2
71 #define VERSION_MAJOR		3
72 #define VERSION_MINOR		1
73 #define VERSION_STRING		"NetBSD iSCSI Software Initiator 20110407"
74 
75 /*
76    NOTE: CCBS_PER_SESSION must not exceed 256 due to the way the ITT
77    is constructed (it has the CCB index in its lower 8 bits). If it should ever
78    be necessary to increase the number beyond that (which isn't expected),
79    the corresponding ITT generation and extraction code must be rewritten.
80 */
81 #define CCBS_PER_SESSION      32	/* ToDo: Reasonable number?? */
82 /*
83    NOTE: CCBS_FOR_SCSPI limits the number of outstanding commands for
84    SCSI commands, leaving some CCBs for keepalive and logout attempts,
85    which are needed for each connection.
86 */
87 #define CCBS_FOR_SCSIPI       16	/* ToDo: Reasonable number?? */
88 /*
89    NOTE: PDUS_PER_CONNECTION is a number that could potentially impact
90    performance if set too low, as a single command may use up a lot of PDUs for
91    high values of First/MaxBurstLength and small values of
92    MaxRecvDataSegmentLength of the target.
93 */
94 #define PDUS_PER_CONNECTION   64	/* ToDo: Reasonable number?? */
95 
96 /* max outstanding serial nums before we give up on the connection */
97 #define SERNUM_BUFFER_LENGTH  (CCBS_PER_SESSION / 2)	/* ToDo: Reasonable?? */
98 
99 /* The RecvDataSegmentLength for Target->Initiator */
100 #define DEFAULT_MaxRecvDataSegmentLength     (64*1024)
101 
102 /* Command timeout (reset on received PDU associated with the command's CCB) */
103 #define COMMAND_TIMEOUT		(60 * hz) /* ToDo: Reasonable? (60 seconds) */
104 #define MAX_CCB_TIMEOUTS	3		/* Max number of tries to resend or SNACK */
105 #define MAX_CCB_TRIES		9      	/* Max number of total tries to recover */
106 
107 /* Connectionn timeout (reset on every valid received PDU) */
108 #define CONNECTION_TIMEOUT       (2 * hz)	/* ToDo: Reasonable? (2 seconds) */
109 #define CONNECTION_IDLE_TIMEOUT  (30 * hz)	/* Adjusted to Time2Retain/2 later */
110 #define MAX_CONN_TIMEOUTS        4	/* Max number of tries to ping a target */
111 
112 /* Maximum attempts to recover connection */
113 #define MAX_RECOVERY_ATTEMPTS	2	/* If two attempts don't work, something */
114 									/* probably is seriously broken */
115 
116 /* PDU flags */
117 
118 #define PDUF_BUSY	0x01	/* PDU is being sent, don't re-send */
119 #define PDUF_INQUEUE	0x02	/* PDU is in send queue */
120 #define PDUF_PRIORITY	0x04	/* Insert PDU at head of queue */
121 #define PDUF_NOUPDATE	0x10	/* Do not update PDU header/digest (test mode) */
122 
123 /* CCB Flags */
124 
125 #define CCBF_COMPLETE   0x0001	/* received status */
126 #define CCBF_RESENT     0x0002	/* ccb was resent */
127 #define CCBF_SENDTARGET 0x0004	/* SendTargets text request, not negotiation */
128 #define CCBF_GOT_RSP    0x0010	/* Got at least one response to this request */
129 #define CCBF_REASSIGN   0x0020	/* Command can be reassigned */
130 #define CCBF_OTHERCONN  0x0040	/* a logout for a different connection */
131 #define CCBF_WAITQUEUE  0x0080	/* CCB is on waiting queue */
132 
133 /* ---------------------------  Global Types  ------------------------------- */
134 
135 /* Connection state */
136 
137 typedef enum {
138 	/* first three correspond to CSG/NSG coding */
139 	ST_SEC_NEG	= 0,	/* security negotiation phase */
140 	ST_OP_NEG	= 1,	/* operational negotiation phase */
141 	ST_FULL_FEATURE	= 3,	/* full feature phase */
142 	/* rest is internal */
143 	ST_WINDING_DOWN	= 4,	/* connection termination initiated, logging out */
144 	ST_LOGOUT_SENT	= 5,	/* logout has been sent */
145 	ST_SETTLING	= 6,	/* waiting for things to settle down */
146 	ST_IDLE		= 7	/* connection is idle (ready to delete) */
147 } conn_state_t;
148 
149 
150 /* Logout state */
151 
152 typedef enum {
153 	NOT_LOGGED_OUT,				/* Not logged out */
154 	LOGOUT_SENT,				/* Logout was sent */
155 	LOGOUT_SUCCESS,				/* Logout succeeded */
156 	LOGOUT_FAILED				/* Logout failed */
157 } logout_state_t;
158 
159 
160 /* CCB Disposition */
161 
162 typedef enum {
163 	CCBDISP_UNUSED,	/* 0 = In free pool */
164 	CCBDISP_BUSY,	/* This CCB is busy, don't allow rx ops */
165 	CCBDISP_NOWAIT,	/* Not waiting for anything */
166 	CCBDISP_FREE,	/* Free this CCB when done */
167 	CCBDISP_WAIT,	/* Calling thread is waiting for completion */
168 	CCBDISP_SCSIPI,	/* Call scsipi_done when operation completes */
169 	CCBDISP_DEFER	/* Defer waiting until all PDUs have been queued */
170 } ccb_disp_t;
171 
172 
173 /* PDU Disposition */
174 
175 typedef enum {
176 	PDUDISP_UNUSED,		/* 0 = In free pool */
177 	PDUDISP_FREE,		/* Free this PDU when done */
178 	PDUDISP_WAIT		/* Waiting for acknowledge */
179 } pdu_disp_t;
180 
181 /* Timeout state */
182 
183 typedef enum {
184 	TOUT_NONE,		/* Initial */
185 	TOUT_ARMED,		/* callout is scheduled */
186 	TOUT_QUEUED,		/* put into timeout queue */
187 	TOUT_BUSY		/* cleanup thread working */
188 } tout_state_t;
189 
190 typedef struct connection_s connection_t;
191 typedef struct session_s session_t;
192 typedef struct ccb_s ccb_t;
193 typedef struct pdu_s pdu_t;
194 
195 /* the serial number management structure (a circular buffer) */
196 
197 typedef struct {
198 	uint32_t	ExpSN;	/* ExpxxSN (Data or Stat) sent to the target */
199 	uint32_t	next_sn; /* next_sn (== ExpSN if no ack is pending) */
200 	int		top;	/* top of buffer (newest element) */
201 	int		bottom;	/* bottom of buffer (oldest element) */
202 	uint32_t	sernum[SERNUM_BUFFER_LENGTH];	/* the serial numbers */
203 	bool		ack[SERNUM_BUFFER_LENGTH];	/* acknowledged? */
204 } sernum_buffer_t;
205 
206 
207 /*
208    The per-PDU data structure.
209 */
210 
211 struct pdu_s {
212 	TAILQ_ENTRY(pdu_s)	pdu_chain;	/* freelist or wait list (or no list) */
213 	TAILQ_ENTRY(pdu_s)	pdu_send_chain;
214 				/* chaining PDUs waiting to be sent */
215 	pdu_disp_t		pdu_disp; /* what to do with this pdu */
216 	uint32_t		pdu_flags; 	/* various processing flags */
217 	pdu_header_t		pdu_hdr; /* Buffer for PDU associated with cmd */
218 	void			*pdu_temp_data; /* (free after use) */
219 	uint32_t		pdu_temp_data_len;	/* size of temp data */
220 
221 	struct uio		pdu_uio; /* UIO structure */
222 	struct iovec		pdu_io_vec[4];
223 				/* Header + data + data-digest + padding */
224 
225 	struct uio		pdu_save_uio;
226 				/* UIO structure save for retransmits */
227 	struct iovec		pdu_save_iovec[4];
228 				/* Header + data + data-digest + padding */
229 	uint32_t		pdu_data_digest;
230 				/* holds data digest if enabled */
231 	ccb_t			*pdu_owner;
232 				/* the ccb this PDU belongs to (if any) */
233 	connection_t		*pdu_connection;
234 				/* the connection this PDU belongs to */
235 };
236 
237 
238 /* the PDU list type */
239 
240 TAILQ_HEAD(pdu_list_s, pdu_s);
241 typedef struct pdu_list_s pdu_list_t;
242 
243 /*
244    The per-command data structure. Calling it ccb in correspondence
245    to other HA drivers.
246 */
247 
248 struct ccb_s {
249 	TAILQ_ENTRY(ccb_s)	ccb_chain;
250 	/* either freelist or waiting list (or no list) */
251 
252 	uint32_t		ccb_status; /* Status gets entered here */
253 	ccb_disp_t		ccb_disp;	/* what to do with this ccb */
254 
255 	struct callout		ccb_timeout; /* To make sure it isn't lost */
256 	TAILQ_ENTRY(ccb_s)	ccb_tchain;
257 	tout_state_t		ccb_timedout;
258 	int			ccb_num_timeouts;
259 	/* How often we've sent out SNACK without answer */
260 	int			ccb_total_tries;
261 	/* How often we've tried to recover */
262 
263 	uint32_t		ccb_ITT;
264 	/* task tag: ITT counter + sess id + CCB index */
265 	sernum_buffer_t		ccb_DataSN_buf;
266 	/* Received Data Seq nums (read ops only) */
267 
268 	void			*ccb_par;
269 	/* misc. parameter for this request */
270 	struct scsipi_xfer	*ccb_xs;
271 	/* the scsipi_xfer for this cmd */
272 
273 	void			*ccb_temp_data;
274 	/* to hold state (mainly during negotiation) */
275 	void			*ccb_text_data;
276 	/* holds accumulated text for continued PDUs */
277 	uint32_t		ccb_text_len;
278 	/* length of text data so far */
279 
280 	uint64_t		ccb_lun; /* LUN */
281 	uint32_t		ccb_tag; /* Command tag */
282 	uint8_t			*ccb_cmd; /* SCSI command block */
283 	uint16_t		ccb_cmdlen; /* SCSI command block length */
284 	bool			ccb_data_in; /* if this is a read request */
285 	uint8_t			*ccb_data_ptr; /* data pointer for read/write */
286 	uint32_t		ccb_data_len; /* total data length */
287 	uint32_t		ccb_xfer_len; /* data transferred on read */
288 	uint32_t		ccb_residual; /* residual data size */
289 
290 	void			*ccb_sense_ptr; /* sense data pointer */
291 	int			ccb_sense_len_req; /* requested sense data length */
292 	int			ccb_sense_len_got; /* actual sense data length */
293 
294 	pdu_t			*ccb_pdu_waiting; /* PDU waiting to be ack'ed */
295 	volatile uint32_t	ccb_CmdSN; /* CmdSN associated with waiting PDU */
296 
297 	int			ccb_flags;
298 	connection_t		*ccb_connection; /* connection for CCB */
299 	session_t		*ccb_session; /* session for CCB */
300 };
301 
302 
303 /* the CCB list type */
304 
305 TAILQ_HEAD(ccb_list_s, ccb_s);
306 typedef struct ccb_list_s ccb_list_t;
307 
308 
309 /*
310    Per connection data: the connection structure
311 */
312 struct connection_s {
313 	TAILQ_ENTRY(connection_s)	c_connections;
314 
315 	kmutex_t			c_lock;
316 	kcondvar_t			c_conn_cv;
317 	kcondvar_t			c_pdu_cv;
318 	kcondvar_t			c_ccb_cv;
319 	kcondvar_t			c_idle_cv;
320 
321 	pdu_list_t			c_pdu_pool; /* the free PDU pool */
322 
323 	ccb_list_t			c_ccbs_waiting;
324 					/* CCBs waiting for completion */
325 
326 	pdu_list_t			c_pdus_to_send;
327 					/* the PDUs waiting to be sent */
328 
329 	sernum_buffer_t			c_StatSN_buf;
330 					/* to keep track of received StatSNs */
331 
332 	uint32_t			c_max_transfer;
333 		/* min(MaxRecvDataSegmentLength, MaxBurstLength) */
334 	uint32_t			c_max_firstimmed;
335 		/* 0 if InitialR2T=Yes, else
336 		   min of (MaxRecvDataSegmentLength, FirstBurstLength) */
337 	uint32_t			c_max_firstdata;
338 		/* 0 if ImmediateData=No, else min of */
339 		/* (MaxRecvDataSegmentLength, FirstBurstLength) */
340 
341 	uint32_t			c_MaxRecvDataSegmentLength;
342 					/* Target's value */
343 	uint32_t			c_Our_MaxRecvDataSegmentLength;
344 					/* Our own value */
345 	bool				c_HeaderDigest;	/* TRUE if doing CRC */
346 	bool				c_DataDigest;	/* TRUE if doing CRC */
347 	uint32_t			c_Time2Wait;
348 					/* Negotiated default or logout value */
349 	uint32_t			c_Time2Retain;
350 					/* Negotiated default or logout value */
351 
352 	uint16_t			c_id;
353 		/* connection ID (unique within session) */
354 
355 	conn_state_t			c_state; /* State of connection */
356 
357 	struct lwp			*c_threadobj;
358 		/* proc/thread pointer of socket owner */
359 
360 	krwlock_t			c_sock_rw;
361 	struct file			*c_sock;	/* the connection's socket */
362 	session_t			*c_session;
363 					/* back pointer to the owning session */
364 
365 	struct lwp			*c_rcvproc; /* receive thread */
366 	struct lwp			*c_sendproc; /* send thread */
367 
368 	uint32_t			c_terminating;
369 					/* if closing down: status */
370 	int				c_recover; /* recovery count */
371 		/* (reset on first successful data transfer) */
372 	volatile unsigned		c_usecount; /* number of active CCBs */
373 	unsigned			c_pducount; /* number of active PDUs */
374 
375 	bool				c_destroy; /* conn will be destroyed */
376 	bool				c_in_session;
377 		/* if it's linked into the session list */
378 	logout_state_t			c_loggedout;
379 		/* status of logout (for recovery) */
380 	struct callout			c_timeout;
381 		/* Timeout for checking if connection is dead */
382 	TAILQ_ENTRY(connection_s)	c_tchain;
383 	tout_state_t			c_timedout;
384 	int				c_num_timeouts;
385 		/* How often we've sent out a NOP without answer */
386 	uint32_t			c_idle_timeout_val;
387 		/* Connection timeout value when idle */
388 
389 	iscsi_login_parameters_t	*c_login_par;
390 					/* only valid during login */
391 
392 	pdu_t				c_pdu[PDUS_PER_CONNECTION]; /* PDUs */
393 };
394 
395 /* the connection list type */
396 
397 TAILQ_HEAD(connection_list_s, connection_s);
398 typedef struct connection_list_s connection_list_t;
399 
400 
401 /*
402    Per session data: the session structure
403 */
404 
405 struct session_s {
406 	/* Interface to child drivers.
407 	   NOTE: sc_adapter MUST be the first field in this structure so we can
408 	   easily get from adapter to session.
409 	 */
410 	struct scsipi_adapter	s_sc_adapter;
411 	struct scsipi_channel	s_sc_channel;
412 
413 	device_t		s_child_dev;
414 	/* the child we're associated with - (NULL if not mapped) */
415 
416 	int			s_refcount;	/* session in use by scsipi */
417 
418 	/* local stuff */
419 	TAILQ_ENTRY(session_s)	s_sessions;	/* the list of sessions */
420 
421 	kmutex_t		s_lock;
422 	kcondvar_t		s_sess_cv;
423 	kcondvar_t		s_ccb_cv;
424 
425 	ccb_list_t		s_ccb_pool;	/* The free CCB pool */
426 
427 	int			s_send_window;
428 
429 	uint16_t		s_id;	/* session ID (unique within driver) */
430 	uint16_t		s_TSIH;	/* Target assigned session ID */
431 
432 	uint32_t		s_CmdSN;	 /* Current CmdSN */
433 	uint32_t		s_ExpCmdSN; /* Current max ExpCmdSN received */
434 	uint32_t		s_MaxCmdSN; /* Current MaxCmdSN */
435 
436 	/* negotiated values */
437 	uint32_t		s_ErrorRecoveryLevel;
438 	uint32_t		s_FirstBurstLength;
439 	uint32_t		s_MaxBurstLength;
440 	bool			s_ImmediateData;
441 	bool			s_InitialR2T;
442 	uint32_t		s_MaxOutstandingR2T;
443 	uint32_t		s_MaxConnections;
444 	uint32_t		s_DefaultTime2Wait;
445 	uint32_t		s_DefaultTime2Retain;
446 
447 	iscsi_login_session_type_t s_login_type;	/* session type */
448 
449 	/* for send_targets requests */
450 	uint8_t			*s_target_list;
451 	uint32_t		s_target_list_len;
452 
453 	uint32_t		s_conn_id;	/* connection ID counter */
454 
455 	uint32_t		s_terminating;	/* if closing down: status */
456 
457 	uint32_t		s_active_connections;
458 				/* currently active connections */
459 	uint32_t		s_total_connections;
460 	/* connections associated with this session (active or winding down) */
461 	connection_list_t	s_conn_list;	/* the list of connections */
462 	connection_t		*s_mru_connection;
463 				/* the most recently used connection */
464 
465 	ccb_t			s_ccb[CCBS_PER_SESSION];	/* CCBs */
466 
467 	char			s_tgtname[ISCSI_STRING_LENGTH + 1];
468 				/* iSCSI target name */
469 };
470 
471 /* the session list type */
472 
473 TAILQ_HEAD(session_list_s, session_s);
474 typedef struct session_list_s session_list_t;
475 
476 
477 /*
478    Event notification structures
479 */
480 
481 typedef struct event_s {
482 	TAILQ_ENTRY(event_s)	ev_link;	/* next event in queue */
483 	iscsi_event_t		ev_event_kind;	/* which event */
484 	uint32_t		ev_session_id;	/* affected session ID */
485 	uint32_t		ev_connection_id;/* affected connection ID */
486 	uint32_t		ev_reason;		/* event reason */
487 } event_t;
488 
489 /* the event list entry type */
490 
491 TAILQ_HEAD(event_list_s, event_s);
492 typedef struct event_list_s event_list_t;
493 
494 
495 typedef struct event_handler_s {
496 	TAILQ_ENTRY(event_handler_s)	evh_link;	/* next handler */
497 	uint32_t			evh_id;	/* unique ID */
498 	event_list_t			evh_events;	/* list of events pending */
499 	iscsi_wait_event_parameters_t	*evh_waiter; /* waiting parameter */
500 	/* following to detect dead handlers */
501 	event_t				*evh_first_in_list;
502 } event_handler_t;
503 
504 /* the event list entry type */
505 
506 TAILQ_HEAD(event_handler_list_s, event_handler_s);
507 typedef struct event_handler_list_s event_handler_list_t;
508 
509 /* /dev/iscsi0 state */
510 struct iscsifd {
511 	TAILQ_ENTRY(iscsifd)		fd_link;
512 	device_t	fd_dev;
513 	int		fd_unit;
514 };
515 
516 /* -------------------------  Global Variables  ----------------------------- */
517 
518 /* In iscsi_main.c */
519 
520 extern struct cfattach iscsi_ca;		/* the device attach structure */
521 
522 extern session_list_t iscsi_sessions;		/* the list of sessions */
523 extern bool iscsi_detaching;			/* signal to cleanup thread it should exit */
524 extern uint32_t iscsi_num_send_threads;		/* the number of active send threads */
525 
526 extern uint8_t iscsi_InitiatorName[ISCSI_STRING_LENGTH];
527 extern uint8_t iscsi_InitiatorAlias[ISCSI_STRING_LENGTH];
528 extern login_isid_t iscsi_InitiatorISID;
529 
530 /* Debugging stuff */
531 
532 #ifndef DDB
533 #define Debugger() panic("should call debugger here (iscsi.c)")
534 #endif /* ! DDB */
535 
536 #ifdef ISCSI_DEBUG
537 
538 extern int iscsi_debug_level;	/* How much debug info to display */
539 extern bool iscsi_hex_bignums;	/* Whether to encode parameters in hex or base64 */
540 
541 #define DEBOUT(x) printf x
542 #define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;}
543 #define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
544 			conn && conn->c_session ? conn->c_session->s_id : -1, \
545 			conn ? conn->c_id : -1); printf x ;}}
546 
547 #define STATIC static
548 
549 #else
550 
551 #define DEBOUT(x)
552 #define DEB(lev,x)
553 #define DEBC(conn,lev,x)
554 
555 #define STATIC static
556 
557 #endif
558 
559 /* Critical section macros */
560 
561 /* misc stuff */
562 #define min(a, b) ((a) < (b)) ? (a) : (b)
563 #define max(a, b) ((a) < (b)) ? (b) : (a)
564 
565 
566 /*
567    Convert unsigned int to 3-byte value (for DataSegmentLength field in PDU)
568 */
569 
570 static __inline void
571 hton3(uint32_t val, uint8_t *bytes)
572 {
573 	bytes[0] = (uint8_t) (val >> 16);
574 	bytes[1] = (uint8_t) (val >> 8);
575 	bytes[2] = (uint8_t) val;
576 }
577 
578 /*
579    Convert 3-byte value to unsigned int (for DataSegmentLength field in PDU)
580 */
581 
582 static __inline uint32_t
583 ntoh3(uint8_t *bytes)
584 {
585 	return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
586 }
587 
588 
589 /*
590  * Convert uint64 to network byte order (for LUN field in PDU)
591 */
592 static __inline uint64_t
593 htonq(uint64_t x)
594 {
595 #if BYTE_ORDER == LITTLE_ENDIAN
596 	uint8_t *s = (uint8_t *) & x;
597 	return (uint64_t) ((uint64_t) s[0] << 56 | (uint64_t) s[1] << 48 |
598 			(uint64_t) s[2] << 40 | (uint64_t) s[3] << 32 |
599 			(uint64_t) s[4] << 24 | (uint64_t) s[5] << 16 |
600 			(uint64_t) s[6] <<  8 | (uint64_t) s[7]);
601 #else
602 	return x;
603 #endif
604 }
605 
606 #define ntohq(x) htonq(x)
607 
608 /*
609  * Serial number buffer empty?
610 */
611 
612 static __inline bool
613 sn_empty(sernum_buffer_t *buf)
614 {
615 	return buf->top == buf->bottom;
616 }
617 
618 
619 /*
620  * Serial number compare
621 */
622 
623 static __inline bool
624 sn_a_lt_b(uint32_t a, uint32_t b)
625 {
626 	return (a < b && !((b - a) & 0x80000000)) ||
627 	       (a > b && ((a - b) & 0x80000000));
628 }
629 
630 static __inline bool
631 sn_a_le_b(uint32_t a, uint32_t b)
632 {
633 	return (a <= b && !((b - a) & 0x80000000)) ||
634 	       (a >= b && ((a - b) & 0x80000000));
635 }
636 
637 /* in iscsi_ioctl.c */
638 
639 void iscsi_init_cleanup(void);
640 int iscsi_destroy_cleanup(void);
641 void iscsi_notify_cleanup(void);
642 
643 
644 /* Parameter for logout is reason code in logout PDU, -1 for don't send logout */
645 #define NO_LOGOUT          -1
646 #define LOGOUT_SESSION     0
647 #define LOGOUT_CONNECTION  1
648 #define RECOVER_CONNECTION 2
649 
650 void add_event(iscsi_event_t, uint32_t, uint32_t, uint32_t);
651 
652 void kill_connection(connection_t *, uint32_t, int, bool);
653 void kill_session(uint32_t, uint32_t, int, bool);
654 int kill_all_sessions(void);
655 void handle_connection_error(connection_t *, uint32_t, int);
656 void add_connection_cleanup(connection_t *);
657 
658 int iscsiioctl(struct file *, u_long, void *);
659 
660 session_t *find_session(uint32_t);
661 connection_t *find_connection(session_t *, uint32_t);
662 int ref_session(session_t *);
663 void unref_session(session_t *);
664 
665 /* in iscsi_main.c */
666 
667 /*void iscsiattach(void *); */
668 int iscsidetach(device_t, int);
669 
670 void iscsi_done(ccb_t *);
671 int map_session(session_t *, device_t);
672 int unmap_session(session_t *);
673 
674 /* in iscsi_send.c */
675 
676 void iscsi_send_thread(void *);
677 
678 connection_t *assign_connection(session_t *session, bool waitok);
679 void resend_pdu(ccb_t *);
680 int send_login(connection_t *);
681 int send_logout(connection_t *, connection_t *, int, bool);
682 int send_data_out(connection_t *, pdu_t *, ccb_t *, ccb_disp_t, bool);
683 void send_run_xfer(session_t *, struct scsipi_xfer *);
684 int send_send_targets(session_t *, uint8_t *);
685 int send_task_management(connection_t *, ccb_t *, struct scsipi_xfer *, int);
686 
687 void negotiate_login(connection_t *, pdu_t *, ccb_t *);
688 void acknowledge_text(connection_t *, pdu_t *, ccb_t *);
689 void start_text_negotiation(connection_t *);
690 void negotiate_text(connection_t *, pdu_t *, ccb_t *);
691 int send_nop_out(connection_t *, pdu_t *);
692 void snack_missing(connection_t *, ccb_t *, uint8_t, uint32_t, uint32_t);
693 void send_snack(connection_t *, pdu_t *, ccb_t *, uint8_t);
694 int send_send_targets(session_t *, uint8_t *);
695 
696 void send_command(ccb_t *, ccb_disp_t, bool, bool);
697 #ifndef ISCSI_MINIMAL
698 int send_io_command(session_t *, uint64_t, scsireq_t *, bool, uint32_t);
699 #endif
700 
701 void connection_timeout_co(void *);
702 void ccb_timeout_co(void *);
703 
704 void connection_timeout(connection_t *);
705 void connection_timeout_start(connection_t *, int);
706 void connection_timeout_stop(connection_t *);
707 void ccb_timeout(ccb_t *);
708 void ccb_timeout_start(ccb_t *, int);
709 void ccb_timeout_stop(ccb_t *);
710 
711 /* in iscsi_rcv.c */
712 
713 void iscsi_rcv_thread(void *);
714 
715 /* in iscsi_utils.c */
716 
717 uint32_t gen_digest(const void *, size_t);
718 uint32_t gen_digest_2(const void *, size_t, const void *, size_t);
719 
720 void create_ccbs(session_t *);
721 void destroy_ccbs(session_t *);
722 ccb_t *get_ccb(connection_t *, bool);
723 void free_ccb(ccb_t *);
724 void suspend_ccb(ccb_t *, bool);
725 void wake_ccb(ccb_t *, uint32_t);
726 
727 void create_pdus(connection_t *);
728 pdu_t *get_pdu(connection_t *, bool);
729 void free_pdu(pdu_t *);
730 
731 void init_sernum(sernum_buffer_t *);
732 int add_sernum(sernum_buffer_t *, uint32_t);
733 uint32_t ack_sernum(sernum_buffer_t *, uint32_t);
734 
735 uint32_t get_sernum(session_t *, pdu_t *);
736 int sernum_in_window(session_t *);
737 int window_size(session_t *, int);
738 
739 /* in iscsi_text.c */
740 
741 int assemble_login_parameters(connection_t *, ccb_t *, pdu_t *);
742 int assemble_security_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
743 int assemble_negotiation_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
744 int init_text_parameters(connection_t *, ccb_t *);
745 int assemble_send_targets(pdu_t *, uint8_t *);
746 void set_negotiated_parameters(ccb_t *);
747 
748 #endif /* !_ISCSI_GLOBALS_H */
749