Home | History | Annotate | Line # | Download | only in iscsi
iscsi_globals.h revision 1.22
      1 /*	$NetBSD: iscsi_globals.h,v 1.22 2017/02/05 12:05:46 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/proc.h>
     41 #include <sys/conf.h>
     42 #include <sys/errno.h>
     43 #include <sys/malloc.h>
     44 #include <sys/scsiio.h>
     45 #include <sys/kernel.h>
     46 #include <sys/kthread.h>
     47 #include <sys/systm.h>
     48 #include <sys/device.h>
     49 
     50 #include <dev/scsipi/scsi_all.h>
     51 #include <dev/scsipi/scsi_message.h>
     52 #include <dev/scsipi/scsipi_all.h>
     53 #include <dev/scsipi/scsiconf.h>
     54 #include <dev/scsipi/scsipiconf.h>
     55 
     56 #include "iscsi.h"
     57 #include "iscsi_pdu.h"
     58 #include "iscsi_ioctl.h"
     59 
     60 /* ------------------------ Code selection constants ------------------------ */
     61 
     62 #define ISCSI_DEBUG      0
     63 
     64 /* -------------------------  Global Constants  ----------------------------- */
     65 
     66 /* Version information */
     67 
     68 #define INTERFACE_VERSION	2
     69 #define VERSION_MAJOR		3
     70 #define VERSION_MINOR		1
     71 #define VERSION_STRING		"NetBSD iSCSI Software Initiator 20110407"
     72 
     73 /*
     74    NOTE: CCBS_PER_SESSION must not exceed 256 due to the way the ITT
     75    is constructed (it has the CCB index in its lower 8 bits). If it should ever
     76    be necessary to increase the number beyond that (which isn't expected),
     77    the corresponding ITT generation and extraction code must be rewritten.
     78 */
     79 #define CCBS_PER_SESSION      32	/* ToDo: Reasonable number?? */
     80 /*
     81    NOTE: CCBS_FOR_SCSPI limits the number of outstanding commands for
     82    SCSI commands, leaving some CCBs for keepalive and logout attempts,
     83    which are needed for each connection.
     84 */
     85 #define CCBS_FOR_SCSIPI       16	/* ToDo: Reasonable number?? */
     86 /*
     87    NOTE: PDUS_PER_CONNECTION is a number that could potentially impact
     88    performance if set too low, as a single command may use up a lot of PDUs for
     89    high values of First/MaxBurstLength and small values of
     90    MaxRecvDataSegmentLength of the target.
     91 */
     92 #define PDUS_PER_CONNECTION   64	/* ToDo: Reasonable number?? */
     93 
     94 /* max outstanding serial nums before we give up on the connection */
     95 #define SERNUM_BUFFER_LENGTH  (CCBS_PER_SESSION / 2)	/* ToDo: Reasonable?? */
     96 
     97 /* The RecvDataSegmentLength for Target->Initiator */
     98 #define DEFAULT_MaxRecvDataSegmentLength     (64*1024)
     99 
    100 /* Command timeout (reset on received PDU associated with the command's CCB) */
    101 #define COMMAND_TIMEOUT		(60 * hz) /* ToDo: Reasonable? (60 seconds) */
    102 #define MAX_CCB_TIMEOUTS	3		/* Max number of tries to resend or SNACK */
    103 #define MAX_CCB_TRIES		9      	/* Max number of total tries to recover */
    104 
    105 /* Connectionn timeout (reset on every valid received PDU) */
    106 #define CONNECTION_TIMEOUT       (2 * hz)	/* ToDo: Reasonable? (2 seconds) */
    107 #define CONNECTION_IDLE_TIMEOUT  (30 * hz)	/* Adjusted to Time2Retain/2 later */
    108 #define MAX_CONN_TIMEOUTS        4	/* Max number of tries to ping a target */
    109 
    110 /* Maximum attempts to recover connection */
    111 #define MAX_RECOVERY_ATTEMPTS	2	/* If two attempts don't work, something */
    112 									/* probably is seriously broken */
    113 
    114 /* PDU flags */
    115 
    116 #define PDUF_BUSY	0x01	/* PDU is being sent, don't re-send */
    117 #define PDUF_INQUEUE	0x02	/* PDU is in send queue */
    118 #define PDUF_PRIORITY	0x04	/* Insert PDU at head of queue */
    119 #define PDUF_NOUPDATE	0x10	/* Do not update PDU header/digest (test mode) */
    120 
    121 /* CCB Flags */
    122 
    123 #define CCBF_COMPLETE   0x0001	/* received status */
    124 #define CCBF_RESENT     0x0002	/* ccb was resent */
    125 #define CCBF_SENDTARGET 0x0004	/* SendTargets text request, not negotiation */
    126 #define CCBF_GOT_RSP    0x0010	/* Got at least one response to this request */
    127 #define CCBF_REASSIGN   0x0020	/* Command can be reassigned */
    128 #define CCBF_OTHERCONN  0x0040	/* a logout for a different connection */
    129 #define CCBF_WAITQUEUE  0x0080	/* CCB is on waiting queue */
    130 
    131 /* ---------------------------  Global Types  ------------------------------- */
    132 
    133 /* Connection state */
    134 
    135 typedef enum {
    136 	/* first three correspond to CSG/NSG coding */
    137 	ST_SEC_NEG	= 0,	/* security negotiation phase */
    138 	ST_OP_NEG	= 1,	/* operational negotiation phase */
    139 	ST_FULL_FEATURE	= 3,	/* full feature phase */
    140 	/* rest is internal */
    141 	ST_WINDING_DOWN	= 4,	/* connection termination initiated, logging out */
    142 	ST_LOGOUT_SENT	= 5,	/* logout has been sent */
    143 	ST_SETTLING	= 6,	/* waiting for things to settle down */
    144 	ST_IDLE		= 7	/* connection is idle (ready to delete) */
    145 } conn_state_t;
    146 
    147 
    148 /* Logout state */
    149 
    150 typedef enum {
    151 	NOT_LOGGED_OUT,				/* Not logged out */
    152 	LOGOUT_SENT,				/* Logout was sent */
    153 	LOGOUT_SUCCESS,				/* Logout succeeded */
    154 	LOGOUT_FAILED				/* Logout failed */
    155 } logout_state_t;
    156 
    157 
    158 /* CCB Disposition */
    159 
    160 typedef enum {
    161 	CCBDISP_UNUSED,	/* 0 = In free pool */
    162 	CCBDISP_BUSY,	/* This CCB is busy, don't allow rx ops */
    163 	CCBDISP_NOWAIT,	/* Not waiting for anything */
    164 	CCBDISP_FREE,	/* Free this CCB when done */
    165 	CCBDISP_WAIT,	/* Calling thread is waiting for completion */
    166 	CCBDISP_SCSIPI,	/* Call scsipi_done when operation completes */
    167 	CCBDISP_DEFER	/* Defer waiting until all PDUs have been queued */
    168 } ccb_disp_t;
    169 
    170 
    171 /* PDU Disposition */
    172 
    173 typedef enum {
    174 	PDUDISP_UNUSED,		/* 0 = In free pool */
    175 	PDUDISP_FREE,		/* Free this PDU when done */
    176 	PDUDISP_WAIT		/* Waiting for acknowledge */
    177 } pdu_disp_t;
    178 
    179 /* Timeout state */
    180 
    181 typedef enum {
    182 	TOUT_NONE,		/* Initial */
    183 	TOUT_ARMED,		/* callout is scheduled */
    184 	TOUT_QUEUED,		/* put into timeout queue */
    185 	TOUT_BUSY		/* cleanup thread working */
    186 } tout_state_t;
    187 
    188 typedef struct connection_s connection_t;
    189 typedef struct session_s session_t;
    190 typedef struct ccb_s ccb_t;
    191 typedef struct pdu_s pdu_t;
    192 
    193 /* the serial number management structure (a circular buffer) */
    194 
    195 typedef struct {
    196 	uint32_t	ExpSN;	/* ExpxxSN (Data or Stat) sent to the target */
    197 	uint32_t	next_sn; /* next_sn (== ExpSN if no ack is pending) */
    198 	int		top;	/* top of buffer (newest element) */
    199 	int		bottom;	/* bottom of buffer (oldest element) */
    200 	uint32_t	sernum[SERNUM_BUFFER_LENGTH];	/* the serial numbers */
    201 	bool		ack[SERNUM_BUFFER_LENGTH];	/* acknowledged? */
    202 } sernum_buffer_t;
    203 
    204 
    205 /*
    206    The per-PDU data structure.
    207 */
    208 
    209 struct pdu_s {
    210 	TAILQ_ENTRY(pdu_s)	chain;	/* freelist or wait list (or no list) */
    211 	TAILQ_ENTRY(pdu_s)	send_chain;
    212 				/* chaining PDUs waiting to be sent */
    213 	pdu_disp_t		disp; /* what to do with this pdu */
    214 	uint32_t		flags; 	/* various processing flags */
    215 	pdu_header_t		pdu; /* Buffer for PDU associated with cmd */
    216 	void			*temp_data; /* (free after use) */
    217 	uint32_t		temp_data_len;	/* size of temp data */
    218 
    219 	struct uio		uio; /* UIO structure */
    220 	struct iovec		io_vec[4];
    221 				/* Header + data + data-digest + padding */
    222 
    223 	struct uio		save_uio;
    224 				/* UIO structure save for retransmits */
    225 	struct iovec		save_iovec[4];
    226 				/* Header + data + data-digest + padding */
    227 	uint32_t		data_digest;
    228 				/* holds data digest if enabled */
    229 	ccb_t			*owner;
    230 				/* the ccb this PDU belongs to (if any) */
    231 	connection_t		*connection;
    232 				/* the connection this PDU belongs to */
    233 };
    234 
    235 
    236 /* the PDU list type */
    237 
    238 TAILQ_HEAD(pdu_list_s, pdu_s);
    239 typedef struct pdu_list_s pdu_list_t;
    240 
    241 /*
    242    The per-command data structure. Calling it ccb in correspondence
    243    to other HA drivers.
    244 */
    245 
    246 struct ccb_s {
    247 	TAILQ_ENTRY(ccb_s)	chain;
    248 	/* either freelist or waiting list (or no list) */
    249 
    250 	uint32_t		status; /* Status gets entered here */
    251 	ccb_disp_t		disp;	/* what to do with this ccb */
    252 
    253 	struct callout		timeout; /* To make sure it isn't lost */
    254 	TAILQ_ENTRY(ccb_s)	tchain;
    255 	tout_state_t		timedout;
    256 	int			num_timeouts;
    257 	/* How often we've sent out SNACK without answer */
    258 	int			total_tries;
    259 	/* How often we've tried to recover */
    260 
    261 	uint32_t		ITT;
    262 	/* task tag: ITT counter + sess id + CCB index */
    263 	sernum_buffer_t		DataSN_buf;
    264 	/* Received Data Seq nums (read ops only) */
    265 
    266 	void			*par;
    267 	/* misc. parameter for this request */
    268 	struct scsipi_xfer	*xs;
    269 	/* the scsipi_xfer for this cmd */
    270 
    271 	void			*temp_data;
    272 	/* to hold state (mainly during negotiation) */
    273 	void			*text_data;
    274 	/* holds accumulated text for continued PDUs */
    275 	uint32_t		text_len;
    276 	/* length of text data so far */
    277 
    278 	uint64_t		lun; /* LUN */
    279 	uint32_t		tag; /* Command tag */
    280 	uint8_t			*cmd; /* SCSI command block */
    281 	uint16_t		cmdlen; /* SCSI command block length */
    282 	bool			data_in; /* if this is a read request */
    283 	uint8_t			*data_ptr; /* data pointer for read/write */
    284 	uint32_t		data_len; /* total data length */
    285 	uint32_t		xfer_len; /* data transferred on read */
    286 	uint32_t		residual; /* residual data size */
    287 
    288 	void			*sense_ptr; /* sense data pointer */
    289 	int			sense_len_req; /* requested sense data length */
    290 	int			sense_len_got; /* actual sense data length */
    291 
    292 	pdu_t			*pdu_waiting; /* PDU waiting to be ack'ed */
    293 	volatile uint32_t	CmdSN; /* CmdSN associated with waiting PDU */
    294 
    295 	int			flags;
    296 	connection_t		*connection; /* connection for CCB */
    297 	session_t		*session; /* session for CCB */
    298 };
    299 
    300 
    301 /* the CCB list type */
    302 
    303 TAILQ_HEAD(ccb_list_s, ccb_s);
    304 typedef struct ccb_list_s ccb_list_t;
    305 
    306 
    307 /*
    308    Per connection data: the connection structure
    309 */
    310 struct connection_s {
    311 	TAILQ_ENTRY(connection_s)	connections;
    312 
    313 	kmutex_t			lock;
    314 	kcondvar_t			conn_cv;
    315 	kcondvar_t			pdu_cv;
    316 	kcondvar_t			ccb_cv;
    317 	kcondvar_t			idle_cv;
    318 
    319 	pdu_list_t			pdu_pool; /* the free PDU pool */
    320 
    321 	ccb_list_t			ccbs_waiting;
    322 					/* CCBs waiting for completion */
    323 
    324 	pdu_list_t			pdus_to_send;
    325 					/* the PDUs waiting to be sent */
    326 
    327 	sernum_buffer_t			StatSN_buf;
    328 					/* to keep track of received StatSNs */
    329 
    330 	uint32_t			max_transfer;
    331 		/* min(MaxRecvDataSegmentLength, MaxBurstLength) */
    332 	uint32_t			max_firstimmed;
    333 		/* 0 if InitialR2T=Yes, else
    334 		   min of (MaxRecvDataSegmentLength, FirstBurstLength) */
    335 	uint32_t			max_firstdata;
    336 		/* 0 if ImmediateData=No, else min of */
    337 		/* (MaxRecvDataSegmentLength, FirstBurstLength) */
    338 
    339 	uint32_t			MaxRecvDataSegmentLength;
    340 					/* Target's value */
    341 	uint32_t			Our_MaxRecvDataSegmentLength;
    342 					/* Our own value */
    343 	bool				HeaderDigest;	/* TRUE if doing CRC */
    344 	bool				DataDigest;	/* TRUE if doing CRC */
    345 	uint32_t			Time2Wait;
    346 					/* Negotiated default or logout value */
    347 	uint32_t			Time2Retain;
    348 					/* Negotiated default or logout value */
    349 
    350 	uint16_t			id;
    351 		/* connection ID (unique within session) */
    352 
    353 	conn_state_t			state; /* State of connection */
    354 
    355 	struct lwp			*threadobj;
    356 		/* proc/thread pointer of socket owner */
    357 	struct file			*sock;	/* the connection's socket */
    358 	session_t			*session;
    359 					/* back pointer to the owning session */
    360 
    361 	struct lwp			*rcvproc; /* receive thread */
    362 	struct lwp			*sendproc; /* send thread */
    363 
    364 	uint32_t			terminating;
    365 					/* if closing down: status */
    366 	int				recover; /* recovery count */
    367 		/* (reset on first successful data transfer) */
    368 	volatile unsigned		usecount; /* number of active CCBs */
    369 	volatile unsigned		pducount; /* number of active PDUs */
    370 
    371 	bool				destroy; /* conn will be destroyed */
    372 	bool				in_session;
    373 		/* if it's linked into the session list */
    374 	logout_state_t			loggedout;
    375 		/* status of logout (for recovery) */
    376 	struct callout			timeout;
    377 		/* Timeout for checking if connection is dead */
    378 	TAILQ_ENTRY(connection_s)	tchain;
    379 	tout_state_t			timedout;
    380 	int				num_timeouts;
    381 		/* How often we've sent out a NOP without answer */
    382 	uint32_t			idle_timeout_val;
    383 		/* Connection timeout value when idle */
    384 
    385 	iscsi_login_parameters_t	*login_par;
    386 					/* only valid during login */
    387 
    388 	pdu_t				pdu[PDUS_PER_CONNECTION]; /* PDUs */
    389 };
    390 
    391 /* the connection list type */
    392 
    393 TAILQ_HEAD(connection_list_s, connection_s);
    394 typedef struct connection_list_s connection_list_t;
    395 
    396 
    397 /*
    398    Per session data: the session structure
    399 */
    400 
    401 struct session_s {
    402 	/* Interface to child drivers.
    403 	   NOTE: sc_adapter MUST be the first field in this structure so we can
    404 	   easily get from adapter to session.
    405 	 */
    406 	struct scsipi_adapter	sc_adapter;
    407 	struct scsipi_channel	sc_channel;
    408 
    409 	device_t		child_dev;
    410 	/* the child we're associated with - (NULL if not mapped) */
    411 
    412 	int			refcount;	/* session in use by scsipi */
    413 
    414 	/* local stuff */
    415 	TAILQ_ENTRY(session_s)	sessions;	/* the list of sessions */
    416 
    417 	kmutex_t		lock;
    418 	kcondvar_t		sess_cv;
    419 	kcondvar_t		ccb_cv;
    420 
    421 	ccb_list_t		ccb_pool;	/* The free CCB pool */
    422 
    423 	int			send_window;
    424 
    425 	uint16_t		id;	/* session ID (unique within driver) */
    426 	uint16_t		TSIH;	/* Target assigned session ID */
    427 
    428 	uint32_t		CmdSN;	 /* Current CmdSN */
    429 	uint32_t		ExpCmdSN; /* Current max ExpCmdSN received */
    430 	uint32_t		MaxCmdSN; /* Current MaxCmdSN */
    431 
    432 	/* negotiated values */
    433 	uint32_t		ErrorRecoveryLevel;
    434 	uint32_t		FirstBurstLength;
    435 	uint32_t		MaxBurstLength;
    436 	bool			ImmediateData;
    437 	bool			InitialR2T;
    438 	uint32_t		MaxOutstandingR2T;
    439 	uint32_t		MaxConnections;
    440 	uint32_t		DefaultTime2Wait;
    441 	uint32_t		DefaultTime2Retain;
    442 
    443 	iscsi_login_session_type_t login_type;	/* session type */
    444 
    445 	/* for send_targets requests */
    446 	uint8_t			*target_list;
    447 	uint32_t		target_list_len;
    448 
    449 	uint32_t		conn_id;	/* connection ID counter */
    450 
    451 	uint32_t		terminating;	/* if closing down: status */
    452 
    453 	uint32_t		active_connections;
    454 				/* currently active connections */
    455 	uint32_t		total_connections;
    456 	/* connections associated with this session (active or winding down) */
    457 	connection_list_t	conn_list;	/* the list of connections */
    458 	connection_t		*mru_connection;
    459 				/* the most recently used connection */
    460 
    461 	ccb_t			ccb[CCBS_PER_SESSION];		/* CCBs */
    462 
    463 	char			tgtname[ISCSI_STRING_LENGTH + 1];
    464 				/* iSCSI target name */
    465 };
    466 
    467 /* the session list type */
    468 
    469 TAILQ_HEAD(session_list_s, session_s);
    470 typedef struct session_list_s session_list_t;
    471 
    472 
    473 /*
    474    Event notification structures
    475 */
    476 
    477 typedef struct event_s {
    478 	TAILQ_ENTRY(event_s)	link;		/* next event in queue */
    479 	iscsi_event_t		event_kind;	/* which event */
    480 	uint32_t		session_id;	/* affected session ID */
    481 	uint32_t		connection_id;	/* affected connection ID */
    482 	uint32_t		reason;		/* event reason */
    483 } event_t;
    484 
    485 /* the event list entry type */
    486 
    487 TAILQ_HEAD(event_list_s, event_s);
    488 typedef struct event_list_s event_list_t;
    489 
    490 
    491 typedef struct event_handler_s {
    492 	TAILQ_ENTRY(event_handler_s)	link;	/* next handler */
    493 	uint32_t			id;	/* unique ID */
    494 	event_list_t			events;	/* list of events pending */
    495 	iscsi_wait_event_parameters_t	*waiter; /* waiting parameter */
    496 	/* following to detect dead handlers */
    497 	event_t				*first_in_list;
    498 } event_handler_t;
    499 
    500 /* the event list entry type */
    501 
    502 TAILQ_HEAD(event_handler_list_s, event_handler_s);
    503 typedef struct event_handler_list_s event_handler_list_t;
    504 
    505 /* /dev/iscsi0 state */
    506 struct iscsifd {
    507 	TAILQ_ENTRY(iscsifd)		link;
    508 	device_t	dev;
    509 	int		unit;
    510 };
    511 
    512 /* -------------------------  Global Variables  ----------------------------- */
    513 
    514 /* In iscsi_main.c */
    515 
    516 extern struct cfattach iscsi_ca;		/* the device attach structure */
    517 
    518 extern session_list_t iscsi_sessions;		/* the list of sessions */
    519 extern bool iscsi_detaching;			/* signal to cleanup thread it should exit */
    520 extern uint32_t iscsi_num_send_threads;		/* the number of active send threads */
    521 
    522 extern uint8_t iscsi_InitiatorName[ISCSI_STRING_LENGTH];
    523 extern uint8_t iscsi_InitiatorAlias[ISCSI_STRING_LENGTH];
    524 extern login_isid_t iscsi_InitiatorISID;
    525 
    526 /* Debugging stuff */
    527 
    528 #ifndef DDB
    529 #define Debugger() panic("should call debugger here (iscsi.c)")
    530 #endif /* ! DDB */
    531 
    532 #ifdef ISCSI_DEBUG
    533 
    534 extern int iscsi_debug_level;	/* How much debug info to display */
    535 
    536 #define DEBOUT(x) printf x
    537 #define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;}
    538 #define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
    539 				conn ? conn->session->id : -1, \
    540 				conn ? conn->id : -1); printf x ;}}
    541 
    542 #define STATIC static
    543 
    544 #else
    545 
    546 #define DEBOUT(x)
    547 #define DEB(lev,x)
    548 #define DEBC(conn,lev,x)
    549 
    550 #define STATIC static
    551 
    552 #endif
    553 
    554 /* Critical section macros */
    555 
    556 /* misc stuff */
    557 #define min(a, b) ((a) < (b)) ? (a) : (b)
    558 #define max(a, b) ((a) < (b)) ? (b) : (a)
    559 
    560 
    561 /*
    562    Convert unsigned int to 3-byte value (for DataSegmentLength field in PDU)
    563 */
    564 
    565 static __inline void
    566 hton3(uint32_t val, uint8_t *bytes)
    567 {
    568 	bytes[0] = (uint8_t) (val >> 16);
    569 	bytes[1] = (uint8_t) (val >> 8);
    570 	bytes[2] = (uint8_t) val;
    571 }
    572 
    573 /*
    574    Convert 3-byte value to unsigned int (for DataSegmentLength field in PDU)
    575 */
    576 
    577 static __inline uint32_t
    578 ntoh3(uint8_t *bytes)
    579 {
    580 	return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
    581 }
    582 
    583 
    584 /*
    585  * Convert uint64 to network byte order (for LUN field in PDU)
    586 */
    587 static __inline uint64_t
    588 htonq(uint64_t x)
    589 {
    590 #if BYTE_ORDER == LITTLE_ENDIAN
    591 	uint8_t *s = (uint8_t *) & x;
    592 	return (uint64_t) ((uint64_t) s[0] << 56 | (uint64_t) s[1] << 48 |
    593 			(uint64_t) s[2] << 40 | (uint64_t) s[3] << 32 |
    594 			(uint64_t) s[4] << 24 | (uint64_t) s[5] << 16 |
    595 			(uint64_t) s[6] <<  8 | (uint64_t) s[7]);
    596 #else
    597 	return x;
    598 #endif
    599 }
    600 
    601 #define ntohq(x) htonq(x)
    602 
    603 /*
    604  * Serial number buffer empty?
    605 */
    606 
    607 static __inline bool
    608 sn_empty(sernum_buffer_t *buf)
    609 {
    610 	return buf->top == buf->bottom;
    611 }
    612 
    613 
    614 /*
    615  * Serial number compare
    616 */
    617 
    618 static __inline bool
    619 sn_a_lt_b(uint32_t a, uint32_t b)
    620 {
    621 	return (a < b && !((b - a) & 0x80000000)) ||
    622 	       (a > b && ((a - b) & 0x80000000));
    623 }
    624 
    625 static __inline bool
    626 sn_a_le_b(uint32_t a, uint32_t b)
    627 {
    628 	return (a <= b && !((b - a) & 0x80000000)) ||
    629 	       (a >= b && ((a - b) & 0x80000000));
    630 }
    631 
    632 /* in iscsi_ioctl.c */
    633 
    634 void iscsi_init_cleanup(void);
    635 int iscsi_destroy_cleanup(void);
    636 void iscsi_notify_cleanup(void);
    637 
    638 
    639 /* Parameter for logout is reason code in logout PDU, -1 for don't send logout */
    640 #define NO_LOGOUT          -1
    641 #define LOGOUT_SESSION     0
    642 #define LOGOUT_CONNECTION  1
    643 #define RECOVER_CONNECTION 2
    644 
    645 void add_event(iscsi_event_t, uint32_t, uint32_t, uint32_t);
    646 
    647 void kill_connection(connection_t *, uint32_t, int, bool);
    648 void kill_session(session_t *, uint32_t, int, bool);
    649 int kill_all_sessions(void);
    650 void handle_connection_error(connection_t *, uint32_t, int);
    651 void add_connection_cleanup(connection_t *);
    652 
    653 #ifndef ISCSI_MINIMAL
    654 uint32_t map_databuf(struct proc *, void **, uint32_t);
    655 void unmap_databuf(struct proc *, void *, uint32_t);
    656 #endif
    657 int iscsiioctl(struct file *, u_long, void *);
    658 
    659 session_t *find_session(uint32_t);
    660 connection_t *find_connection(session_t *, uint32_t);
    661 int ref_session(session_t *);
    662 void unref_session(session_t *);
    663 
    664 /* in iscsi_main.c */
    665 
    666 /*void iscsiattach(void *); */
    667 int iscsidetach(device_t, int);
    668 
    669 void iscsi_done(ccb_t *);
    670 int map_session(session_t *, device_t);
    671 int unmap_session(session_t *);
    672 
    673 /* in iscsi_send.c */
    674 
    675 void iscsi_send_thread(void *);
    676 
    677 connection_t *assign_connection(session_t *session, bool waitok);
    678 void resend_pdu(ccb_t *);
    679 int send_login(connection_t *);
    680 int send_logout(connection_t *, connection_t *, int, bool);
    681 int send_data_out(connection_t *, pdu_t *, ccb_t *, ccb_disp_t, bool);
    682 void send_run_xfer(session_t *, struct scsipi_xfer *);
    683 int send_send_targets(session_t *, uint8_t *);
    684 int send_task_management(connection_t *, ccb_t *, struct scsipi_xfer *, int);
    685 
    686 void negotiate_login(connection_t *, pdu_t *, ccb_t *);
    687 void acknowledge_text(connection_t *, pdu_t *, ccb_t *);
    688 void start_text_negotiation(connection_t *);
    689 void negotiate_text(connection_t *, pdu_t *, ccb_t *);
    690 int send_nop_out(connection_t *, pdu_t *);
    691 void snack_missing(connection_t *, ccb_t *, uint8_t, uint32_t, uint32_t);
    692 void send_snack(connection_t *, pdu_t *, ccb_t *, uint8_t);
    693 int send_send_targets(session_t *, uint8_t *);
    694 
    695 void send_command(ccb_t *, ccb_disp_t, bool, bool);
    696 #ifndef ISCSI_MINIMAL
    697 int send_io_command(session_t *, uint64_t, scsireq_t *, bool, uint32_t);
    698 #endif
    699 
    700 void connection_timeout_co(void *);
    701 void ccb_timeout_co(void *);
    702 
    703 void connection_timeout(connection_t *);
    704 void connection_timeout_start(connection_t *, int);
    705 void connection_timeout_stop(connection_t *);
    706 void ccb_timeout(ccb_t *);
    707 void ccb_timeout_start(ccb_t *, int);
    708 void ccb_timeout_stop(ccb_t *);
    709 
    710 /* in iscsi_rcv.c */
    711 
    712 void iscsi_rcv_thread(void *);
    713 
    714 /* in iscsi_utils.c */
    715 
    716 uint32_t gen_digest(void *, int);
    717 uint32_t gen_digest_2(void *, int, void *, int);
    718 
    719 void create_ccbs(session_t *);
    720 void destroy_ccbs(session_t *);
    721 ccb_t *get_ccb(connection_t *, bool);
    722 void free_ccb(ccb_t *);
    723 void suspend_ccb(ccb_t *, bool);
    724 void wake_ccb(ccb_t *, uint32_t);
    725 
    726 void create_pdus(connection_t *);
    727 pdu_t *get_pdu(connection_t *, bool);
    728 void free_pdu(pdu_t *);
    729 
    730 void init_sernum(sernum_buffer_t *);
    731 int add_sernum(sernum_buffer_t *, uint32_t);
    732 uint32_t ack_sernum(sernum_buffer_t *, uint32_t);
    733 
    734 uint32_t get_sernum(session_t *, pdu_t *);
    735 int sernum_in_window(session_t *);
    736 int window_size(session_t *, int);
    737 
    738 /* in iscsi_text.c */
    739 
    740 int assemble_login_parameters(connection_t *, ccb_t *, pdu_t *);
    741 int assemble_security_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
    742 int assemble_negotiation_parameters(connection_t *, ccb_t *, pdu_t *, pdu_t *);
    743 int init_text_parameters(connection_t *, ccb_t *);
    744 int assemble_send_targets(pdu_t *, uint8_t *);
    745 void set_negotiated_parameters(ccb_t *);
    746 
    747 #endif /* !_ISCSI_GLOBALS_H */
    748