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