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