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