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