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