xref: /netbsd-src/sys/dev/iscsi/iscsi_utils.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /*	$NetBSD: iscsi_utils.c,v 1.21 2016/06/15 04:30:30 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 /*****************************************************************************
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(void *buff, int len)
145 {
146 	uint8_t *bp = (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(void *buf1, int len1, void *buf2, int len2)
170 {
171 	uint8_t *bp = (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 = (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->session;
204 
205 	mutex_enter(&sess->lock);
206 	do {
207 		ccb = TAILQ_FIRST(&sess->ccb_pool);
208 		DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
209 
210 		if (ccb != NULL) {
211 			TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
212 		} else {
213 			if (!waitok || conn->terminating) {
214 				mutex_exit(&sess->lock);
215 				return NULL;
216 			}
217 			cv_wait(&sess->ccb_cv, &sess->lock);
218 		}
219 	} while (ccb == NULL);
220 	mutex_exit(&sess->lock);
221 
222 	ccb->flags = 0;
223 	ccb->timedout = TOUT_NONE;
224 	ccb->xs = NULL;
225 	ccb->temp_data = NULL;
226 	ccb->text_data = NULL;
227 	ccb->status = ISCSI_STATUS_SUCCESS;
228 	ccb->ITT = (ccb->ITT & 0xffffff);
229 	ccb->disp = CCBDISP_NOWAIT;
230 	ccb->connection = conn;
231 	ccb->num_timeouts = 0;
232 	atomic_inc_uint(&conn->usecount);
233 
234 	DEBC(conn, 15, (
235 		"get_ccb: ccb = %p, usecount = %d\n",
236 		ccb, conn->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->session;
252 	connection_t *conn = ccb->connection;
253 	pdu_t *pdu;
254 
255 	DEBC(conn, 15, (
256 		"free_ccb: ccb = %p, usecount = %d\n",
257 		ccb, conn->usecount-1));
258 
259 	KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
260 
261 	atomic_dec_uint(&conn->usecount);
262 	ccb->connection = NULL;
263 
264 	if (ccb->disp > CCBDISP_NOWAIT) {
265 		DEBOUT(("Freeing CCB with disp %d\n",ccb->disp));
266 	}
267 
268 	ccb->disp = CCBDISP_UNUSED;
269 
270 	/* free temporary data */
271 	if (ccb->temp_data != NULL) {
272 		free(ccb->temp_data, M_TEMP);
273 	}
274 	if (ccb->text_data != NULL) {
275 		free(ccb->text_data, M_TEMP);
276 	}
277 	/* free PDU waiting for ACK */
278 	if ((pdu = ccb->pdu_waiting) != NULL) {
279 		ccb->pdu_waiting = NULL;
280 		mutex_enter(&conn->lock);
281 		if ((pdu->flags & PDUF_INQUEUE) != 0) {
282 			TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
283 			pdu->flags &= ~PDUF_INQUEUE;
284 		}
285 		mutex_exit(&conn->lock);
286 		free_pdu(pdu);
287 	}
288 
289 	mutex_enter(&sess->lock);
290 	TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
291 	mutex_exit(&sess->lock);
292 
293 	cv_broadcast(&sess->ccb_cv);
294 }
295 
296 /*
297  *    create_ccbs
298  *       "Create" the pool of CCBs. This doesn't actually create the CCBs
299  *       (they are allocated with the session structure), but it links them
300  *       into the free-list.
301  *
302  *    Parameter:  The session owning the CCBs.
303  */
304 
305 void
306 create_ccbs(session_t *sess)
307 {
308 	int i;
309 	ccb_t *ccb;
310 	int sid = sess->id << 8;
311 
312 	/* Note: CCBs are initialized to 0 with connection structure */
313 
314 	for (i = 0, ccb = sess->ccb; i < CCBS_PER_SESSION; i++, ccb++) {
315 		ccb->ITT = i | sid;
316 		ccb->session = sess;
317 
318 		callout_init(&ccb->timeout, CALLOUT_MPSAFE);
319 		callout_setfunc(&ccb->timeout, ccb_timeout_co, ccb);
320 
321 		DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ITT));
322 		TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain);
323 	}
324 }
325 
326 /*
327  * suspend_ccb:
328  *    Put CCB on wait queue
329  */
330 void
331 suspend_ccb(ccb_t *ccb, bool yes)
332 {
333 	connection_t *conn;
334 
335 	conn = ccb->connection;
336 
337 	KASSERT(mutex_owned(&conn->lock));
338 
339 	if (yes) {
340 		KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
341 		TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
342 		ccb->flags |= CCBF_WAITQUEUE;
343 	} else if (ccb->flags & CCBF_WAITQUEUE) {
344 		TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
345 		ccb->flags &= ~CCBF_WAITQUEUE;
346 	}
347 }
348 
349 /*
350  * wake_ccb:
351  *    Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
352  *    either wake up the requesting thread, signal SCSIPI that we're done,
353  *    or just free the CCB for CCBDISP_FREE.
354  *
355  *    Parameter:  The CCB to handle and the new status of the CCB
356  */
357 
358 void
359 wake_ccb(ccb_t *ccb, uint32_t status)
360 {
361 	ccb_disp_t disp;
362 	connection_t *conn;
363 
364 	conn = ccb->connection;
365 
366 	DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n",
367 		ccb->CmdSN, ccb, ccb->disp));
368 
369 	ccb_timeout_stop(ccb);
370 
371 	mutex_enter(&conn->lock);
372 	disp = ccb->disp;
373 	if (disp <= CCBDISP_NOWAIT ||
374 		(disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
375 		mutex_exit(&conn->lock);
376 		return;
377 	}
378 
379 	suspend_ccb(ccb, FALSE);
380 
381 	/* change the disposition so nobody tries this again */
382 	ccb->disp = CCBDISP_BUSY;
383 	ccb->status = status;
384 	mutex_exit(&conn->lock);
385 
386 	switch (disp) {
387 	case CCBDISP_FREE:
388 		free_ccb(ccb);
389 		break;
390 
391 	case CCBDISP_WAIT:
392 		cv_broadcast(&conn->ccb_cv);
393 		break;
394 
395 	case CCBDISP_SCSIPI:
396 		iscsi_done(ccb);
397 		free_ccb(ccb);
398 		break;
399 
400 	case CCBDISP_DEFER:
401 		break;
402 
403 	default:
404 		DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
405 		free_ccb(ccb);
406 		break;
407 	}
408 }
409 
410 /*****************************************************************************
411  * PDU management functions
412  *****************************************************************************/
413 
414 /*
415  * get_pdu:
416  *    Get a PDU for the SCSI operation.
417  *
418  *    Parameter:
419  *          conn     The connection this PDU should be associated with
420  *          waitok   OK to wait for PDU if TRUE
421  *
422  *    Returns:    The PDU or NULL if none is available and waitok is FALSE.
423  */
424 
425 pdu_t *
426 get_pdu(connection_t *conn, bool waitok)
427 {
428 	pdu_t *pdu;
429 
430 	mutex_enter(&conn->lock);
431 	do {
432 		pdu = TAILQ_FIRST(&conn->pdu_pool);
433 		if (pdu != NULL)
434 			TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
435 
436 		if (pdu == NULL) {
437 			if (!waitok || conn->terminating) {
438 				mutex_exit(&conn->lock);
439 				DEB(15, ("get_pdu: failed"));
440 				return NULL;
441 			}
442 			cv_wait(&conn->pdu_cv, &conn->lock);
443 		}
444 	} while (pdu == NULL);
445 	atomic_inc_uint(&conn->pducount);
446 	mutex_exit(&conn->lock);
447 
448 	memset(pdu, 0, sizeof(pdu_t));
449 	pdu->connection = conn;
450 	pdu->disp = PDUDISP_FREE;
451 
452 	DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount));
453 
454 	return pdu;
455 }
456 
457 /*
458  * free_pdu:
459  *    Put a PDU back onto the free list.
460  *
461  *    Parameter:  The PDU.
462  */
463 
464 void
465 free_pdu(pdu_t *pdu)
466 {
467 	connection_t *conn = pdu->connection;
468 	pdu_disp_t pdisp;
469 
470 	DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount-1));
471 
472 	KASSERT((pdu->flags & PDUF_INQUEUE) == 0);
473 
474 	if (PDUDISP_UNUSED == (pdisp = pdu->disp))
475 		return;
476 	pdu->disp = PDUDISP_UNUSED;
477 
478 	/* free temporary data in this PDU */
479 	if (pdu->temp_data)
480 		free(pdu->temp_data, M_TEMP);
481 
482 	mutex_enter(&conn->lock);
483 	atomic_dec_uint(&conn->pducount);
484 	TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
485 	mutex_exit(&conn->lock);
486 
487 	cv_broadcast(&conn->pdu_cv);
488 }
489 
490 /*
491  *    create_pdus
492  *       "Create" the pool of PDUs. This doesn't actually create the PDUs
493  *       (they are allocated with the connection structure), but it links them
494  *       into the free-list.
495  *
496  *    Parameter:  The connection owning the PDUs.
497  */
498 
499 void
500 create_pdus(connection_t *conn)
501 {
502 	int i;
503 	pdu_t *pdu;
504 
505 	/* Note: PDUs are initialized to 0 with connection structure */
506 
507 	for (i = 0, pdu = conn->pdu; i < PDUS_PER_CONNECTION; i++, pdu++) {
508 		TAILQ_INSERT_HEAD(&conn->pdu_pool, pdu, chain);
509 	}
510 }
511 
512 
513 /*****************************************************************************
514  * Serial Number management functions
515  *****************************************************************************/
516 
517 /*
518  * init_sernum:
519  *    Initialize serial number buffer variables.
520  *
521  *    Parameter:
522  *          buff   The serial number buffer.
523  */
524 
525 void
526 init_sernum(sernum_buffer_t *buff)
527 {
528 
529 	buff->bottom = 0;
530 	buff->top = 0;
531 	buff->next_sn = 0;
532 	buff->ExpSN = 0;
533 }
534 
535 
536 /*
537  * add_sernum:
538  *    Add a received serial number to the buffer.
539  *    If the serial number is smaller than the expected one, it is ignored.
540  *    If it is larger, all missing serial numbers are added as well.
541  *
542  *    Parameter:
543  *          buff   The serial number buffer.
544  *          num   The received serial number
545  *
546  *    Returns:
547  *          0     if the received block is a duplicate
548  *          1     if the number is the expected one
549  *          >1    if the numer is > the expected value, in this case the
550  *                return value is the number of unacknowledged blocks
551  *          <0    if the buffer is full (i.e. an excessive number of blocks
552  *                is unacknowledged)
553  */
554 
555 int
556 add_sernum(sernum_buffer_t *buff, uint32_t num)
557 {
558 	int i, t, b;
559 	uint32_t n;
560 	int32_t diff;
561 
562 	/*
563 	 * next_sn is the next expected SN, so normally diff should be 1.
564 	 */
565 	n = buff->next_sn;
566 	diff = (num - n) + 1;
567 
568 	if (diff <= 0) {
569 		return 0;				/* ignore if SN is smaller than expected (dup or retransmit) */
570 	}
571 
572 	buff->next_sn = num + 1;
573 	t = buff->top;
574 	b = buff->bottom;
575 
576 	for (i = 0; i < diff; i++) {
577 		buff->sernum[t] = n++;
578 		buff->ack[t] = false;
579 		t = (t + 1) % SERNUM_BUFFER_LENGTH;
580 		if (t == b) {
581 			DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff));
582 			return -1;
583 		}
584 	}
585 
586 	buff->top = t;
587 	DEB(11, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n",
588 			 b, buff->sernum[b], buff->top, num, diff));
589 
590 	return diff;
591 }
592 
593 
594 /*
595  * ack_sernum:
596  *    Mark a received serial number as acknowledged. This does not necessarily
597  *    change the associated ExpSN if there are lower serial numbers in the
598  *    buffer.
599  *
600  *    Parameter:
601  *          buff   The serial number buffer.
602  *          num   The serial number to acknowledge.
603  *
604  *    Returns:    The value of ExpSN.
605  */
606 
607 uint32_t
608 ack_sernum(sernum_buffer_t *buff, uint32_t num)
609 {
610 	int b = buff->bottom;
611 	int t = buff->top;
612 
613 	/* shortcut for most likely case */
614 	if (t == (b + 1) && num == buff->sernum[b]) {
615 		/* buffer is now empty, reset top */
616 		buff->top = b;
617 	} else if (b != t) {
618 		for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
619 			if (!sn_a_lt_b(buff->sernum[b], num))
620 				break;
621 		}
622 		if (num == buff->sernum[b]) {
623 			if (b == buff->bottom)
624 				buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH;
625 			else
626 				buff->ack[b] = true;
627 		}
628 
629 		for (b = buff->bottom, num = buff->sernum[b] - 1;
630 			 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
631 			num = buff->sernum[b];
632 		}
633 	}
634 
635 	if (!sn_a_lt_b(num, buff->ExpSN))
636 		buff->ExpSN = num + 1;
637 
638 	DEB(11, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n",
639 			 buff->bottom, buff->top, num, buff->ExpSN));
640 
641 	return buff->ExpSN;
642 }
643 
644 /*
645  * next_sernum:
646  *   Return the current command serial number of the session
647  *   and optionally increment it for the next query
648  */
649 uint32_t
650 get_sernum(session_t *sess, pdu_t *pdu)
651 {
652 	uint32_t sn;
653 
654 	KASSERT(mutex_owned(&sess->lock));
655 
656 	sn = sess->CmdSN;
657 	if ((pdu->pdu.Opcode & OP_IMMEDIATE) == 0)
658 		atomic_inc_32(&sess->CmdSN);
659 	return sn;
660 }
661 
662 /*
663  * sernum_in_window:
664  *   Check wether serial number is in send window
665  *
666  */
667 int
668 sernum_in_window(session_t *sess)
669 {
670 
671 	KASSERT(mutex_owned(&sess->lock));
672 	return sn_a_le_b(sess->CmdSN, sess->MaxCmdSN);
673 }
674 
675 /*
676  * window_size:
677  *    Compute send window size
678  */
679 int
680 window_size(session_t *sess, int limit)
681 {
682 	uint32_t win;
683 
684 	KASSERT(mutex_owned(&sess->lock));
685 
686 	win = 0;
687 	if (sn_a_le_b(sess->CmdSN, sess->MaxCmdSN))
688 		win = sess->MaxCmdSN - sess->CmdSN + 1;
689 	if (win > INT_MAX || win > limit)
690 		win = limit;
691 
692 	return win;
693 }
694