1 1.29 mlelstv /* $NetBSD: iscsi_utils.c,v 1.29 2023/11/25 10:08:27 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.29 mlelstv mutex_enter(&conn->c_lock); 239 1.29 mlelstv conn->c_usecount++; 240 1.29 mlelstv mutex_exit(&conn->c_lock); 241 1.9 mlelstv 242 1.12 mlelstv DEBC(conn, 15, ( 243 1.9 mlelstv "get_ccb: ccb = %p, usecount = %d\n", 244 1.24 christos ccb, conn->c_usecount)); 245 1.1 agc 246 1.1 agc return ccb; 247 1.1 agc } 248 1.1 agc 249 1.1 agc /* 250 1.1 agc * free_ccb: 251 1.1 agc * Put a CCB back onto the free list. 252 1.1 agc * 253 1.1 agc * Parameter: The CCB. 254 1.1 agc */ 255 1.1 agc 256 1.1 agc void 257 1.1 agc free_ccb(ccb_t *ccb) 258 1.1 agc { 259 1.24 christos session_t *sess = ccb->ccb_session; 260 1.24 christos connection_t *conn = ccb->ccb_connection; 261 1.1 agc pdu_t *pdu; 262 1.9 mlelstv 263 1.19 mlelstv DEBC(conn, 15, ( 264 1.9 mlelstv "free_ccb: ccb = %p, usecount = %d\n", 265 1.24 christos ccb, conn->c_usecount-1)); 266 1.5 mlelstv 267 1.24 christos KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0); 268 1.1 agc 269 1.24 christos ccb->ccb_connection = NULL; 270 1.29 mlelstv mutex_enter(&conn->c_lock); 271 1.29 mlelstv conn->c_usecount--; 272 1.29 mlelstv mutex_exit(&conn->c_lock); 273 1.2 mlelstv 274 1.24 christos if (ccb->ccb_disp > CCBDISP_NOWAIT) { 275 1.24 christos DEBOUT(("Freeing CCB with disp %d\n",ccb->ccb_disp)); 276 1.9 mlelstv } 277 1.9 mlelstv 278 1.24 christos ccb->ccb_disp = CCBDISP_UNUSED; 279 1.1 agc 280 1.1 agc /* free temporary data */ 281 1.24 christos if (ccb->ccb_temp_data != NULL) { 282 1.24 christos free(ccb->ccb_temp_data, M_TEMP); 283 1.1 agc } 284 1.24 christos if (ccb->ccb_text_data != NULL) { 285 1.24 christos free(ccb->ccb_text_data, M_TEMP); 286 1.1 agc } 287 1.1 agc /* free PDU waiting for ACK */ 288 1.24 christos if ((pdu = ccb->ccb_pdu_waiting) != NULL) { 289 1.24 christos ccb->ccb_pdu_waiting = NULL; 290 1.24 christos mutex_enter(&conn->c_lock); 291 1.24 christos if ((pdu->pdu_flags & PDUF_INQUEUE) != 0) { 292 1.24 christos TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain); 293 1.24 christos pdu->pdu_flags &= ~PDUF_INQUEUE; 294 1.19 mlelstv } 295 1.24 christos mutex_exit(&conn->c_lock); 296 1.1 agc free_pdu(pdu); 297 1.1 agc } 298 1.1 agc 299 1.24 christos mutex_enter(&sess->s_lock); 300 1.24 christos TAILQ_INSERT_TAIL(&sess->s_ccb_pool, ccb, ccb_chain); 301 1.24 christos cv_broadcast(&sess->s_ccb_cv); 302 1.24 christos mutex_exit(&sess->s_lock); 303 1.1 agc } 304 1.1 agc 305 1.1 agc /* 306 1.1 agc * create_ccbs 307 1.1 agc * "Create" the pool of CCBs. This doesn't actually create the CCBs 308 1.1 agc * (they are allocated with the session structure), but it links them 309 1.1 agc * into the free-list. 310 1.1 agc * 311 1.1 agc * Parameter: The session owning the CCBs. 312 1.1 agc */ 313 1.1 agc 314 1.1 agc void 315 1.1 agc create_ccbs(session_t *sess) 316 1.1 agc { 317 1.1 agc int i; 318 1.1 agc ccb_t *ccb; 319 1.24 christos int sid = sess->s_id << 8; 320 1.1 agc 321 1.1 agc /* Note: CCBs are initialized to 0 with connection structure */ 322 1.1 agc 323 1.24 christos for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) { 324 1.24 christos ccb->ccb_ITT = i | sid; 325 1.24 christos ccb->ccb_session = sess; 326 1.1 agc 327 1.24 christos callout_init(&ccb->ccb_timeout, CALLOUT_MPSAFE); 328 1.24 christos callout_setfunc(&ccb->ccb_timeout, ccb_timeout_co, ccb); 329 1.1 agc 330 1.24 christos DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT)); 331 1.24 christos TAILQ_INSERT_HEAD(&sess->s_ccb_pool, ccb, ccb_chain); 332 1.1 agc } 333 1.1 agc } 334 1.1 agc 335 1.5 mlelstv /* 336 1.23 mlelstv * destroy_ccbs 337 1.23 mlelstv * Kill the callouts 338 1.23 mlelstv * 339 1.23 mlelstv * Parameter: The session owning the CCBs. 340 1.23 mlelstv */ 341 1.23 mlelstv 342 1.23 mlelstv void 343 1.23 mlelstv destroy_ccbs(session_t *sess) 344 1.23 mlelstv { 345 1.23 mlelstv int i; 346 1.23 mlelstv ccb_t *ccb; 347 1.23 mlelstv 348 1.23 mlelstv /* Note: CCBs are initialized to 0 with connection structure */ 349 1.23 mlelstv 350 1.24 christos for (i = 0, ccb = sess->s_ccb; i < CCBS_PER_SESSION; i++, ccb++) { 351 1.23 mlelstv 352 1.24 christos callout_halt(&ccb->ccb_timeout, NULL); 353 1.24 christos callout_destroy(&ccb->ccb_timeout); 354 1.23 mlelstv 355 1.24 christos DEB(9, ("destroy_ccbs: ccb %p itt %x\n", ccb, ccb->ccb_ITT)); 356 1.24 christos KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0); 357 1.24 christos KASSERT(ccb->ccb_disp == CCBDISP_UNUSED); 358 1.24 christos KASSERT(ccb->ccb_connection == NULL); 359 1.24 christos TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain); 360 1.23 mlelstv } 361 1.23 mlelstv } 362 1.23 mlelstv 363 1.23 mlelstv /* 364 1.5 mlelstv * suspend_ccb: 365 1.5 mlelstv * Put CCB on wait queue 366 1.5 mlelstv */ 367 1.5 mlelstv void 368 1.5 mlelstv suspend_ccb(ccb_t *ccb, bool yes) 369 1.5 mlelstv { 370 1.5 mlelstv connection_t *conn; 371 1.5 mlelstv 372 1.24 christos conn = ccb->ccb_connection; 373 1.22 mlelstv KASSERT(conn != NULL); 374 1.21 mlelstv 375 1.24 christos KASSERT(mutex_owned(&conn->c_lock)); 376 1.21 mlelstv 377 1.5 mlelstv if (yes) { 378 1.24 christos KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0); 379 1.24 christos TAILQ_INSERT_TAIL(&conn->c_ccbs_waiting, ccb, ccb_chain); 380 1.24 christos ccb->ccb_flags |= CCBF_WAITQUEUE; 381 1.24 christos } else if (ccb->ccb_flags & CCBF_WAITQUEUE) { 382 1.24 christos TAILQ_REMOVE(&conn->c_ccbs_waiting, ccb, ccb_chain); 383 1.24 christos ccb->ccb_flags &= ~CCBF_WAITQUEUE; 384 1.5 mlelstv } 385 1.5 mlelstv } 386 1.5 mlelstv 387 1.5 mlelstv /* 388 1.1 agc * wake_ccb: 389 1.1 agc * Wake up (or dispose of) a CCB. Depending on the CCB's disposition, 390 1.1 agc * either wake up the requesting thread, signal SCSIPI that we're done, 391 1.1 agc * or just free the CCB for CCBDISP_FREE. 392 1.1 agc * 393 1.5 mlelstv * Parameter: The CCB to handle and the new status of the CCB 394 1.1 agc */ 395 1.1 agc 396 1.1 agc void 397 1.5 mlelstv wake_ccb(ccb_t *ccb, uint32_t status) 398 1.1 agc { 399 1.1 agc ccb_disp_t disp; 400 1.1 agc connection_t *conn; 401 1.1 agc 402 1.24 christos conn = ccb->ccb_connection; 403 1.22 mlelstv KASSERT(conn != NULL); 404 1.1 agc 405 1.21 mlelstv DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n", 406 1.24 christos ccb->ccb_CmdSN, ccb, ccb->ccb_disp)); 407 1.1 agc 408 1.11 mlelstv ccb_timeout_stop(ccb); 409 1.1 agc 410 1.24 christos mutex_enter(&conn->c_lock); 411 1.24 christos disp = ccb->ccb_disp; 412 1.1 agc if (disp <= CCBDISP_NOWAIT || 413 1.24 christos (disp == CCBDISP_DEFER && conn->c_state <= ST_WINDING_DOWN)) { 414 1.24 christos mutex_exit(&conn->c_lock); 415 1.1 agc return; 416 1.1 agc } 417 1.1 agc 418 1.5 mlelstv suspend_ccb(ccb, FALSE); 419 1.1 agc 420 1.1 agc /* change the disposition so nobody tries this again */ 421 1.24 christos ccb->ccb_disp = CCBDISP_BUSY; 422 1.24 christos ccb->ccb_status = status; 423 1.22 mlelstv 424 1.22 mlelstv if (disp == CCBDISP_WAIT) 425 1.24 christos cv_broadcast(&conn->c_ccb_cv); 426 1.24 christos mutex_exit(&conn->c_lock); 427 1.1 agc 428 1.22 mlelstv switch(disp) { 429 1.1 agc case CCBDISP_WAIT: 430 1.22 mlelstv case CCBDISP_DEFER: 431 1.1 agc break; 432 1.1 agc 433 1.1 agc case CCBDISP_SCSIPI: 434 1.1 agc iscsi_done(ccb); 435 1.25 mrg /* FALLTHROUGH */ 436 1.22 mlelstv case CCBDISP_FREE: 437 1.5 mlelstv free_ccb(ccb); 438 1.1 agc break; 439 1.1 agc default: 440 1.5 mlelstv DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp)); 441 1.1 agc free_ccb(ccb); 442 1.1 agc break; 443 1.1 agc } 444 1.1 agc } 445 1.1 agc 446 1.1 agc /***************************************************************************** 447 1.1 agc * PDU management functions 448 1.1 agc *****************************************************************************/ 449 1.1 agc 450 1.1 agc /* 451 1.5 mlelstv * get_pdu: 452 1.1 agc * Get a PDU for the SCSI operation. 453 1.1 agc * 454 1.1 agc * Parameter: 455 1.1 agc * conn The connection this PDU should be associated with 456 1.1 agc * waitok OK to wait for PDU if TRUE 457 1.1 agc * 458 1.1 agc * Returns: The PDU or NULL if none is available and waitok is FALSE. 459 1.1 agc */ 460 1.1 agc 461 1.1 agc pdu_t * 462 1.5 mlelstv get_pdu(connection_t *conn, bool waitok) 463 1.1 agc { 464 1.1 agc pdu_t *pdu; 465 1.1 agc 466 1.24 christos mutex_enter(&conn->c_lock); 467 1.28 mlelstv for (;;) { 468 1.24 christos pdu = TAILQ_FIRST(&conn->c_pdu_pool); 469 1.28 mlelstv 470 1.28 mlelstv if (pdu != NULL) { 471 1.24 christos TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain); 472 1.28 mlelstv conn->c_pducount++; 473 1.28 mlelstv break; 474 1.28 mlelstv } 475 1.5 mlelstv 476 1.28 mlelstv if (!waitok) 477 1.28 mlelstv break; 478 1.28 mlelstv 479 1.28 mlelstv cv_wait(&conn->c_pdu_cv, &conn->c_lock); 480 1.28 mlelstv } 481 1.24 christos mutex_exit(&conn->c_lock); 482 1.1 agc 483 1.28 mlelstv if (pdu == NULL) { 484 1.28 mlelstv DEB(15, ("get_pdu: failed")); 485 1.28 mlelstv return NULL; 486 1.28 mlelstv } 487 1.28 mlelstv 488 1.1 agc memset(pdu, 0, sizeof(pdu_t)); 489 1.24 christos pdu->pdu_connection = conn; 490 1.24 christos pdu->pdu_disp = PDUDISP_FREE; 491 1.1 agc 492 1.24 christos DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount)); 493 1.21 mlelstv 494 1.1 agc return pdu; 495 1.1 agc } 496 1.1 agc 497 1.1 agc /* 498 1.1 agc * free_pdu: 499 1.1 agc * Put a PDU back onto the free list. 500 1.1 agc * 501 1.1 agc * Parameter: The PDU. 502 1.1 agc */ 503 1.1 agc 504 1.1 agc void 505 1.1 agc free_pdu(pdu_t *pdu) 506 1.1 agc { 507 1.24 christos connection_t *conn = pdu->pdu_connection; 508 1.1 agc pdu_disp_t pdisp; 509 1.1 agc 510 1.24 christos DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->c_pducount-1)); 511 1.21 mlelstv 512 1.24 christos KASSERT((pdu->pdu_flags & PDUF_INQUEUE) == 0); 513 1.14 mlelstv 514 1.28 mlelstv if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp)) { 515 1.28 mlelstv DEBC(conn, 0, ("freeing UNUSED pdu\n")); 516 1.1 agc return; 517 1.28 mlelstv } 518 1.28 mlelstv 519 1.24 christos pdu->pdu_disp = PDUDISP_UNUSED; 520 1.1 agc 521 1.1 agc /* free temporary data in this PDU */ 522 1.24 christos if (pdu->pdu_temp_data) 523 1.24 christos free(pdu->pdu_temp_data, M_TEMP); 524 1.1 agc 525 1.24 christos mutex_enter(&conn->c_lock); 526 1.28 mlelstv conn->c_pducount--; 527 1.24 christos TAILQ_INSERT_TAIL(&conn->c_pdu_pool, pdu, pdu_chain); 528 1.24 christos cv_broadcast(&conn->c_pdu_cv); 529 1.24 christos mutex_exit(&conn->c_lock); 530 1.1 agc } 531 1.1 agc 532 1.1 agc /* 533 1.1 agc * create_pdus 534 1.1 agc * "Create" the pool of PDUs. This doesn't actually create the PDUs 535 1.1 agc * (they are allocated with the connection structure), but it links them 536 1.1 agc * into the free-list. 537 1.1 agc * 538 1.1 agc * Parameter: The connection owning the PDUs. 539 1.1 agc */ 540 1.1 agc 541 1.1 agc void 542 1.1 agc create_pdus(connection_t *conn) 543 1.1 agc { 544 1.1 agc int i; 545 1.1 agc pdu_t *pdu; 546 1.1 agc 547 1.1 agc /* Note: PDUs are initialized to 0 with connection structure */ 548 1.1 agc 549 1.24 christos for (i = 0, pdu = conn->c_pdu; i < PDUS_PER_CONNECTION; i++, pdu++) { 550 1.24 christos TAILQ_INSERT_HEAD(&conn->c_pdu_pool, pdu, pdu_chain); 551 1.1 agc } 552 1.1 agc } 553 1.1 agc 554 1.1 agc 555 1.1 agc /***************************************************************************** 556 1.1 agc * Serial Number management functions 557 1.1 agc *****************************************************************************/ 558 1.1 agc 559 1.1 agc /* 560 1.1 agc * init_sernum: 561 1.1 agc * Initialize serial number buffer variables. 562 1.1 agc * 563 1.1 agc * Parameter: 564 1.1 agc * buff The serial number buffer. 565 1.1 agc */ 566 1.1 agc 567 1.1 agc void 568 1.1 agc init_sernum(sernum_buffer_t *buff) 569 1.1 agc { 570 1.1 agc 571 1.1 agc buff->bottom = 0; 572 1.1 agc buff->top = 0; 573 1.1 agc buff->next_sn = 0; 574 1.1 agc buff->ExpSN = 0; 575 1.1 agc } 576 1.1 agc 577 1.1 agc 578 1.1 agc /* 579 1.1 agc * add_sernum: 580 1.1 agc * Add a received serial number to the buffer. 581 1.1 agc * If the serial number is smaller than the expected one, it is ignored. 582 1.1 agc * If it is larger, all missing serial numbers are added as well. 583 1.1 agc * 584 1.1 agc * Parameter: 585 1.1 agc * buff The serial number buffer. 586 1.1 agc * num The received serial number 587 1.1 agc * 588 1.1 agc * Returns: 589 1.1 agc * 0 if the received block is a duplicate 590 1.1 agc * 1 if the number is the expected one 591 1.26 msaitoh * >1 if the number is > the expected value, in this case the 592 1.1 agc * return value is the number of unacknowledged blocks 593 1.1 agc * <0 if the buffer is full (i.e. an excessive number of blocks 594 1.1 agc * is unacknowledged) 595 1.1 agc */ 596 1.1 agc 597 1.1 agc int 598 1.1 agc add_sernum(sernum_buffer_t *buff, uint32_t num) 599 1.1 agc { 600 1.3 mlelstv int i, t, b; 601 1.3 mlelstv uint32_t n; 602 1.3 mlelstv int32_t diff; 603 1.1 agc 604 1.1 agc /* 605 1.1 agc * next_sn is the next expected SN, so normally diff should be 1. 606 1.1 agc */ 607 1.1 agc n = buff->next_sn; 608 1.1 agc diff = (num - n) + 1; 609 1.1 agc 610 1.1 agc if (diff <= 0) { 611 1.1 agc return 0; /* ignore if SN is smaller than expected (dup or retransmit) */ 612 1.1 agc } 613 1.1 agc 614 1.1 agc buff->next_sn = num + 1; 615 1.1 agc t = buff->top; 616 1.1 agc b = buff->bottom; 617 1.1 agc 618 1.1 agc for (i = 0; i < diff; i++) { 619 1.1 agc buff->sernum[t] = n++; 620 1.8 joerg buff->ack[t] = false; 621 1.1 agc t = (t + 1) % SERNUM_BUFFER_LENGTH; 622 1.1 agc if (t == b) { 623 1.1 agc DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff)); 624 1.1 agc return -1; 625 1.1 agc } 626 1.1 agc } 627 1.1 agc 628 1.1 agc buff->top = t; 629 1.12 mlelstv DEB(11, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n", 630 1.1 agc b, buff->sernum[b], buff->top, num, diff)); 631 1.1 agc 632 1.1 agc return diff; 633 1.1 agc } 634 1.1 agc 635 1.1 agc 636 1.1 agc /* 637 1.1 agc * ack_sernum: 638 1.1 agc * Mark a received serial number as acknowledged. This does not necessarily 639 1.1 agc * change the associated ExpSN if there are lower serial numbers in the 640 1.1 agc * buffer. 641 1.1 agc * 642 1.1 agc * Parameter: 643 1.1 agc * buff The serial number buffer. 644 1.1 agc * num The serial number to acknowledge. 645 1.1 agc * 646 1.1 agc * Returns: The value of ExpSN. 647 1.1 agc */ 648 1.1 agc 649 1.1 agc uint32_t 650 1.1 agc ack_sernum(sernum_buffer_t *buff, uint32_t num) 651 1.1 agc { 652 1.1 agc int b = buff->bottom; 653 1.1 agc int t = buff->top; 654 1.1 agc 655 1.1 agc /* shortcut for most likely case */ 656 1.1 agc if (t == (b + 1) && num == buff->sernum[b]) { 657 1.1 agc /* buffer is now empty, reset top */ 658 1.1 agc buff->top = b; 659 1.1 agc } else if (b != t) { 660 1.1 agc for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 661 1.1 agc if (!sn_a_lt_b(buff->sernum[b], num)) 662 1.1 agc break; 663 1.1 agc } 664 1.1 agc if (num == buff->sernum[b]) { 665 1.1 agc if (b == buff->bottom) 666 1.1 agc buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH; 667 1.1 agc else 668 1.8 joerg buff->ack[b] = true; 669 1.1 agc } 670 1.1 agc 671 1.1 agc for (b = buff->bottom, num = buff->sernum[b] - 1; 672 1.1 agc b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 673 1.1 agc num = buff->sernum[b]; 674 1.1 agc } 675 1.1 agc } 676 1.1 agc 677 1.1 agc if (!sn_a_lt_b(num, buff->ExpSN)) 678 1.1 agc buff->ExpSN = num + 1; 679 1.1 agc 680 1.12 mlelstv DEB(11, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n", 681 1.1 agc buff->bottom, buff->top, num, buff->ExpSN)); 682 1.1 agc 683 1.1 agc return buff->ExpSN; 684 1.1 agc } 685 1.10 mlelstv 686 1.10 mlelstv /* 687 1.10 mlelstv * next_sernum: 688 1.10 mlelstv * Return the current command serial number of the session 689 1.10 mlelstv * and optionally increment it for the next query 690 1.10 mlelstv */ 691 1.10 mlelstv uint32_t 692 1.21 mlelstv get_sernum(session_t *sess, pdu_t *pdu) 693 1.10 mlelstv { 694 1.10 mlelstv uint32_t sn; 695 1.10 mlelstv 696 1.24 christos KASSERT(mutex_owned(&sess->s_lock)); 697 1.10 mlelstv 698 1.24 christos sn = sess->s_CmdSN; 699 1.24 christos if ((pdu->pdu_hdr.pduh_Opcode & OP_IMMEDIATE) == 0) 700 1.24 christos atomic_inc_32(&sess->s_CmdSN); 701 1.10 mlelstv return sn; 702 1.10 mlelstv } 703 1.10 mlelstv 704 1.10 mlelstv /* 705 1.10 mlelstv * sernum_in_window: 706 1.27 maya * Check whether serial number is in send window 707 1.10 mlelstv * 708 1.10 mlelstv */ 709 1.10 mlelstv int 710 1.10 mlelstv sernum_in_window(session_t *sess) 711 1.10 mlelstv { 712 1.10 mlelstv 713 1.24 christos KASSERT(mutex_owned(&sess->s_lock)); 714 1.24 christos return sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN); 715 1.10 mlelstv } 716 1.10 mlelstv 717 1.21 mlelstv /* 718 1.21 mlelstv * window_size: 719 1.21 mlelstv * Compute send window size 720 1.21 mlelstv */ 721 1.21 mlelstv int 722 1.21 mlelstv window_size(session_t *sess, int limit) 723 1.21 mlelstv { 724 1.21 mlelstv uint32_t win; 725 1.21 mlelstv 726 1.24 christos KASSERT(mutex_owned(&sess->s_lock)); 727 1.21 mlelstv 728 1.21 mlelstv win = 0; 729 1.24 christos if (sn_a_le_b(sess->s_CmdSN, sess->s_MaxCmdSN)) 730 1.24 christos win = sess->s_MaxCmdSN - sess->s_CmdSN + 1; 731 1.21 mlelstv if (win > INT_MAX || win > limit) 732 1.21 mlelstv win = limit; 733 1.21 mlelstv 734 1.21 mlelstv return win; 735 1.21 mlelstv } 736