Home | History | Annotate | Line # | Download | only in iscsi
      1 /*	$NetBSD: iscsi_utils.c,v 1.30 2026/06/06 08:29:08 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  * Digest functions
     41  *****************************************************************************/
     42 
     43 /*****************************************************************
     44  *
     45  * CRC LOOKUP TABLE
     46  * ================
     47  * The following CRC lookup table was generated automagically
     48  * by the Rocksoft^tm Model CRC Algorithm Table Generation
     49  * Program V1.0 using the following model parameters:
     50  *
     51  *    Width   : 4 bytes.
     52  *    Poly    : 0x1EDC6F41L
     53  *    Reverse : TRUE.
     54  *
     55  * For more information on the Rocksoft^tm Model CRC Algorithm,
     56  * see the document titled "A Painless Guide to CRC Error
     57  * Detection Algorithms" by Ross Williams
     58  * (ross (at) guest.adelaide.edu.au.). This document is likely to be
     59  * in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".
     60  *
     61  *****************************************************************/
     62 
     63 STATIC uint32_t crc_table[256] = {
     64 	0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
     65 	0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
     66 	0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
     67 	0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
     68 	0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
     69 	0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
     70 	0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
     71 	0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
     72 	0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
     73 	0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
     74 	0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
     75 	0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
     76 	0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
     77 	0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
     78 	0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
     79 	0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
     80 	0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
     81 	0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
     82 	0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
     83 	0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
     84 	0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
     85 	0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
     86 	0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
     87 	0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
     88 	0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
     89 	0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
     90 	0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
     91 	0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
     92 	0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
     93 	0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
     94 	0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
     95 	0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
     96 	0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
     97 	0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
     98 	0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
     99 	0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
    100 	0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
    101 	0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
    102 	0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
    103 	0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
    104 	0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
    105 	0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
    106 	0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
    107 	0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
    108 	0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
    109 	0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
    110 	0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
    111 	0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
    112 	0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
    113 	0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
    114 	0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
    115 	0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
    116 	0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
    117 	0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
    118 	0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
    119 	0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
    120 	0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
    121 	0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
    122 	0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
    123 	0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
    124 	0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
    125 	0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
    126 	0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
    127 	0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
    128 };
    129 
    130 
    131 /*
    132  * gen_digest:
    133  *    Generate an iSCSI CRC32C digest over the given data.
    134  *
    135  *    Parameters:
    136  *          buff   The data
    137  *          len   The length of the data in bytes
    138  *
    139  *    Returns:    The digest in network byte order
    140  */
    141 
    142 uint32_t
    143 gen_digest(const void *buff, size_t len)
    144 {
    145 	const uint8_t *bp = (const uint8_t *) buff;
    146 	uint32_t crc = 0xffffffff;
    147 
    148 	while (len--) {
    149 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
    150 	}
    151 	return htonl(bswap32(crc ^ 0xffffffff));
    152 }
    153 
    154 
    155 /*
    156  * gen_digest_2:
    157  *    Generate an iSCSI CRC32C digest over the given data, which is split over
    158  *    two buffers.
    159  *
    160  *    Parameters:
    161  *          buf1, buf2  The data
    162  *          len1, len2  The length of the data in bytes
    163  *
    164  *    Returns:    The digest in network byte order
    165  */
    166 
    167 uint32_t
    168 gen_digest_2(const void *buf1, size_t len1, const void *buf2, size_t len2)
    169 {
    170 	const uint8_t *bp = (const uint8_t *) buf1;
    171 	uint32_t crc = 0xffffffff;
    172 
    173 	while (len1--) {
    174 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
    175 	}
    176 	bp = (const uint8_t *) buf2;
    177 	while (len2--) {
    178 		crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
    179 	}
    180 	return htonl(bswap32(crc ^ 0xffffffff));
    181 }
    182 
    183 /*****************************************************************************
    184  * CCB management functions
    185  *****************************************************************************/
    186 
    187 /*
    188  * get_ccb:
    189  *    Get a CCB for the SCSI operation, waiting if none is available.
    190  *
    191  *    Parameter:
    192  *       sess     The session containing this CCB
    193  *       waitok   Whether waiting for a CCB is OK
    194  *
    195  *    Returns:    The CCB.
    196  */
    197 
    198 ccb_t *
    199 get_ccb(connection_t *conn, bool waitok)
    200 {
    201 	ccb_t *ccb;
    202 	session_t *sess = conn->c_session;
    203 
    204 	mutex_enter(&sess->s_lock);
    205 	for (;;) {
    206 		ccb = TAILQ_FIRST(&sess->s_ccb_pool);
    207 
    208 		DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
    209 
    210 		if (ccb != NULL) {
    211 			TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain);
    212 			break;
    213 		}
    214 
    215 		if (!waitok)
    216 			break;
    217 
    218 		cv_wait(&sess->s_ccb_cv, &sess->s_lock);
    219 	}
    220 	mutex_exit(&sess->s_lock);
    221 
    222 	if (ccb == NULL) {
    223 		DEB(15, ("get_ccb: failed"));
    224 		return NULL;
    225 	}
    226 
    227 	ccb->ccb_flags = 0;
    228 	ccb->ccb_timedout = TOUT_NONE;
    229 	ccb->ccb_xs = NULL;
    230 	ccb->ccb_temp_data = NULL;
    231 	ccb->ccb_text_data = NULL;
    232 	ccb->ccb_status = ISCSI_STATUS_SUCCESS;
    233 	ccb->ccb_ITT = (ccb->ccb_ITT & 0xffffff);
    234 	ccb->ccb_disp = CCBDISP_NOWAIT;
    235 	ccb->ccb_connection = conn;
    236 	ccb->ccb_num_timeouts = 0;
    237 	mutex_enter(&conn->c_lock);
    238 	conn->c_usecount++;
    239 	mutex_exit(&conn->c_lock);
    240 
    241 	DEBC(conn, 15, (
    242 		"get_ccb: ccb = %p, usecount = %d\n",
    243 		ccb, conn->c_usecount));
    244 
    245 	return ccb;
    246 }
    247 
    248 /*
    249  * free_ccb:
    250  *    Put a CCB back onto the free list.
    251  *
    252  *    Parameter:  The CCB.
    253  */
    254 
    255 void
    256 free_ccb(ccb_t *ccb)
    257 {
    258 	session_t *sess = ccb->ccb_session;
    259 	connection_t *conn = ccb->ccb_connection;
    260 	pdu_t *pdu;
    261 	pdu_disp_t pdisp;
    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 		pdisp = pdu->pdu_disp;
    292 		if ((pdu->pdu_flags & PDUF_INQUEUE) != 0) {
    293 			TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain);
    294 			pdu->pdu_flags &= ~PDUF_INQUEUE;
    295 		}
    296 		mutex_exit(&conn->c_lock);
    297 		if (pdisp > PDUDISP_FREE)
    298 			free_pdu(pdu);
    299 	}
    300 
    301 	mutex_enter(&sess->s_lock);
    302 	TAILQ_INSERT_TAIL(&sess->s_ccb_pool, ccb, ccb_chain);
    303 	cv_broadcast(&sess->s_ccb_cv);
    304 	mutex_exit(&sess->s_lock);
    305 }
    306 
    307 /*
    308  *    create_ccbs
    309  *       "Create" the pool of CCBs. This doesn't actually create the CCBs
    310  *       (they are allocated with the session structure), but it links them
    311  *       into the free-list.
    312  *
    313  *    Parameter:  The session owning the CCBs.
    314  */
    315 
    316 void
    317 create_ccbs(session_t *sess)
    318 {
    319 	int i;
    320 	ccb_t *ccb;
    321 	int sid = sess->s_id << 8;
    322 
    323 	/* Note: CCBs are initialized to 0 with connection structure */
    324 
    325 	for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) {
    326 		ccb->ccb_ITT = i | sid;
    327 		ccb->ccb_session = sess;
    328 
    329 		callout_init(&ccb->ccb_timeout, CALLOUT_MPSAFE);
    330 		callout_setfunc(&ccb->ccb_timeout, ccb_timeout_co, ccb);
    331 
    332 		DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT));
    333 		TAILQ_INSERT_HEAD(&sess->s_ccb_pool, ccb, ccb_chain);
    334 	}
    335 }
    336 
    337 /*
    338  *    destroy_ccbs
    339  *       Kill the callouts
    340  *
    341  *    Parameter:  The session owning the CCBs.
    342  */
    343 
    344 void
    345 destroy_ccbs(session_t *sess)
    346 {
    347 	int i;
    348 	ccb_t *ccb;
    349 
    350 	/* Note: CCBs are initialized to 0 with connection structure */
    351 
    352 	for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) {
    353 
    354 		callout_halt(&ccb->ccb_timeout, NULL);
    355 		callout_destroy(&ccb->ccb_timeout);
    356 
    357 		DEB(9, ("destroy_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT));
    358 		KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0);
    359 		KASSERT(ccb->ccb_disp == CCBDISP_UNUSED);
    360 		KASSERT(ccb->ccb_connection == NULL);
    361 		TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain);
    362 	}
    363 }
    364 
    365 /*
    366  * suspend_ccb:
    367  *    Put CCB on wait queue
    368  */
    369 void
    370 suspend_ccb(ccb_t *ccb, bool yes)
    371 {
    372 	connection_t *conn;
    373 
    374 	conn = ccb->ccb_connection;
    375 	KASSERT(conn != NULL);
    376 
    377 	KASSERT(mutex_owned(&conn->c_lock));
    378 
    379 	if (yes) {
    380 		KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0);
    381 		TAILQ_INSERT_TAIL(&conn->c_ccbs_waiting, ccb, ccb_chain);
    382 		ccb->ccb_flags |= CCBF_WAITQUEUE;
    383 	} else if (ccb->ccb_flags & CCBF_WAITQUEUE) {
    384 		TAILQ_REMOVE(&conn->c_ccbs_waiting, ccb, ccb_chain);
    385 		ccb->ccb_flags &= ~CCBF_WAITQUEUE;
    386 	}
    387 }
    388 
    389 /*
    390  * wake_ccb:
    391  *    Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
    392  *    either wake up the requesting thread, signal SCSIPI that we're done,
    393  *    or just free the CCB for CCBDISP_FREE.
    394  *
    395  *    Parameter:  The CCB to handle and the new status of the CCB
    396  */
    397 
    398 void
    399 wake_ccb(ccb_t *ccb, uint32_t status)
    400 {
    401 	ccb_disp_t disp;
    402 	connection_t *conn;
    403 
    404 	conn = ccb->ccb_connection;
    405 	KASSERT(conn != NULL);
    406 
    407 	DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n",
    408 		ccb->ccb_CmdSN, ccb, ccb->ccb_disp));
    409 
    410 	ccb_timeout_stop(ccb);
    411 
    412 	mutex_enter(&conn->c_lock);
    413 	disp = ccb->ccb_disp;
    414 	if (disp <= CCBDISP_NOWAIT ||
    415 		(disp == CCBDISP_DEFER && conn->c_state <= ST_WINDING_DOWN)) {
    416 		mutex_exit(&conn->c_lock);
    417 		return;
    418 	}
    419 
    420 	suspend_ccb(ccb, FALSE);
    421 
    422 	/* change the disposition so nobody tries this again */
    423 	ccb->ccb_disp = CCBDISP_BUSY;
    424 	ccb->ccb_status = status;
    425 
    426 	if (disp == CCBDISP_WAIT)
    427 		cv_broadcast(&conn->c_ccb_cv);
    428 	mutex_exit(&conn->c_lock);
    429 
    430 	switch(disp) {
    431 	case CCBDISP_WAIT:
    432 	case CCBDISP_DEFER:
    433 		break;
    434 
    435 	case CCBDISP_SCSIPI:
    436 		iscsi_done(ccb);
    437 		/* FALLTHROUGH */
    438 	case CCBDISP_FREE:
    439 		free_ccb(ccb);
    440 		break;
    441 	default:
    442 		DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
    443 		free_ccb(ccb);
    444 		break;
    445 	}
    446 }
    447 
    448 /*****************************************************************************
    449  * PDU management functions
    450  *****************************************************************************/
    451 
    452 /*
    453  * get_pdu:
    454  *    Get a PDU for the SCSI operation.
    455  *
    456  *    Parameter:
    457  *          conn     The connection this PDU should be associated with
    458  *          waitok   OK to wait for PDU if TRUE
    459  *
    460  *    Returns:    The PDU or NULL if none is available and waitok is FALSE.
    461  */
    462 
    463 pdu_t *
    464 get_pdu(connection_t *conn, bool waitok)
    465 {
    466 	pdu_t *pdu;
    467 
    468 	mutex_enter(&conn->c_lock);
    469 	for (;;) {
    470 		pdu = TAILQ_FIRST(&conn->c_pdu_pool);
    471 
    472 		if (pdu != NULL) {
    473 			TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain);
    474 			conn->c_pducount++;
    475 			break;
    476 		}
    477 
    478 		if (!waitok)
    479 			break;
    480 
    481 		cv_wait(&conn->c_pdu_cv, &conn->c_lock);
    482 	}
    483 	mutex_exit(&conn->c_lock);
    484 
    485 	if (pdu == NULL) {
    486 		DEB(15, ("get_pdu: failed"));
    487 		return NULL;
    488 	}
    489 
    490 	memset(pdu, 0, sizeof(pdu_t));
    491 	pdu->pdu_connection = conn;
    492 	pdu->pdu_disp = PDUDISP_FREE;
    493 
    494 	DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount));
    495 
    496 	return pdu;
    497 }
    498 
    499 /*
    500  * free_pdu:
    501  *    Put a PDU back onto the free list.
    502  *
    503  *    Parameter:  The PDU.
    504  */
    505 
    506 void
    507 free_pdu(pdu_t *pdu)
    508 {
    509 	connection_t *conn = pdu->pdu_connection;
    510 	pdu_disp_t pdisp;
    511 
    512 	DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount-1));
    513 
    514 	KASSERT((pdu->pdu_flags & PDUF_INQUEUE) == 0);
    515 
    516 	if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp)) {
    517 		DEBC(conn, 0, ("freeing UNUSED pdu\n"));
    518 		return;
    519 	}
    520 
    521 	pdu->pdu_disp = PDUDISP_UNUSED;
    522 
    523 	/* free temporary data in this PDU */
    524 	if (pdu->pdu_temp_data)
    525 		free(pdu->pdu_temp_data, M_TEMP);
    526 
    527 	mutex_enter(&conn->c_lock);
    528 	conn->c_pducount--;
    529 	TAILQ_INSERT_TAIL(&conn->c_pdu_pool, pdu, pdu_chain);
    530 	cv_broadcast(&conn->c_pdu_cv);
    531 	mutex_exit(&conn->c_lock);
    532 }
    533 
    534 /*
    535  *    create_pdus
    536  *       "Create" the pool of PDUs. This doesn't actually create the PDUs
    537  *       (they are allocated with the connection structure), but it links them
    538  *       into the free-list.
    539  *
    540  *    Parameter:  The connection owning the PDUs.
    541  */
    542 
    543 void
    544 create_pdus(connection_t *conn)
    545 {
    546 	int i;
    547 	pdu_t *pdu;
    548 
    549 	/* Note: PDUs are initialized to 0 with connection structure */
    550 
    551 	for (i = 0, pdu = conn->c_pdu; i < PDUS_PER_CONNECTION; i++, pdu++) {
    552 		TAILQ_INSERT_HEAD(&conn->c_pdu_pool, pdu, pdu_chain);
    553 	}
    554 }
    555 
    556 
    557 /*****************************************************************************
    558  * Serial Number management functions
    559  *****************************************************************************/
    560 
    561 /*
    562  * init_sernum:
    563  *    Initialize serial number buffer variables.
    564  *
    565  *    Parameter:
    566  *          buff   The serial number buffer.
    567  */
    568 
    569 void
    570 init_sernum(sernum_buffer_t *buff)
    571 {
    572 
    573 	buff->bottom = 0;
    574 	buff->top = 0;
    575 	buff->next_sn = 0;
    576 	buff->ExpSN = 0;
    577 }
    578 
    579 
    580 /*
    581  * add_sernum:
    582  *    Add a received serial number to the buffer.
    583  *    If the serial number is smaller than the expected one, it is ignored.
    584  *    If it is larger, all missing serial numbers are added as well.
    585  *
    586  *    Parameter:
    587  *          buff   The serial number buffer.
    588  *          num   The received serial number
    589  *
    590  *    Returns:
    591  *          0     if the received block is a duplicate
    592  *          1     if the number is the expected one
    593  *          >1    if the number is > the expected value, in this case the
    594  *                return value is the number of unacknowledged blocks
    595  *          <0    if the buffer is full (i.e. an excessive number of blocks
    596  *                is unacknowledged)
    597  */
    598 
    599 int
    600 add_sernum(sernum_buffer_t *buff, uint32_t num)
    601 {
    602 	int i, t, b;
    603 	uint32_t n;
    604 	int32_t diff;
    605 
    606 	/*
    607 	 * next_sn is the next expected SN, so normally diff should be 1.
    608 	 */
    609 	n = buff->next_sn;
    610 	diff = (num - n) + 1;
    611 
    612 	if (diff <= 0) {
    613 		return 0;				/* ignore if SN is smaller than expected (dup or retransmit) */
    614 	}
    615 
    616 	buff->next_sn = num + 1;
    617 	t = buff->top;
    618 	b = buff->bottom;
    619 
    620 	for (i = 0; i < diff; i++) {
    621 		buff->sernum[t] = n++;
    622 		buff->ack[t] = false;
    623 		t = (t + 1) % SERNUM_BUFFER_LENGTH;
    624 		if (t == b) {
    625 			DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff));
    626 			return -1;
    627 		}
    628 	}
    629 
    630 	buff->top = t;
    631 	DEB(11, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n",
    632 			 b, buff->sernum[b], buff->top, num, diff));
    633 
    634 	return diff;
    635 }
    636 
    637 
    638 /*
    639  * ack_sernum:
    640  *    Mark a received serial number as acknowledged. This does not necessarily
    641  *    change the associated ExpSN if there are lower serial numbers in the
    642  *    buffer.
    643  *
    644  *    Parameter:
    645  *          buff   The serial number buffer.
    646  *          num   The serial number to acknowledge.
    647  *
    648  *    Returns:    The value of ExpSN.
    649  */
    650 
    651 uint32_t
    652 ack_sernum(sernum_buffer_t *buff, uint32_t num)
    653 {
    654 	int b = buff->bottom;
    655 	int t = buff->top;
    656 
    657 	/* shortcut for most likely case */
    658 	if (t == (b + 1) && num == buff->sernum[b]) {
    659 		/* buffer is now empty, reset top */
    660 		buff->top = b;
    661 	} else if (b != t) {
    662 		for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
    663 			if (!sn_a_lt_b(buff->sernum[b], num))
    664 				break;
    665 		}
    666 		if (num == buff->sernum[b]) {
    667 			if (b == buff->bottom)
    668 				buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH;
    669 			else
    670 				buff->ack[b] = true;
    671 		}
    672 
    673 		for (b = buff->bottom, num = buff->sernum[b] - 1;
    674 			 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
    675 			num = buff->sernum[b];
    676 		}
    677 	}
    678 
    679 	if (!sn_a_lt_b(num, buff->ExpSN))
    680 		buff->ExpSN = num + 1;
    681 
    682 	DEB(11, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n",
    683 			 buff->bottom, buff->top, num, buff->ExpSN));
    684 
    685 	return buff->ExpSN;
    686 }
    687 
    688 /*
    689  * next_sernum:
    690  *   Return the current command serial number of the session
    691  *   and optionally increment it for the next query
    692  */
    693 uint32_t
    694 get_sernum(session_t *sess, pdu_t *pdu)
    695 {
    696 	uint32_t sn;
    697 
    698 	KASSERT(mutex_owned(&sess->s_lock));
    699 
    700 	sn = sess->s_CmdSN;
    701 	if ((pdu->pdu_hdr.pduh_Opcode & OP_IMMEDIATE) == 0)
    702 		atomic_inc_32(&sess->s_CmdSN);
    703 	return sn;
    704 }
    705 
    706 /*
    707  * sernum_in_window:
    708  *   Check whether serial number is in send window
    709  *
    710  */
    711 int
    712 sernum_in_window(session_t *sess)
    713 {
    714 
    715 	KASSERT(mutex_owned(&sess->s_lock));
    716 	return sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN);
    717 }
    718 
    719 /*
    720  * window_size:
    721  *    Compute send window size
    722  */
    723 int
    724 window_size(session_t *sess, int limit)
    725 {
    726 	uint32_t win;
    727 
    728 	KASSERT(mutex_owned(&sess->s_lock));
    729 
    730 	win = 0;
    731 	if (sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN))
    732 		win = sess->s_MaxCmdSN - sess->s_CmdSN + 1;
    733 	if (win > INT_MAX || win > limit)
    734 		win = limit;
    735 
    736 	return win;
    737 }
    738