Home | History | Annotate | Line # | Download | only in iscsi
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