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