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