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