1 /*        $NetBSD: iscsi_globals.h,v 1.28 2023/11/25 10:08:27 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           ST_SEC_NEG          = 0,      /* security negotiation phase */
139           ST_SEC_FIN          = 1,      /* switch from SEC after mutual CHAP */
140           ST_OP_NEG = 2,      /* operational negotiation phase */
141           ST_FULL_FEATURE     = 3,      /* full feature phase */
142           ST_WINDING_DOWN     = 4,      /* connection termination initiated, logging out */
143           ST_LOGOUT_SENT      = 5,      /* logout has been sent */
144           ST_SETTLING         = 6,      /* waiting for things to settle down */
145           ST_IDLE             = 7       /* connection is idle (ready to delete) */
146 } conn_state_t;
147 
148 
149 /* Logout state */
150 
151 typedef enum {
152           NOT_LOGGED_OUT,                                   /* Not logged out */
153           LOGOUT_SENT,                                      /* Logout was sent */
154           LOGOUT_SUCCESS,                                   /* Logout succeeded */
155           LOGOUT_FAILED                                     /* Logout failed */
156 } logout_state_t;
157 
158 
159 /* CCB Disposition */
160 
161 typedef enum {
162           CCBDISP_UNUSED,     /* 0 = In free pool */
163           CCBDISP_BUSY,       /* This CCB is busy, don't allow rx ops */
164           CCBDISP_NOWAIT,     /* Not waiting for anything */
165           CCBDISP_FREE,       /* Free this CCB when done */
166           CCBDISP_WAIT,       /* Calling thread is waiting for completion */
167           CCBDISP_SCSIPI,     /* Call scsipi_done when operation completes */
168           CCBDISP_DEFER       /* Defer waiting until all PDUs have been queued */
169 } ccb_disp_t;
170 
171 
172 /* PDU Disposition */
173 
174 typedef enum {
175           PDUDISP_UNUSED,               /* 0 = In free pool */
176           PDUDISP_FREE,                 /* Free this PDU when done */
177           PDUDISP_WAIT                  /* Waiting for acknowledge */
178 } pdu_disp_t;
179 
180 /* Timeout state */
181 
182 typedef enum {
183           TOUT_NONE,                    /* Initial */
184           TOUT_ARMED,                   /* callout is scheduled */
185           TOUT_QUEUED,                  /* put into timeout queue */
186           TOUT_BUSY           /* cleanup thread working */
187 } tout_state_t;
188 
189 typedef struct connection_s connection_t;
190 typedef struct session_s session_t;
191 typedef struct ccb_s ccb_t;
192 typedef struct pdu_s pdu_t;
193 
194 /* the serial number management structure (a circular buffer) */
195 
196 typedef struct {
197           uint32_t  ExpSN;    /* ExpxxSN (Data or Stat) sent to the target */
198           uint32_t  next_sn; /* next_sn (== ExpSN if no ack is pending) */
199           int                 top;      /* top of buffer (newest element) */
200           int                 bottom;   /* bottom of buffer (oldest element) */
201           uint32_t  sernum[SERNUM_BUFFER_LENGTH]; /* the serial numbers */
202           bool                ack[SERNUM_BUFFER_LENGTH];    /* acknowledged? */
203 } sernum_buffer_t;
204 
205 
206 /*
207    The per-PDU data structure.
208 */
209 
210 struct pdu_s {
211           TAILQ_ENTRY(pdu_s)  pdu_chain;          /* freelist or wait list (or no list) */
212           TAILQ_ENTRY(pdu_s)  pdu_send_chain;
213                                         /* chaining PDUs waiting to be sent */
214           pdu_disp_t                    pdu_disp; /* what to do with this pdu */
215           uint32_t            pdu_flags;          /* various processing flags */
216           pdu_header_t                  pdu_hdr; /* Buffer for PDU associated with cmd */
217           void                          *pdu_temp_data; /* (free after use) */
218           uint32_t            pdu_temp_data_len;  /* size of temp data */
219 
220           struct uio                    pdu_uio; /* UIO structure */
221           struct iovec                  pdu_io_vec[4];
222                                         /* Header + data + data-digest + padding */
223 
224           struct uio                    pdu_save_uio;
225                                         /* UIO structure save for retransmits */
226           struct iovec                  pdu_save_iovec[4];
227                                         /* Header + data + data-digest + padding */
228           uint32_t            pdu_data_digest;
229                                         /* holds data digest if enabled */
230           ccb_t                         *pdu_owner;
231                                         /* the ccb this PDU belongs to (if any) */
232           connection_t                  *pdu_connection;
233                                         /* the connection this PDU belongs to */
234 };
235 
236 
237 /* the PDU list type */
238 
239 TAILQ_HEAD(pdu_list_s, pdu_s);
240 typedef struct pdu_list_s pdu_list_t;
241 
242 /*
243    The per-command data structure. Calling it ccb in correspondence
244    to other HA drivers.
245 */
246 
247 struct ccb_s {
248           TAILQ_ENTRY(ccb_s)  ccb_chain;
249           /* either freelist or waiting list (or no list) */
250 
251           uint32_t            ccb_status; /* Status gets entered here */
252           ccb_disp_t                    ccb_disp; /* what to do with this ccb */
253 
254           struct callout                ccb_timeout; /* To make sure it isn't lost */
255           TAILQ_ENTRY(ccb_s)  ccb_tchain;
256           tout_state_t                  ccb_timedout;
257           int                           ccb_num_timeouts;
258           /* How often we've sent out SNACK without answer */
259           int                           ccb_total_tries;
260           /* How often we've tried to recover */
261 
262           uint32_t            ccb_ITT;
263           /* task tag: ITT counter + sess id + CCB index */
264           sernum_buffer_t               ccb_DataSN_buf;
265           /* Received Data Seq nums (read ops only) */
266 
267           void                          *ccb_par;
268           /* misc. parameter for this request */
269           struct scsipi_xfer  *ccb_xs;
270           /* the scsipi_xfer for this cmd */
271 
272           void                          *ccb_temp_data;
273           /* to hold state (mainly during negotiation) */
274           void                          *ccb_text_data;
275           /* holds accumulated text for continued PDUs */
276           uint32_t            ccb_text_len;
277           /* length of text data so far */
278 
279           uint64_t            ccb_lun; /* LUN */
280           uint32_t            ccb_tag; /* Command tag */
281           uint8_t                       *ccb_cmd; /* SCSI command block */
282           uint16_t            ccb_cmdlen; /* SCSI command block length */
283           bool                          ccb_data_in; /* if this is a read request */
284           uint8_t                       *ccb_data_ptr; /* data pointer for read/write */
285           uint32_t            ccb_data_len; /* total data length */
286           uint32_t            ccb_xfer_len; /* data transferred on read */
287           uint32_t            ccb_residual; /* residual data size */
288 
289           void                          *ccb_sense_ptr; /* sense data pointer */
290           int                           ccb_sense_len_req; /* requested sense data length */
291           int                           ccb_sense_len_got; /* actual sense data length */
292 
293           pdu_t                         *ccb_pdu_waiting; /* PDU waiting to be ack'ed */
294           volatile uint32_t   ccb_CmdSN; /* CmdSN associated with waiting PDU */
295 
296           int                           ccb_flags;
297           connection_t                  *ccb_connection; /* connection for CCB */
298           session_t           *ccb_session; /* session for CCB */
299 };
300 
301 
302 /* the CCB list type */
303 
304 TAILQ_HEAD(ccb_list_s, ccb_s);
305 typedef struct ccb_list_s ccb_list_t;
306 
307 
308 /*
309    Per connection data: the connection structure
310 */
311 struct connection_s {
312           TAILQ_ENTRY(connection_s)     c_connections;
313 
314           kmutex_t                      c_lock;
315           kcondvar_t                              c_conn_cv;
316           kcondvar_t                              c_pdu_cv;
317           kcondvar_t                              c_ccb_cv;
318           kcondvar_t                              c_idle_cv;
319 
320           pdu_list_t                              c_pdu_pool; /* the free PDU pool */
321 
322           ccb_list_t                              c_ccbs_waiting;
323                                                   /* CCBs waiting for completion */
324 
325           pdu_list_t                              c_pdus_to_send;
326                                                   /* the PDUs waiting to be sent */
327 
328           sernum_buffer_t                         c_StatSN_buf;
329                                                   /* to keep track of received StatSNs */
330 
331           uint32_t                      c_max_transfer;
332                     /* min(MaxRecvDataSegmentLength, MaxBurstLength) */
333           uint32_t                      c_max_firstimmed;
334                     /* 0 if InitialR2T=Yes, else
335                        min of (MaxRecvDataSegmentLength, FirstBurstLength) */
336           uint32_t                      c_max_firstdata;
337                     /* 0 if ImmediateData=No, else min of */
338                     /* (MaxRecvDataSegmentLength, FirstBurstLength) */
339 
340           uint32_t                      c_MaxRecvDataSegmentLength;
341                                                   /* Target's value */
342           uint32_t                      c_Our_MaxRecvDataSegmentLength;
343                                                   /* Our own value */
344           bool                                    c_HeaderDigest;     /* TRUE if doing CRC */
345           bool                                    c_DataDigest;       /* TRUE if doing CRC */
346           uint32_t                      c_Time2Wait;
347                                                   /* Negotiated default or logout value */
348           uint32_t                      c_Time2Retain;
349                                                   /* Negotiated default or logout value */
350 
351           uint16_t                      c_id;
352                     /* connection ID (unique within session) */
353 
354           conn_state_t                            c_state; /* State of connection */
355 
356           struct lwp                              *c_threadobj;
357                     /* proc/thread pointer of socket owner */
358 
359           krwlock_t                     c_sock_rw;
360           struct file                             *c_sock;  /* the connection's socket */
361           session_t                     *c_session;
362                                                   /* back pointer to the owning session */
363 
364           struct lwp                              *c_rcvproc; /* receive thread */
365           struct lwp                              *c_sendproc; /* send thread */
366 
367           uint32_t                      c_terminating;
368                                                   /* if closing down: status */
369           int                                     c_recover; /* recovery count */
370                     /* (reset on first successful data transfer) */
371           volatile unsigned             c_usecount; /* number of active CCBs */
372           unsigned                      c_pducount; /* number of active PDUs */
373 
374           bool                                    c_destroy; /* conn will be destroyed */
375           bool                                    c_in_session;
376                     /* if it's linked into the session list */
377           logout_state_t                          c_loggedout;
378                     /* status of logout (for recovery) */
379           struct callout                          c_timeout;
380                     /* Timeout for checking if connection is dead */
381           TAILQ_ENTRY(connection_s)     c_tchain;
382           tout_state_t                            c_timedout;
383           int                                     c_num_timeouts;
384                     /* How often we've sent out a NOP without answer */
385           uint32_t                      c_idle_timeout_val;
386                     /* Connection timeout value when idle */
387 
388           iscsi_login_parameters_t      *c_login_par;
389                                                   /* only valid during login */
390 
391           pdu_t                                   c_pdu[PDUS_PER_CONNECTION]; /* PDUs */
392 };
393 
394 /* the connection list type */
395 
396 TAILQ_HEAD(connection_list_s, connection_s);
397 typedef struct connection_list_s connection_list_t;
398 
399 
400 /*
401    Per session data: the session structure
402 */
403 
404 struct session_s {
405           /* Interface to child drivers.
406              NOTE: sc_adapter MUST be the first field in this structure so we can
407              easily get from adapter to session.
408            */
409           struct scsipi_adapter         s_sc_adapter;
410           struct scsipi_channel         s_sc_channel;
411 
412           device_t            s_child_dev;
413           /* the child we're associated with - (NULL if not mapped) */
414 
415           int                           s_refcount;         /* session in use by scsipi */
416 
417           /* local stuff */
418           TAILQ_ENTRY(session_s)        s_sessions;         /* the list of sessions */
419 
420           kmutex_t            s_lock;
421           kcondvar_t                    s_sess_cv;
422           kcondvar_t                    s_ccb_cv;
423 
424           ccb_list_t                    s_ccb_pool;         /* The free CCB pool */
425 
426           int                           s_send_window;
427 
428           uint16_t            s_id;     /* session ID (unique within driver) */
429           uint16_t            s_TSIH;   /* Target assigned session ID */
430 
431           uint32_t            s_CmdSN;   /* Current CmdSN */
432           uint32_t            s_ExpCmdSN; /* Current max ExpCmdSN received */
433           uint32_t            s_MaxCmdSN; /* Current MaxCmdSN */
434 
435           /* negotiated values */
436           uint32_t            s_ErrorRecoveryLevel;
437           uint32_t            s_FirstBurstLength;
438           uint32_t            s_MaxBurstLength;
439           bool                          s_ImmediateData;
440           bool                          s_InitialR2T;
441           uint32_t            s_MaxOutstandingR2T;
442           uint32_t            s_MaxConnections;
443           uint32_t            s_DefaultTime2Wait;
444           uint32_t            s_DefaultTime2Retain;
445 
446           iscsi_login_session_type_t s_login_type;          /* session type */
447 
448           /* for send_targets requests */
449           uint8_t                       *s_target_list;
450           uint32_t            s_target_list_len;
451 
452           uint32_t            s_conn_id;          /* connection ID counter */
453 
454           uint32_t            s_terminating;      /* if closing down: status */
455 
456           uint32_t            s_active_connections;
457                                         /* currently active connections */
458           uint32_t            s_total_connections;
459           /* connections associated with this session (active or winding down) */
460           connection_list_t   s_conn_list;        /* the list of connections */
461           connection_t                  *s_mru_connection;
462                                         /* the most recently used connection */
463 
464           ccb_t                         s_ccb[CCBS_PER_SESSION];      /* CCBs */
465 
466           char                          s_tgtname[ISCSI_STRING_LENGTH + 1];
467                                         /* iSCSI target name */
468 };
469 
470 /* the session list type */
471 
472 TAILQ_HEAD(session_list_s, session_s);
473 typedef struct session_list_s session_list_t;
474 
475 
476 /*
477    Event notification structures
478 */
479 
480 typedef struct event_s {
481           TAILQ_ENTRY(event_s)          ev_link;  /* next event in queue */
482           iscsi_event_t                 ev_event_kind;      /* which event */
483           uint32_t            ev_session_id;      /* affected session ID */
484           uint32_t            ev_connection_id;/* affected connection ID */
485           uint32_t            ev_reason;                    /* event reason */
486 } event_t;
487 
488 /* the event list entry type */
489 
490 TAILQ_HEAD(event_list_s, event_s);
491 typedef struct event_list_s event_list_t;
492 
493 
494 typedef struct event_handler_s {
495           TAILQ_ENTRY(event_handler_s)  evh_link; /* next handler */
496           uint32_t                      evh_id;   /* unique ID */
497           event_list_t                            evh_events;         /* list of events pending */
498           iscsi_wait_event_parameters_t *evh_waiter; /* waiting parameter */
499           /* following to detect dead handlers */
500           event_t                                 *evh_first_in_list;
501 } event_handler_t;
502 
503 /* the event list entry type */
504 
505 TAILQ_HEAD(event_handler_list_s, event_handler_s);
506 typedef struct event_handler_list_s event_handler_list_t;
507 
508 /* /dev/iscsi0 state */
509 struct iscsifd {
510           TAILQ_ENTRY(iscsifd)                    fd_link;
511           device_t  fd_dev;
512           int                 fd_unit;
513 };
514 
515 /* -------------------------  Global Variables  ----------------------------- */
516 
517 /* In iscsi_main.c */
518 
519 extern struct cfattach iscsi_ca;                  /* the device attach structure */
520 
521 extern session_list_t iscsi_sessions;             /* the list of sessions */
522 extern bool iscsi_detaching;                      /* signal to cleanup thread it should exit */
523 extern uint32_t iscsi_num_send_threads;           /* the number of active send threads */
524 
525 extern uint8_t iscsi_InitiatorName[ISCSI_STRING_LENGTH];
526 extern uint8_t iscsi_InitiatorAlias[ISCSI_STRING_LENGTH];
527 extern login_isid_t iscsi_InitiatorISID;
528 
529 /* Debugging stuff */
530 
531 #ifndef DDB
532 #define Debugger() panic("should call debugger here (iscsi.c)")
533 #endif /* ! DDB */
534 
535 #ifdef ISCSI_DEBUG
536 
537 extern int iscsi_debug_level; /* How much debug info to display */
538 extern bool iscsi_hex_bignums;          /* Whether to encode parameters in hex or base64 */
539 
540 #define DEBOUT(x) printf x
541 #define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;}
542 #define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
543                               conn && conn->c_session ? conn->c_session->s_id : -1, \
544                               conn ? conn->c_id : -1); printf x ;}}
545 
546 #define STATIC static
547 
548 #else
549 
550 #define DEBOUT(x)
551 #define DEB(lev,x)
552 #define DEBC(conn,lev,x)
553 
554 #define STATIC static
555 
556 #endif
557 
558 /* Critical section macros */
559 
560 /* misc stuff */
561 #define min(a, b) ((a) < (b)) ? (a) : (b)
562 #define max(a, b) ((a) < (b)) ? (b) : (a)
563 
564 
565 /*
566    Convert unsigned int to 3-byte value (for DataSegmentLength field in PDU)
567 */
568 
569 static __inline void
hton3(uint32_t val,uint8_t * bytes)570 hton3(uint32_t val, uint8_t *bytes)
571 {
572           bytes[0] = (uint8_t) (val >> 16);
573           bytes[1] = (uint8_t) (val >> 8);
574           bytes[2] = (uint8_t) val;
575 }
576 
577 /*
578    Convert 3-byte value to unsigned int (for DataSegmentLength field in PDU)
579 */
580 
581 static __inline uint32_t
ntoh3(uint8_t * bytes)582 ntoh3(uint8_t *bytes)
583 {
584           return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
585 }
586 
587 
588 /*
589  * Convert uint64 to network byte order (for LUN field in PDU)
590 */
591 static __inline uint64_t
htonq(uint64_t x)592 htonq(uint64_t x)
593 {
594 #if BYTE_ORDER == LITTLE_ENDIAN
595           uint8_t *s = (uint8_t *) & x;
596           return (uint64_t) ((uint64_t) s[0] << 56 | (uint64_t) s[1] << 48 |
597                               (uint64_t) s[2] << 40 | (uint64_t) s[3] << 32 |
598                               (uint64_t) s[4] << 24 | (uint64_t) s[5] << 16 |
599                               (uint64_t) s[6] <<  8 | (uint64_t) s[7]);
600 #else
601           return x;
602 #endif
603 }
604 
605 #define ntohq(x) htonq(x)
606 
607 /*
608  * Serial number buffer empty?
609 */
610 
611 static __inline bool
sn_empty(sernum_buffer_t * buf)612 sn_empty(sernum_buffer_t *buf)
613 {
614           return buf->top == buf->bottom;
615 }
616 
617 
618 /*
619  * Serial number compare
620 */
621 
622 static __inline bool
sn_a_lt_b(uint32_t a,uint32_t b)623 sn_a_lt_b(uint32_t a, uint32_t b)
624 {
625           return (a < b && !((b - a) & 0x80000000)) ||
626                  (a > b && ((a - b) & 0x80000000));
627 }
628 
629 static __inline bool
sn_a_le_b(uint32_t a,uint32_t b)630 sn_a_le_b(uint32_t a, uint32_t b)
631 {
632           return (a <= b && !((b - a) & 0x80000000)) ||
633                  (a >= b && ((a - b) & 0x80000000));
634 }
635 
636 /* in iscsi_ioctl.c */
637 
638 void iscsi_init_cleanup(void);
639 int iscsi_destroy_cleanup(void);
640 void iscsi_notify_cleanup(void);
641 
642 
643 /* Parameter for logout is reason code in logout PDU, -1 for don't send logout */
644 #define NO_LOGOUT          -1
645 #define LOGOUT_SESSION     0
646 #define LOGOUT_CONNECTION  1
647 #define RECOVER_CONNECTION 2
648 
649 void add_event(iscsi_event_t, uint32_t, uint32_t, uint32_t);
650 
651 void kill_connection(connection_t *, uint32_t, int, bool);
652 void kill_session(uint32_t, uint32_t, int, bool);
653 int kill_all_sessions(void);
654 void handle_connection_error(connection_t *, uint32_t, int);
655 void add_connection_cleanup(connection_t *);
656 
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(const void *, size_t);
717 uint32_t gen_digest_2(const void *, size_t, const void *, size_t);
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