xref: /netbsd-src/sys/dev/iscsi/iscsi_utils.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: iscsi_utils.c,v 1.27 2019/04/21 11:45:08 maya Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004,2005,2006,2008 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 #include "iscsi_globals.h"
32 
33 #include <sys/systm.h>
34 #include <sys/buf.h>
35 #include <sys/socketvar.h>
36 #include <sys/bswap.h>
37 #include <sys/atomic.h>
38 
39 
40 /*****************************************************************************
41  * Digest functions
42  *****************************************************************************/
43 
44 /*****************************************************************
45  *
46  * CRC LOOKUP TABLE
47  * ================
48  * The following CRC lookup table was generated automagically
49  * by the Rocksoft^tm Model CRC Algorithm Table Generation
50  * Program V1.0 using the following model parameters:
51  *
52  *    Width   : 4 bytes.
53  *    Poly    : 0x1EDC6F41L
54  *    Reverse : TRUE.
55  *
56  * For more information on the Rocksoft^tm Model CRC Algorithm,
57  * see the document titled "A Painless Guide to CRC Error
58  * Detection Algorithms" by Ross Williams
59  * (ross@guest.adelaide.edu.au.). This document is likely to be
60  * in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".
61  *
62  *****************************************************************/
63 
64 STATIC uint32_t crc_table[256] = {
65 	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
66 	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
67 	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
68 	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
69 	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
70 	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
71 	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
72 	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
73 	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
74 	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
75 	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
76 	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
77 	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
78 	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
79 	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
80 	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
81 	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
82 	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
83 	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
84 	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
85 	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
86 	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
87 	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
88 	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
89 	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
90 	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
91 	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
92 	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
93 	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
94 	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
95 	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
96 	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
97 	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
98 	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
99 	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
100 	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
101 	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
102 	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
103 	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
104 	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
105 	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
106 	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
107 	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
108 	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
109 	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
110 	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
111 	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
112 	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
113 	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
114 	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
115 	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
116 	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
117 	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
118 	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
119 	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
120 	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
121 	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
122 	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
123 	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
124 	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
125 	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
126 	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
127 	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
128 	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
129 };
130 
131 
132 /*
133  * gen_digest:
134  *    Generate an iSCSI CRC32C digest over the given data.
135  *
136  *    Parameters:
137  *          buff   The data
138  *          len   The length of the data in bytes
139  *
140  *    Returns:    The digest in network byte order
141  */
142 
143 uint32_t
144 gen_digest(const void *buff, size_t len)
145 {
146 	const uint8_t *bp = (const uint8_t *) buff;
147 	uint32_t crc = 0xffffffff;
148 
149 	while (len--) {
150 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
151 	}
152 	return htonl(bswap32(crc ^ 0xffffffff));
153 }
154 
155 
156 /*
157  * gen_digest_2:
158  *    Generate an iSCSI CRC32C digest over the given data, which is split over
159  *    two buffers.
160  *
161  *    Parameters:
162  *          buf1, buf2  The data
163  *          len1, len2  The length of the data in bytes
164  *
165  *    Returns:    The digest in network byte order
166  */
167 
168 uint32_t
169 gen_digest_2(const void *buf1, size_t len1, const void *buf2, size_t len2)
170 {
171 	const uint8_t *bp = (const uint8_t *) buf1;
172 	uint32_t crc = 0xffffffff;
173 
174 	while (len1--) {
175 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
176 	}
177 	bp = (const uint8_t *) buf2;
178 	while (len2--) {
179 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
180 	}
181 	return htonl(bswap32(crc ^ 0xffffffff));
182 }
183 
184 /*****************************************************************************
185  * CCB management functions
186  *****************************************************************************/
187 
188 /*
189  * get_ccb:
190  *    Get a CCB for the SCSI operation, waiting if none is available.
191  *
192  *    Parameter:
193  *       sess     The session containing this CCB
194  *       waitok   Whether waiting for a CCB is OK
195  *
196  *    Returns:    The CCB.
197  */
198 
199 ccb_t *
200 get_ccb(connection_t *conn, bool waitok)
201 {
202 	ccb_t *ccb;
203 	session_t *sess = conn->c_session;
204 
205 	mutex_enter(&sess->s_lock);
206 	do {
207 		ccb = TAILQ_FIRST(&sess->s_ccb_pool);
208 		DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
209 
210 		if (ccb != NULL) {
211 			TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain);
212 		} else {
213 			if (!waitok || conn->c_terminating) {
214 				mutex_exit(&sess->s_lock);
215 				return NULL;
216 			}
217 			cv_wait(&sess->s_ccb_cv, &sess->s_lock);
218 		}
219 	} while (ccb == NULL);
220 	mutex_exit(&sess->s_lock);
221 
222 	ccb->ccb_flags = 0;
223 	ccb->ccb_timedout = TOUT_NONE;
224 	ccb->ccb_xs = NULL;
225 	ccb->ccb_temp_data = NULL;
226 	ccb->ccb_text_data = NULL;
227 	ccb->ccb_status = ISCSI_STATUS_SUCCESS;
228 	ccb->ccb_ITT = (ccb->ccb_ITT & 0xffffff);
229 	ccb->ccb_disp = CCBDISP_NOWAIT;
230 	ccb->ccb_connection = conn;
231 	ccb->ccb_num_timeouts = 0;
232 	atomic_inc_uint(&conn->c_usecount);
233 
234 	DEBC(conn, 15, (
235 		"get_ccb: ccb = %p, usecount = %d\n",
236 		ccb, conn->c_usecount));
237 
238 	return ccb;
239 }
240 
241 /*
242  * free_ccb:
243  *    Put a CCB back onto the free list.
244  *
245  *    Parameter:  The CCB.
246  */
247 
248 void
249 free_ccb(ccb_t *ccb)
250 {
251 	session_t *sess = ccb->ccb_session;
252 	connection_t *conn = ccb->ccb_connection;
253 	pdu_t *pdu;
254 
255 	DEBC(conn, 15, (
256 		"free_ccb: ccb = %p, usecount = %d\n",
257 		ccb, conn->c_usecount-1));
258 
259 	KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0);
260 
261 	atomic_dec_uint(&conn->c_usecount);
262 	ccb->ccb_connection = NULL;
263 
264 	if (ccb->ccb_disp > CCBDISP_NOWAIT) {
265 		DEBOUT(("Freeing CCB with disp %d\n",ccb->ccb_disp));
266 	}
267 
268 	ccb->ccb_disp = CCBDISP_UNUSED;
269 
270 	/* free temporary data */
271 	if (ccb->ccb_temp_data != NULL) {
272 		free(ccb->ccb_temp_data, M_TEMP);
273 	}
274 	if (ccb->ccb_text_data != NULL) {
275 		free(ccb->ccb_text_data, M_TEMP);
276 	}
277 	/* free PDU waiting for ACK */
278 	if ((pdu = ccb->ccb_pdu_waiting) != NULL) {
279 		ccb->ccb_pdu_waiting = NULL;
280 		mutex_enter(&conn->c_lock);
281 		if ((pdu->pdu_flags & PDUF_INQUEUE) != 0) {
282 			TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain);
283 			pdu->pdu_flags &= ~PDUF_INQUEUE;
284 		}
285 		mutex_exit(&conn->c_lock);
286 		free_pdu(pdu);
287 	}
288 
289 	mutex_enter(&sess->s_lock);
290 	TAILQ_INSERT_TAIL(&sess->s_ccb_pool, ccb, ccb_chain);
291 	cv_broadcast(&sess->s_ccb_cv);
292 	mutex_exit(&sess->s_lock);
293 }
294 
295 /*
296  *    create_ccbs
297  *       "Create" the pool of CCBs. This doesn't actually create the CCBs
298  *       (they are allocated with the session structure), but it links them
299  *       into the free-list.
300  *
301  *    Parameter:  The session owning the CCBs.
302  */
303 
304 void
305 create_ccbs(session_t *sess)
306 {
307 	int i;
308 	ccb_t *ccb;
309 	int sid = sess->s_id << 8;
310 
311 	/* Note: CCBs are initialized to 0 with connection structure */
312 
313 	for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) {
314 		ccb->ccb_ITT = i | sid;
315 		ccb->ccb_session = sess;
316 
317 		callout_init(&ccb->ccb_timeout, CALLOUT_MPSAFE);
318 		callout_setfunc(&ccb->ccb_timeout, ccb_timeout_co, ccb);
319 
320 		DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT));
321 		TAILQ_INSERT_HEAD(&sess->s_ccb_pool, ccb, ccb_chain);
322 	}
323 }
324 
325 /*
326  *    destroy_ccbs
327  *       Kill the callouts
328  *
329  *    Parameter:  The session owning the CCBs.
330  */
331 
332 void
333 destroy_ccbs(session_t *sess)
334 {
335 	int i;
336 	ccb_t *ccb;
337 
338 	/* Note: CCBs are initialized to 0 with connection structure */
339 
340 	for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) {
341 
342 		callout_halt(&ccb->ccb_timeout, NULL);
343 		callout_destroy(&ccb->ccb_timeout);
344 
345 		DEB(9, ("destroy_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT));
346 		KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0);
347 		KASSERT(ccb->ccb_disp == CCBDISP_UNUSED);
348 		KASSERT(ccb->ccb_connection == NULL);
349 		TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain);
350 	}
351 }
352 
353 /*
354  * suspend_ccb:
355  *    Put CCB on wait queue
356  */
357 void
358 suspend_ccb(ccb_t *ccb, bool yes)
359 {
360 	connection_t *conn;
361 
362 	conn = ccb->ccb_connection;
363 	KASSERT(conn != NULL);
364 
365 	KASSERT(mutex_owned(&conn->c_lock));
366 
367 	if (yes) {
368 		KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0);
369 		TAILQ_INSERT_TAIL(&conn->c_ccbs_waiting, ccb, ccb_chain);
370 		ccb->ccb_flags |= CCBF_WAITQUEUE;
371 	} else if (ccb->ccb_flags & CCBF_WAITQUEUE) {
372 		TAILQ_REMOVE(&conn->c_ccbs_waiting, ccb, ccb_chain);
373 		ccb->ccb_flags &= ~CCBF_WAITQUEUE;
374 	}
375 }
376 
377 /*
378  * wake_ccb:
379  *    Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
380  *    either wake up the requesting thread, signal SCSIPI that we're done,
381  *    or just free the CCB for CCBDISP_FREE.
382  *
383  *    Parameter:  The CCB to handle and the new status of the CCB
384  */
385 
386 void
387 wake_ccb(ccb_t *ccb, uint32_t status)
388 {
389 	ccb_disp_t disp;
390 	connection_t *conn;
391 
392 	conn = ccb->ccb_connection;
393 	KASSERT(conn != NULL);
394 
395 	DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n",
396 		ccb->ccb_CmdSN, ccb, ccb->ccb_disp));
397 
398 	ccb_timeout_stop(ccb);
399 
400 	mutex_enter(&conn->c_lock);
401 	disp = ccb->ccb_disp;
402 	if (disp <= CCBDISP_NOWAIT ||
403 		(disp == CCBDISP_DEFER && conn->c_state <= ST_WINDING_DOWN)) {
404 		mutex_exit(&conn->c_lock);
405 		return;
406 	}
407 
408 	suspend_ccb(ccb, FALSE);
409 
410 	/* change the disposition so nobody tries this again */
411 	ccb->ccb_disp = CCBDISP_BUSY;
412 	ccb->ccb_status = status;
413 
414 	if (disp == CCBDISP_WAIT)
415 		cv_broadcast(&conn->c_ccb_cv);
416 	mutex_exit(&conn->c_lock);
417 
418 	switch(disp) {
419 	case CCBDISP_WAIT:
420 	case CCBDISP_DEFER:
421 		break;
422 
423 	case CCBDISP_SCSIPI:
424 		iscsi_done(ccb);
425 		/* FALLTHROUGH */
426 	case CCBDISP_FREE:
427 		free_ccb(ccb);
428 		break;
429 	default:
430 		DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
431 		free_ccb(ccb);
432 		break;
433 	}
434 }
435 
436 /*****************************************************************************
437  * PDU management functions
438  *****************************************************************************/
439 
440 /*
441  * get_pdu:
442  *    Get a PDU for the SCSI operation.
443  *
444  *    Parameter:
445  *          conn     The connection this PDU should be associated with
446  *          waitok   OK to wait for PDU if TRUE
447  *
448  *    Returns:    The PDU or NULL if none is available and waitok is FALSE.
449  */
450 
451 pdu_t *
452 get_pdu(connection_t *conn, bool waitok)
453 {
454 	pdu_t *pdu;
455 
456 	mutex_enter(&conn->c_lock);
457 	do {
458 		pdu = TAILQ_FIRST(&conn->c_pdu_pool);
459 		if (pdu != NULL)
460 			TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain);
461 
462 		if (pdu == NULL) {
463 			if (!waitok || conn->c_terminating) {
464 				mutex_exit(&conn->c_lock);
465 				DEB(15, ("get_pdu: failed"));
466 				return NULL;
467 			}
468 			cv_wait(&conn->c_pdu_cv, &conn->c_lock);
469 		}
470 	} while (pdu == NULL);
471 	atomic_inc_uint(&conn->c_pducount);
472 	mutex_exit(&conn->c_lock);
473 
474 	memset(pdu, 0, sizeof(pdu_t));
475 	pdu->pdu_connection = conn;
476 	pdu->pdu_disp = PDUDISP_FREE;
477 
478 	DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount));
479 
480 	return pdu;
481 }
482 
483 /*
484  * free_pdu:
485  *    Put a PDU back onto the free list.
486  *
487  *    Parameter:  The PDU.
488  */
489 
490 void
491 free_pdu(pdu_t *pdu)
492 {
493 	connection_t *conn = pdu->pdu_connection;
494 	pdu_disp_t pdisp;
495 
496 	DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount-1));
497 
498 	KASSERT((pdu->pdu_flags & PDUF_INQUEUE) == 0);
499 
500 	if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp))
501 		return;
502 	pdu->pdu_disp = PDUDISP_UNUSED;
503 
504 	/* free temporary data in this PDU */
505 	if (pdu->pdu_temp_data)
506 		free(pdu->pdu_temp_data, M_TEMP);
507 
508 	mutex_enter(&conn->c_lock);
509 	atomic_dec_uint(&conn->c_pducount);
510 	TAILQ_INSERT_TAIL(&conn->c_pdu_pool, pdu, pdu_chain);
511 	cv_broadcast(&conn->c_pdu_cv);
512 	mutex_exit(&conn->c_lock);
513 }
514 
515 /*
516  *    create_pdus
517  *       "Create" the pool of PDUs. This doesn't actually create the PDUs
518  *       (they are allocated with the connection structure), but it links them
519  *       into the free-list.
520  *
521  *    Parameter:  The connection owning the PDUs.
522  */
523 
524 void
525 create_pdus(connection_t *conn)
526 {
527 	int i;
528 	pdu_t *pdu;
529 
530 	/* Note: PDUs are initialized to 0 with connection structure */
531 
532 	for (i = 0, pdu = conn->c_pdu; i < PDUS_PER_CONNECTION; i++, pdu++) {
533 		TAILQ_INSERT_HEAD(&conn->c_pdu_pool, pdu, pdu_chain);
534 	}
535 }
536 
537 
538 /*****************************************************************************
539  * Serial Number management functions
540  *****************************************************************************/
541 
542 /*
543  * init_sernum:
544  *    Initialize serial number buffer variables.
545  *
546  *    Parameter:
547  *          buff   The serial number buffer.
548  */
549 
550 void
551 init_sernum(sernum_buffer_t *buff)
552 {
553 
554 	buff->bottom = 0;
555 	buff->top = 0;
556 	buff->next_sn = 0;
557 	buff->ExpSN = 0;
558 }
559 
560 
561 /*
562  * add_sernum:
563  *    Add a received serial number to the buffer.
564  *    If the serial number is smaller than the expected one, it is ignored.
565  *    If it is larger, all missing serial numbers are added as well.
566  *
567  *    Parameter:
568  *          buff   The serial number buffer.
569  *          num   The received serial number
570  *
571  *    Returns:
572  *          0     if the received block is a duplicate
573  *          1     if the number is the expected one
574  *          >1    if the number is > the expected value, in this case the
575  *                return value is the number of unacknowledged blocks
576  *          <0    if the buffer is full (i.e. an excessive number of blocks
577  *                is unacknowledged)
578  */
579 
580 int
581 add_sernum(sernum_buffer_t *buff, uint32_t num)
582 {
583 	int i, t, b;
584 	uint32_t n;
585 	int32_t diff;
586 
587 	/*
588 	 * next_sn is the next expected SN, so normally diff should be 1.
589 	 */
590 	n = buff->next_sn;
591 	diff = (num - n) + 1;
592 
593 	if (diff <= 0) {
594 		return 0;				/* ignore if SN is smaller than expected (dup or retransmit) */
595 	}
596 
597 	buff->next_sn = num + 1;
598 	t = buff->top;
599 	b = buff->bottom;
600 
601 	for (i = 0; i < diff; i++) {
602 		buff->sernum[t] = n++;
603 		buff->ack[t] = false;
604 		t = (t + 1) % SERNUM_BUFFER_LENGTH;
605 		if (t == b) {
606 			DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff));
607 			return -1;
608 		}
609 	}
610 
611 	buff->top = t;
612 	DEB(11, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n",
613 			 b, buff->sernum[b], buff->top, num, diff));
614 
615 	return diff;
616 }
617 
618 
619 /*
620  * ack_sernum:
621  *    Mark a received serial number as acknowledged. This does not necessarily
622  *    change the associated ExpSN if there are lower serial numbers in the
623  *    buffer.
624  *
625  *    Parameter:
626  *          buff   The serial number buffer.
627  *          num   The serial number to acknowledge.
628  *
629  *    Returns:    The value of ExpSN.
630  */
631 
632 uint32_t
633 ack_sernum(sernum_buffer_t *buff, uint32_t num)
634 {
635 	int b = buff->bottom;
636 	int t = buff->top;
637 
638 	/* shortcut for most likely case */
639 	if (t == (b + 1) && num == buff->sernum[b]) {
640 		/* buffer is now empty, reset top */
641 		buff->top = b;
642 	} else if (b != t) {
643 		for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
644 			if (!sn_a_lt_b(buff->sernum[b], num))
645 				break;
646 		}
647 		if (num == buff->sernum[b]) {
648 			if (b == buff->bottom)
649 				buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH;
650 			else
651 				buff->ack[b] = true;
652 		}
653 
654 		for (b = buff->bottom, num = buff->sernum[b] - 1;
655 			 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
656 			num = buff->sernum[b];
657 		}
658 	}
659 
660 	if (!sn_a_lt_b(num, buff->ExpSN))
661 		buff->ExpSN = num + 1;
662 
663 	DEB(11, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n",
664 			 buff->bottom, buff->top, num, buff->ExpSN));
665 
666 	return buff->ExpSN;
667 }
668 
669 /*
670  * next_sernum:
671  *   Return the current command serial number of the session
672  *   and optionally increment it for the next query
673  */
674 uint32_t
675 get_sernum(session_t *sess, pdu_t *pdu)
676 {
677 	uint32_t sn;
678 
679 	KASSERT(mutex_owned(&sess->s_lock));
680 
681 	sn = sess->s_CmdSN;
682 	if ((pdu->pdu_hdr.pduh_Opcode & OP_IMMEDIATE) == 0)
683 		atomic_inc_32(&sess->s_CmdSN);
684 	return sn;
685 }
686 
687 /*
688  * sernum_in_window:
689  *   Check whether serial number is in send window
690  *
691  */
692 int
693 sernum_in_window(session_t *sess)
694 {
695 
696 	KASSERT(mutex_owned(&sess->s_lock));
697 	return sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN);
698 }
699 
700 /*
701  * window_size:
702  *    Compute send window size
703  */
704 int
705 window_size(session_t *sess, int limit)
706 {
707 	uint32_t win;
708 
709 	KASSERT(mutex_owned(&sess->s_lock));
710 
711 	win = 0;
712 	if (sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN))
713 		win = sess->s_MaxCmdSN - sess->s_CmdSN + 1;
714 	if (win > INT_MAX || win > limit)
715 		win = limit;
716 
717 	return win;
718 }
719