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