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