1 /* $NetBSD: iscsi_utils.c,v 1.22 2016/12/25 06:55:28 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@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(void *buff, int len) 145 { 146 uint8_t *bp = (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(void *buf1, int len1, void *buf2, int len2) 170 { 171 uint8_t *bp = (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 = (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->session; 204 205 mutex_enter(&sess->lock); 206 do { 207 ccb = TAILQ_FIRST(&sess->ccb_pool); 208 DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok)); 209 210 if (ccb != NULL) { 211 TAILQ_REMOVE(&sess->ccb_pool, ccb, chain); 212 } else { 213 if (!waitok || conn->terminating) { 214 mutex_exit(&sess->lock); 215 return NULL; 216 } 217 cv_wait(&sess->ccb_cv, &sess->lock); 218 } 219 } while (ccb == NULL); 220 mutex_exit(&sess->lock); 221 222 ccb->flags = 0; 223 ccb->timedout = TOUT_NONE; 224 ccb->xs = NULL; 225 ccb->temp_data = NULL; 226 ccb->text_data = NULL; 227 ccb->status = ISCSI_STATUS_SUCCESS; 228 ccb->ITT = (ccb->ITT & 0xffffff); 229 ccb->disp = CCBDISP_NOWAIT; 230 ccb->connection = conn; 231 ccb->num_timeouts = 0; 232 atomic_inc_uint(&conn->usecount); 233 234 DEBC(conn, 15, ( 235 "get_ccb: ccb = %p, usecount = %d\n", 236 ccb, conn->usecount)); 237 238 return ccb; 239 } 240 241 /* 242 * free_ccb: 243 * Put a CCB back onto the free list. 244 * 245 * Parameter: The CCB. 246 */ 247 248 void 249 free_ccb(ccb_t *ccb) 250 { 251 session_t *sess = ccb->session; 252 connection_t *conn = ccb->connection; 253 pdu_t *pdu; 254 255 DEBC(conn, 15, ( 256 "free_ccb: ccb = %p, usecount = %d\n", 257 ccb, conn->usecount-1)); 258 259 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 260 261 atomic_dec_uint(&conn->usecount); 262 ccb->connection = NULL; 263 264 if (ccb->disp > CCBDISP_NOWAIT) { 265 DEBOUT(("Freeing CCB with disp %d\n",ccb->disp)); 266 } 267 268 ccb->disp = CCBDISP_UNUSED; 269 270 /* free temporary data */ 271 if (ccb->temp_data != NULL) { 272 free(ccb->temp_data, M_TEMP); 273 } 274 if (ccb->text_data != NULL) { 275 free(ccb->text_data, M_TEMP); 276 } 277 /* free PDU waiting for ACK */ 278 if ((pdu = ccb->pdu_waiting) != NULL) { 279 ccb->pdu_waiting = NULL; 280 mutex_enter(&conn->lock); 281 if ((pdu->flags & PDUF_INQUEUE) != 0) { 282 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 283 pdu->flags &= ~PDUF_INQUEUE; 284 } 285 mutex_exit(&conn->lock); 286 free_pdu(pdu); 287 } 288 289 mutex_enter(&sess->lock); 290 TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain); 291 cv_broadcast(&sess->ccb_cv); 292 mutex_exit(&sess->lock); 293 } 294 295 /* 296 * create_ccbs 297 * "Create" the pool of CCBs. This doesn't actually create the CCBs 298 * (they are allocated with the session structure), but it links them 299 * into the free-list. 300 * 301 * Parameter: The session owning the CCBs. 302 */ 303 304 void 305 create_ccbs(session_t *sess) 306 { 307 int i; 308 ccb_t *ccb; 309 int sid = sess->id << 8; 310 311 /* Note: CCBs are initialized to 0 with connection structure */ 312 313 for (i = 0, ccb = sess->ccb; i < CCBS_PER_SESSION; i++, ccb++) { 314 ccb->ITT = i | sid; 315 ccb->session = sess; 316 317 callout_init(&ccb->timeout, CALLOUT_MPSAFE); 318 callout_setfunc(&ccb->timeout, ccb_timeout_co, ccb); 319 320 DEB(9, ("Create_ccbs: ccb %p itt %x\n", ccb, ccb->ITT)); 321 TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain); 322 } 323 } 324 325 /* 326 * suspend_ccb: 327 * Put CCB on wait queue 328 */ 329 void 330 suspend_ccb(ccb_t *ccb, bool yes) 331 { 332 connection_t *conn; 333 334 conn = ccb->connection; 335 KASSERT(conn != NULL); 336 337 KASSERT(mutex_owned(&conn->lock)); 338 339 if (yes) { 340 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 341 TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain); 342 ccb->flags |= CCBF_WAITQUEUE; 343 } else if (ccb->flags & CCBF_WAITQUEUE) { 344 TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain); 345 ccb->flags &= ~CCBF_WAITQUEUE; 346 } 347 } 348 349 /* 350 * wake_ccb: 351 * Wake up (or dispose of) a CCB. Depending on the CCB's disposition, 352 * either wake up the requesting thread, signal SCSIPI that we're done, 353 * or just free the CCB for CCBDISP_FREE. 354 * 355 * Parameter: The CCB to handle and the new status of the CCB 356 */ 357 358 void 359 wake_ccb(ccb_t *ccb, uint32_t status) 360 { 361 ccb_disp_t disp; 362 connection_t *conn; 363 364 conn = ccb->connection; 365 KASSERT(conn != NULL); 366 367 DEBC(conn, 9, ("CCB %d done, ccb = %p, disp = %d\n", 368 ccb->CmdSN, ccb, ccb->disp)); 369 370 ccb_timeout_stop(ccb); 371 372 mutex_enter(&conn->lock); 373 disp = ccb->disp; 374 if (disp <= CCBDISP_NOWAIT || 375 (disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) { 376 mutex_exit(&conn->lock); 377 return; 378 } 379 380 suspend_ccb(ccb, FALSE); 381 382 /* change the disposition so nobody tries this again */ 383 ccb->disp = CCBDISP_BUSY; 384 ccb->status = status; 385 386 if (disp == CCBDISP_WAIT) 387 cv_broadcast(&conn->ccb_cv); 388 mutex_exit(&conn->lock); 389 390 switch(disp) { 391 case CCBDISP_WAIT: 392 case CCBDISP_DEFER: 393 break; 394 395 case CCBDISP_SCSIPI: 396 iscsi_done(ccb); 397 /* FALLTRHOUGH */ 398 case CCBDISP_FREE: 399 free_ccb(ccb); 400 break; 401 default: 402 DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp)); 403 free_ccb(ccb); 404 break; 405 } 406 } 407 408 /***************************************************************************** 409 * PDU management functions 410 *****************************************************************************/ 411 412 /* 413 * get_pdu: 414 * Get a PDU for the SCSI operation. 415 * 416 * Parameter: 417 * conn The connection this PDU should be associated with 418 * waitok OK to wait for PDU if TRUE 419 * 420 * Returns: The PDU or NULL if none is available and waitok is FALSE. 421 */ 422 423 pdu_t * 424 get_pdu(connection_t *conn, bool waitok) 425 { 426 pdu_t *pdu; 427 428 mutex_enter(&conn->lock); 429 do { 430 pdu = TAILQ_FIRST(&conn->pdu_pool); 431 if (pdu != NULL) 432 TAILQ_REMOVE(&conn->pdu_pool, pdu, chain); 433 434 if (pdu == NULL) { 435 if (!waitok || conn->terminating) { 436 mutex_exit(&conn->lock); 437 DEB(15, ("get_pdu: failed")); 438 return NULL; 439 } 440 cv_wait(&conn->pdu_cv, &conn->lock); 441 } 442 } while (pdu == NULL); 443 atomic_inc_uint(&conn->pducount); 444 mutex_exit(&conn->lock); 445 446 memset(pdu, 0, sizeof(pdu_t)); 447 pdu->connection = conn; 448 pdu->disp = PDUDISP_FREE; 449 450 DEBC(conn, 15, ("get_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount)); 451 452 return pdu; 453 } 454 455 /* 456 * free_pdu: 457 * Put a PDU back onto the free list. 458 * 459 * Parameter: The PDU. 460 */ 461 462 void 463 free_pdu(pdu_t *pdu) 464 { 465 connection_t *conn = pdu->connection; 466 pdu_disp_t pdisp; 467 468 DEBC(conn, 15, ("free_pdu: pdu = %p, usecount = %d\n", pdu, conn->pducount-1)); 469 470 KASSERT((pdu->flags & PDUF_INQUEUE) == 0); 471 472 if (PDUDISP_UNUSED == (pdisp = pdu->disp)) 473 return; 474 pdu->disp = PDUDISP_UNUSED; 475 476 /* free temporary data in this PDU */ 477 if (pdu->temp_data) 478 free(pdu->temp_data, M_TEMP); 479 480 mutex_enter(&conn->lock); 481 atomic_dec_uint(&conn->pducount); 482 TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain); 483 cv_broadcast(&conn->pdu_cv); 484 mutex_exit(&conn->lock); 485 } 486 487 /* 488 * create_pdus 489 * "Create" the pool of PDUs. This doesn't actually create the PDUs 490 * (they are allocated with the connection structure), but it links them 491 * into the free-list. 492 * 493 * Parameter: The connection owning the PDUs. 494 */ 495 496 void 497 create_pdus(connection_t *conn) 498 { 499 int i; 500 pdu_t *pdu; 501 502 /* Note: PDUs are initialized to 0 with connection structure */ 503 504 for (i = 0, pdu = conn->pdu; i < PDUS_PER_CONNECTION; i++, pdu++) { 505 TAILQ_INSERT_HEAD(&conn->pdu_pool, pdu, chain); 506 } 507 } 508 509 510 /***************************************************************************** 511 * Serial Number management functions 512 *****************************************************************************/ 513 514 /* 515 * init_sernum: 516 * Initialize serial number buffer variables. 517 * 518 * Parameter: 519 * buff The serial number buffer. 520 */ 521 522 void 523 init_sernum(sernum_buffer_t *buff) 524 { 525 526 buff->bottom = 0; 527 buff->top = 0; 528 buff->next_sn = 0; 529 buff->ExpSN = 0; 530 } 531 532 533 /* 534 * add_sernum: 535 * Add a received serial number to the buffer. 536 * If the serial number is smaller than the expected one, it is ignored. 537 * If it is larger, all missing serial numbers are added as well. 538 * 539 * Parameter: 540 * buff The serial number buffer. 541 * num The received serial number 542 * 543 * Returns: 544 * 0 if the received block is a duplicate 545 * 1 if the number is the expected one 546 * >1 if the numer is > the expected value, in this case the 547 * return value is the number of unacknowledged blocks 548 * <0 if the buffer is full (i.e. an excessive number of blocks 549 * is unacknowledged) 550 */ 551 552 int 553 add_sernum(sernum_buffer_t *buff, uint32_t num) 554 { 555 int i, t, b; 556 uint32_t n; 557 int32_t diff; 558 559 /* 560 * next_sn is the next expected SN, so normally diff should be 1. 561 */ 562 n = buff->next_sn; 563 diff = (num - n) + 1; 564 565 if (diff <= 0) { 566 return 0; /* ignore if SN is smaller than expected (dup or retransmit) */ 567 } 568 569 buff->next_sn = num + 1; 570 t = buff->top; 571 b = buff->bottom; 572 573 for (i = 0; i < diff; i++) { 574 buff->sernum[t] = n++; 575 buff->ack[t] = false; 576 t = (t + 1) % SERNUM_BUFFER_LENGTH; 577 if (t == b) { 578 DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff)); 579 return -1; 580 } 581 } 582 583 buff->top = t; 584 DEB(11, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n", 585 b, buff->sernum[b], buff->top, num, diff)); 586 587 return diff; 588 } 589 590 591 /* 592 * ack_sernum: 593 * Mark a received serial number as acknowledged. This does not necessarily 594 * change the associated ExpSN if there are lower serial numbers in the 595 * buffer. 596 * 597 * Parameter: 598 * buff The serial number buffer. 599 * num The serial number to acknowledge. 600 * 601 * Returns: The value of ExpSN. 602 */ 603 604 uint32_t 605 ack_sernum(sernum_buffer_t *buff, uint32_t num) 606 { 607 int b = buff->bottom; 608 int t = buff->top; 609 610 /* shortcut for most likely case */ 611 if (t == (b + 1) && num == buff->sernum[b]) { 612 /* buffer is now empty, reset top */ 613 buff->top = b; 614 } else if (b != t) { 615 for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 616 if (!sn_a_lt_b(buff->sernum[b], num)) 617 break; 618 } 619 if (num == buff->sernum[b]) { 620 if (b == buff->bottom) 621 buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH; 622 else 623 buff->ack[b] = true; 624 } 625 626 for (b = buff->bottom, num = buff->sernum[b] - 1; 627 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 628 num = buff->sernum[b]; 629 } 630 } 631 632 if (!sn_a_lt_b(num, buff->ExpSN)) 633 buff->ExpSN = num + 1; 634 635 DEB(11, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n", 636 buff->bottom, buff->top, num, buff->ExpSN)); 637 638 return buff->ExpSN; 639 } 640 641 /* 642 * next_sernum: 643 * Return the current command serial number of the session 644 * and optionally increment it for the next query 645 */ 646 uint32_t 647 get_sernum(session_t *sess, pdu_t *pdu) 648 { 649 uint32_t sn; 650 651 KASSERT(mutex_owned(&sess->lock)); 652 653 sn = sess->CmdSN; 654 if ((pdu->pdu.Opcode & OP_IMMEDIATE) == 0) 655 atomic_inc_32(&sess->CmdSN); 656 return sn; 657 } 658 659 /* 660 * sernum_in_window: 661 * Check wether serial number is in send window 662 * 663 */ 664 int 665 sernum_in_window(session_t *sess) 666 { 667 668 KASSERT(mutex_owned(&sess->lock)); 669 return sn_a_le_b(sess->CmdSN, sess->MaxCmdSN); 670 } 671 672 /* 673 * window_size: 674 * Compute send window size 675 */ 676 int 677 window_size(session_t *sess, int limit) 678 { 679 uint32_t win; 680 681 KASSERT(mutex_owned(&sess->lock)); 682 683 win = 0; 684 if (sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) 685 win = sess->MaxCmdSN - sess->CmdSN + 1; 686 if (win > INT_MAX || win > limit) 687 win = limit; 688 689 return win; 690 } 691