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