iscsi_send.c revision 1.1 1 1.1 agc /* $NetBSD: iscsi_send.c,v 1.1 2011/10/23 21:15:02 agc Exp $ */
2 1.1 agc
3 1.1 agc /*-
4 1.1 agc * Copyright (c) 2004,2005,2006,2011 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/file.h>
34 1.1 agc #include <sys/filedesc.h>
35 1.1 agc #include <sys/socket.h>
36 1.1 agc #include <sys/socketvar.h>
37 1.1 agc
38 1.1 agc /*#define LUN_1 1 */
39 1.1 agc
40 1.1 agc /*****************************************************************************/
41 1.1 agc
42 1.1 agc /*
43 1.1 agc * my_soo_write:
44 1.1 agc * Replacement for soo_write with flag handling.
45 1.1 agc *
46 1.1 agc * Parameter:
47 1.1 agc * conn The connection
48 1.1 agc * u The uio descriptor
49 1.1 agc *
50 1.1 agc * Returns: 0 on success, else EIO.
51 1.1 agc */
52 1.1 agc
53 1.1 agc STATIC int
54 1.1 agc my_soo_write(connection_t *conn, struct uio *u)
55 1.1 agc {
56 1.1 agc struct socket *so = (struct socket *) conn->sock->f_data;
57 1.1 agc size_t resid = u->uio_resid;
58 1.1 agc int ret;
59 1.1 agc
60 1.1 agc assert(resid != 0);
61 1.1 agc
62 1.1 agc #if (__NetBSD_Version__ >= 300000000)
63 1.1 agc ret = sosend(so, NULL, u, NULL, NULL, 0, conn->threadobj);
64 1.1 agc #else
65 1.1 agc ret = sosend(so, NULL, u, NULL, NULL, 0);
66 1.1 agc #endif
67 1.1 agc
68 1.1 agc DEB(99, ("soo_write done: len = %zu\n", u->uio_resid));
69 1.1 agc
70 1.1 agc if (ret != 0 || u->uio_resid) {
71 1.1 agc DEBC(conn, 0, ("Write failed sock %p (ret: %d, req: %zu, resid: %zu)\n",
72 1.1 agc conn->sock, ret, resid, u->uio_resid));
73 1.1 agc handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, NO_LOGOUT);
74 1.1 agc return EIO;
75 1.1 agc }
76 1.1 agc return 0;
77 1.1 agc }
78 1.1 agc
79 1.1 agc /*****************************************************************************/
80 1.1 agc
81 1.1 agc /*
82 1.1 agc * assign_connection:
83 1.1 agc * This function returns the connection to use for the next transaction.
84 1.1 agc *
85 1.1 agc * Parameter: The session
86 1.1 agc *
87 1.1 agc * Returns: The connection
88 1.1 agc */
89 1.1 agc
90 1.1 agc connection_t *
91 1.1 agc assign_connection(session_t *session, bool waitok)
92 1.1 agc {
93 1.1 agc connection_t *conn, *next;
94 1.1 agc
95 1.1 agc do {
96 1.1 agc if ((conn = session->mru_connection) == NULL) {
97 1.1 agc return NULL;
98 1.1 agc }
99 1.1 agc next = conn;
100 1.1 agc do {
101 1.1 agc next = TAILQ_NEXT(next, connections);
102 1.1 agc if (next == NULL) {
103 1.1 agc next = TAILQ_FIRST(&session->conn_list);
104 1.1 agc }
105 1.1 agc } while (next != NULL && next != conn &&
106 1.1 agc next->state != ST_FULL_FEATURE);
107 1.1 agc
108 1.1 agc if (next->state != ST_FULL_FEATURE) {
109 1.1 agc if (waitok) {
110 1.1 agc tsleep(session, PRIBIO, "iscsi_assign_connection", 0);
111 1.1 agc next = TAILQ_FIRST(&session->conn_list);
112 1.1 agc } else {
113 1.1 agc return NULL;
114 1.1 agc }
115 1.1 agc } else {
116 1.1 agc session->mru_connection = next;
117 1.1 agc }
118 1.1 agc } while (next != NULL && next->state != ST_FULL_FEATURE);
119 1.1 agc
120 1.1 agc return next;
121 1.1 agc }
122 1.1 agc
123 1.1 agc
124 1.1 agc /*
125 1.1 agc * reassign_tasks:
126 1.1 agc * Reassign pending commands to one of the still existing connections
127 1.1 agc * of a session.
128 1.1 agc *
129 1.1 agc * Parameter:
130 1.1 agc * oldconn The terminating connection
131 1.1 agc */
132 1.1 agc
133 1.1 agc STATIC void
134 1.1 agc reassign_tasks(connection_t *oldconn)
135 1.1 agc {
136 1.1 agc session_t *sess = oldconn->session;
137 1.1 agc connection_t *conn;
138 1.1 agc ccb_t *ccb;
139 1.1 agc pdu_t *pdu = NULL;
140 1.1 agc pdu_t *opdu;
141 1.1 agc int no_tm = 1;
142 1.1 agc int rc = 1;
143 1.1 agc
144 1.1 agc if ((conn = assign_connection(sess, FALSE)) == NULL) {
145 1.1 agc DEB(1, ("Reassign_tasks of Session %d, connection %d failed, "
146 1.1 agc "no active connection\n",
147 1.1 agc sess->id, oldconn->id));
148 1.1 agc return;
149 1.1 agc }
150 1.1 agc
151 1.1 agc if (sess->ErrorRecoveryLevel >= 2) {
152 1.1 agc if (oldconn->loggedout == NOT_LOGGED_OUT) {
153 1.1 agc oldconn->loggedout = LOGOUT_SENT;
154 1.1 agc no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE);
155 1.1 agc oldconn->loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS;
156 1.1 agc if (!oldconn->Time2Retain) {
157 1.1 agc DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n"));
158 1.1 agc no_tm = 1;
159 1.1 agc }
160 1.1 agc } else if (oldconn->loggedout == LOGOUT_SUCCESS) {
161 1.1 agc no_tm = 0;
162 1.1 agc }
163 1.1 agc if (!no_tm && oldconn->Time2Wait) {
164 1.1 agc DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n",
165 1.1 agc oldconn->Time2Wait, hz));
166 1.1 agc tsleep(&no_tm, PRIBIO, "Time2Wait", oldconn->Time2Wait * hz);
167 1.1 agc }
168 1.1 agc }
169 1.1 agc
170 1.1 agc DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n",
171 1.1 agc sess->id, oldconn->id, conn->id, no_tm));
172 1.1 agc
173 1.1 agc TAILQ_FOREACH(ccb, &oldconn->ccbs_waiting, chain) {
174 1.1 agc /* Copy PDU contents (PDUs are bound to connection) */
175 1.1 agc if ((pdu = get_pdu(conn)) == NULL) {
176 1.1 agc break;
177 1.1 agc }
178 1.1 agc opdu = ccb->pdu_waiting;
179 1.1 agc *pdu = *opdu;
180 1.1 agc /* restore overwritten back ptr */
181 1.1 agc pdu->connection = conn;
182 1.1 agc
183 1.1 agc /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */
184 1.1 agc pdu->save_uio.uio_iov = pdu->io_vec;
185 1.1 agc pdu->save_iovec [0].iov_base = &pdu->pdu;
186 1.1 agc
187 1.1 agc if (conn->DataDigest && pdu->save_uio.uio_iovcnt > 1) {
188 1.1 agc if (pdu->save_iovec [2].iov_base == NULL) {
189 1.1 agc pdu->save_iovec [2].iov_base = &pdu->data_digest;
190 1.1 agc pdu->save_uio.uio_iovcnt = 3;
191 1.1 agc } else {
192 1.1 agc pdu->save_iovec [3].iov_base = &pdu->data_digest;
193 1.1 agc pdu->save_uio.uio_iovcnt = 4;
194 1.1 agc }
195 1.1 agc }
196 1.1 agc pdu->save_iovec [0].iov_len =
197 1.1 agc (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
198 1.1 agc
199 1.1 agc ccb->pdu_waiting = pdu;
200 1.1 agc ccb->connection = conn;
201 1.1 agc ccb->num_timeouts = 0;
202 1.1 agc
203 1.1 agc DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
204 1.1 agc ccb, opdu, pdu));
205 1.1 agc
206 1.1 agc /* free the old PDU */
207 1.1 agc opdu->temp_data = NULL;
208 1.1 agc free_pdu(opdu);
209 1.1 agc }
210 1.1 agc
211 1.1 agc if (pdu == NULL) {
212 1.1 agc DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n"));
213 1.1 agc /* give up recovering, the other connection is screwed up as well... */
214 1.1 agc while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
215 1.1 agc ccb->status = oldconn->terminating;
216 1.1 agc wake_ccb(ccb);
217 1.1 agc }
218 1.1 agc return;
219 1.1 agc }
220 1.1 agc
221 1.1 agc while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) {
222 1.1 agc TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain);
223 1.1 agc TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
224 1.1 agc
225 1.1 agc if (!no_tm) {
226 1.1 agc rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN);
227 1.1 agc }
228 1.1 agc /* if we get an error on reassign, restart the original request */
229 1.1 agc if (no_tm || rc) {
230 1.1 agc if (ccb->CmdSN < sess->ExpCmdSN) {
231 1.1 agc pdu = ccb->pdu_waiting;
232 1.1 agc
233 1.1 agc /* update CmdSN */
234 1.1 agc DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n",
235 1.1 agc ccb->CmdSN, sess->CmdSN));
236 1.1 agc ccb->CmdSN = sess->CmdSN;
237 1.1 agc if (!(pdu->pdu.Opcode & OP_IMMEDIATE)) {
238 1.1 agc sess->CmdSN++;
239 1.1 agc }
240 1.1 agc pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
241 1.1 agc }
242 1.1 agc resend_pdu(ccb);
243 1.1 agc } else {
244 1.1 agc SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
245 1.1 agc }
246 1.1 agc DEBC(conn, 1, ("Reassign ccb %p, no_tm=%d, rc=%d\n",
247 1.1 agc ccb, no_tm, rc));
248 1.1 agc }
249 1.1 agc }
250 1.1 agc
251 1.1 agc
252 1.1 agc /*
253 1.1 agc * iscsi_send_thread:
254 1.1 agc * This thread services the send queue, writing the PDUs to the socket.
255 1.1 agc * It also handles the cleanup when the connection is terminated.
256 1.1 agc *
257 1.1 agc * Parameter:
258 1.1 agc * par The connection this thread services
259 1.1 agc */
260 1.1 agc
261 1.1 agc void
262 1.1 agc iscsi_send_thread(void *par)
263 1.1 agc {
264 1.1 agc connection_t *conn = (connection_t *) par;
265 1.1 agc session_t *sess;
266 1.1 agc ccb_t *ccb, *nccb;
267 1.1 agc pdu_t *pdu;
268 1.1 agc struct file *fp;
269 1.1 agc int s;
270 1.1 agc
271 1.1 agc sess = conn->session;
272 1.1 agc /* so cleanup thread knows there's someone left */
273 1.1 agc num_send_threads++;
274 1.1 agc
275 1.1 agc do {
276 1.1 agc while (!conn->terminating) {
277 1.1 agc s = splbio();
278 1.1 agc while (!conn->terminating &&
279 1.1 agc (pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
280 1.1 agc TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
281 1.1 agc pdu->flags &= ~PDUF_INQUEUE;
282 1.1 agc splx(s);
283 1.1 agc
284 1.1 agc PERF_PDUSNAPB(pdu);
285 1.1 agc
286 1.1 agc #ifdef ISCSI_DEBUG
287 1.1 agc if (!pdu->uio.uio_resid) {
288 1.1 agc DEBOUT(("uio.resid = 0 in iscsi_send_thread! pdu=%p\n",
289 1.1 agc pdu));
290 1.1 agc assert(pdu->uio.uio_resid != 0);
291 1.1 agc }
292 1.1 agc #endif
293 1.1 agc /*DEB (99,("Send thread woke up, pdu = %x)\n", (int)pdu)); */
294 1.1 agc
295 1.1 agc #ifdef ISCSI_TEST_MODE
296 1.1 agc if (!test_mode_tx(conn, pdu)) {
297 1.1 agc if (!(pdu->flags & PDUF_NOUPDATE)) {
298 1.1 agc #endif
299 1.1 agc /* update ExpStatSN here to avoid discontinuities */
300 1.1 agc /* and delays in updating target */
301 1.1 agc pdu->pdu.p.command.ExpStatSN =
302 1.1 agc htonl(conn->StatSN_buf.ExpSN);
303 1.1 agc
304 1.1 agc if (conn->HeaderDigest)
305 1.1 agc pdu->pdu.HeaderDigest =
306 1.1 agc gen_digest(&pdu->pdu, BHS_SIZE);
307 1.1 agc #ifdef ISCSI_TEST_MODE
308 1.1 agc }
309 1.1 agc #endif
310 1.1 agc my_soo_write(conn, &pdu->uio);
311 1.1 agc #ifdef ISCSI_TEST_MODE
312 1.1 agc }
313 1.1 agc #endif
314 1.1 agc PERF_PDUSNAPE(pdu);
315 1.1 agc
316 1.1 agc if (pdu->disp <= PDUDISP_FREE) {
317 1.1 agc free_pdu(pdu);
318 1.1 agc } else {
319 1.1 agc pdu->flags &= ~PDUF_BUSY;
320 1.1 agc }
321 1.1 agc s = splbio();
322 1.1 agc }
323 1.1 agc
324 1.1 agc /*DEB (99,("Send thread done, waiting (conn->terminating = %d)\n", */
325 1.1 agc /* conn->terminating)); */
326 1.1 agc
327 1.1 agc if (!conn->terminating) {
328 1.1 agc tsleep(&conn->pdus_to_send, PRIBIO,
329 1.1 agc "iscsisend", 0);
330 1.1 agc }
331 1.1 agc
332 1.1 agc splx(s);
333 1.1 agc }
334 1.1 agc
335 1.1 agc /* ------------------------------------------------------------------------
336 1.1 agc * Here this thread takes over cleanup of the terminating connection.
337 1.1 agc * ------------------------------------------------------------------------
338 1.1 agc */
339 1.1 agc callout_stop(&conn->timeout);
340 1.1 agc conn->idle_timeout_val = CONNECTION_IDLE_TIMEOUT;
341 1.1 agc
342 1.1 agc fp = conn->sock;
343 1.1 agc
344 1.1 agc DEBC(conn, 9, ("Closing Socket %p\n", conn->sock));
345 1.1 agc /*
346 1.1 agc * We must close the socket here to force the receive
347 1.1 agc * thread to wake up
348 1.1 agc */
349 1.1 agc solock((struct socket *) fp->f_data);
350 1.1 agc soshutdown((struct socket *) fp->f_data, SHUT_RDWR);
351 1.1 agc sounlock((struct socket *) fp->f_data);
352 1.1 agc
353 1.1 agc #if __NetBSD_Version__ > 500000000
354 1.1 agc mutex_enter(&fp->f_lock);
355 1.1 agc fp->f_count += 1;
356 1.1 agc mutex_exit(&fp->f_lock);
357 1.1 agc closef(fp);
358 1.1 agc #else
359 1.1 agc simple_lock(&fp->f_slock);
360 1.1 agc FILE_USE(fp);
361 1.1 agc closef(fp, NULL);
362 1.1 agc #endif
363 1.1 agc
364 1.1 agc /* wake up any non-reassignable waiting CCBs */
365 1.1 agc for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) {
366 1.1 agc nccb = TAILQ_NEXT(ccb, chain);
367 1.1 agc if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) {
368 1.1 agc ccb->status = conn->terminating;
369 1.1 agc wake_ccb(ccb);
370 1.1 agc } else {
371 1.1 agc callout_stop(&ccb->timeout);
372 1.1 agc ccb->num_timeouts = 0;
373 1.1 agc }
374 1.1 agc }
375 1.1 agc
376 1.1 agc /* clean out anything left in send queue */
377 1.1 agc while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) {
378 1.1 agc TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
379 1.1 agc pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY);
380 1.1 agc /* if it's not attached to a waiting CCB, free it */
381 1.1 agc if (pdu->owner == NULL ||
382 1.1 agc pdu->owner->pdu_waiting != pdu) {
383 1.1 agc free_pdu(pdu);
384 1.1 agc }
385 1.1 agc }
386 1.1 agc
387 1.1 agc /* If there's another connection available, transfer pending tasks */
388 1.1 agc if (sess->active_connections &&
389 1.1 agc TAILQ_FIRST(&conn->ccbs_waiting) != NULL) {
390 1.1 agc reassign_tasks (conn);
391 1.1 agc } else if (!conn->destroy && conn->Time2Wait) {
392 1.1 agc tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz);
393 1.1 agc }
394 1.1 agc /* notify event handlers of connection shutdown */
395 1.1 agc add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED
396 1.1 agc : ISCSI_RECOVER_CONNECTION,
397 1.1 agc sess->id, conn->id, conn->terminating);
398 1.1 agc
399 1.1 agc if (!conn->destroy)
400 1.1 agc tsleep(conn, PRIBIO, "conn_idle", 0);
401 1.1 agc
402 1.1 agc } while (!conn->destroy);
403 1.1 agc
404 1.1 agc /* wake up anyone waiting for a PDU */
405 1.1 agc wakeup(&conn->pdu_pool);
406 1.1 agc
407 1.1 agc /* wake up any waiting CCBs */
408 1.1 agc while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) {
409 1.1 agc ccb->status = conn->terminating;
410 1.1 agc wake_ccb(ccb);
411 1.1 agc /* NOTE: wake_ccb will remove the CCB from the queue */
412 1.1 agc }
413 1.1 agc
414 1.1 agc s = splbio();
415 1.1 agc if (conn->in_session) {
416 1.1 agc conn->in_session = FALSE;
417 1.1 agc TAILQ_REMOVE(&sess->conn_list, conn, connections);
418 1.1 agc sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
419 1.1 agc }
420 1.1 agc
421 1.1 agc TAILQ_INSERT_TAIL(&cleanup_list, conn, connections);
422 1.1 agc splx(s);
423 1.1 agc
424 1.1 agc wakeup(&cleanup_list);
425 1.1 agc
426 1.1 agc conn->sendproc = NULL;
427 1.1 agc DEBC(conn, 5, ("Send thread exits\n"));
428 1.1 agc num_send_threads--;
429 1.1 agc kthread_exit(0);
430 1.1 agc }
431 1.1 agc
432 1.1 agc
433 1.1 agc /*
434 1.1 agc * send_pdu:
435 1.1 agc * Enqueue a PDU to be sent, and handle its disposition as well as
436 1.1 agc * the disposition of its associated CCB.
437 1.1 agc *
438 1.1 agc * Parameter:
439 1.1 agc * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT
440 1.1 agc * and pdisp is not PDUDISP_WAIT
441 1.1 agc * cdisp The CCB's disposition
442 1.1 agc * pdu The PDU
443 1.1 agc * pdisp The PDU's disposition
444 1.1 agc */
445 1.1 agc
446 1.1 agc STATIC void
447 1.1 agc send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp)
448 1.1 agc {
449 1.1 agc connection_t *conn = pdu->connection;
450 1.1 agc ccb_disp_t prev_cdisp = 0;
451 1.1 agc
452 1.1 agc if (ccb != NULL) {
453 1.1 agc prev_cdisp = ccb->disp;
454 1.1 agc pdu->pdu.InitiatorTaskTag = ccb->ITT;
455 1.1 agc pdu->owner = ccb;
456 1.1 agc if (cdisp != CCBDISP_NOWAIT)
457 1.1 agc ccb->disp = cdisp;
458 1.1 agc }
459 1.1 agc
460 1.1 agc pdu->disp = pdisp;
461 1.1 agc
462 1.1 agc DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n",
463 1.1 agc ccb, prev_cdisp, cdisp, pdu, pdisp));
464 1.1 agc
465 1.1 agc CS_BEGIN;
466 1.1 agc if (pdisp == PDUDISP_WAIT) {
467 1.1 agc ccb->pdu_waiting = pdu;
468 1.1 agc
469 1.1 agc /* save UIO and IOVEC for retransmit */
470 1.1 agc pdu->save_uio = pdu->uio;
471 1.1 agc memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec));
472 1.1 agc
473 1.1 agc pdu->flags |= PDUF_BUSY;
474 1.1 agc }
475 1.1 agc /* Enqueue for sending */
476 1.1 agc pdu->flags |= PDUF_INQUEUE;
477 1.1 agc
478 1.1 agc if (pdu->flags & PDUF_PRIORITY)
479 1.1 agc TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
480 1.1 agc else
481 1.1 agc TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
482 1.1 agc
483 1.1 agc wakeup(&conn->pdus_to_send);
484 1.1 agc
485 1.1 agc if (cdisp != CCBDISP_NOWAIT) {
486 1.1 agc SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
487 1.1 agc
488 1.1 agc if (prev_cdisp <= CCBDISP_NOWAIT)
489 1.1 agc TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
490 1.1 agc
491 1.1 agc if (cdisp == CCBDISP_WAIT)
492 1.1 agc tsleep(ccb, PWAIT, "sendpdu", 0);
493 1.1 agc }
494 1.1 agc CS_END;
495 1.1 agc }
496 1.1 agc
497 1.1 agc
498 1.1 agc /*
499 1.1 agc * resend_pdu:
500 1.1 agc * Re-Enqueue a PDU that has apparently gotten lost.
501 1.1 agc *
502 1.1 agc * Parameter:
503 1.1 agc * ccb The associated CCB.
504 1.1 agc */
505 1.1 agc
506 1.1 agc void
507 1.1 agc resend_pdu(ccb_t *ccb)
508 1.1 agc {
509 1.1 agc connection_t *conn = ccb->connection;
510 1.1 agc pdu_t *pdu = ccb->pdu_waiting;
511 1.1 agc int s;
512 1.1 agc
513 1.1 agc s = splbio ();
514 1.1 agc if (pdu == NULL || (pdu->flags & PDUF_BUSY)) {
515 1.1 agc splx (s);
516 1.1 agc return;
517 1.1 agc }
518 1.1 agc pdu->flags |= PDUF_BUSY;
519 1.1 agc splx (s);
520 1.1 agc
521 1.1 agc /* restore UIO and IOVEC */
522 1.1 agc pdu->uio = pdu->save_uio;
523 1.1 agc memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec));
524 1.1 agc
525 1.1 agc DEBC(conn, 8, ("ReSend_pdu ccb=%p, pdu=%p\n", ccb, pdu));
526 1.1 agc
527 1.1 agc s = splbio ();
528 1.1 agc
529 1.1 agc /* Enqueue for sending */
530 1.1 agc pdu->flags |= PDUF_INQUEUE;
531 1.1 agc
532 1.1 agc if (pdu->flags & PDUF_PRIORITY) {
533 1.1 agc TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain);
534 1.1 agc } else {
535 1.1 agc TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain);
536 1.1 agc }
537 1.1 agc SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
538 1.1 agc splx (s);
539 1.1 agc
540 1.1 agc wakeup(&conn->pdus_to_send);
541 1.1 agc }
542 1.1 agc
543 1.1 agc
544 1.1 agc /*
545 1.1 agc * setup_tx_uio:
546 1.1 agc * Initialize the uio structure for sending, including header,
547 1.1 agc * data (if present), padding, and Data Digest.
548 1.1 agc * Header Digest is generated in send thread.
549 1.1 agc *
550 1.1 agc * Parameter:
551 1.1 agc * pdu The PDU
552 1.1 agc * dsl The Data Segment Length
553 1.1 agc * data The data pointer
554 1.1 agc * read TRUE if this is a read operation
555 1.1 agc */
556 1.1 agc
557 1.1 agc STATIC void
558 1.1 agc setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read)
559 1.1 agc {
560 1.1 agc static uint8_t pad_bytes[4] = { 0 };
561 1.1 agc struct uio *uio;
562 1.1 agc int i, pad, hlen;
563 1.1 agc connection_t *conn = pdu->connection;
564 1.1 agc
565 1.1 agc DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n",
566 1.1 agc dsl, data, read));
567 1.1 agc
568 1.1 agc if (!read && dsl) {
569 1.1 agc hton3(dsl, pdu->pdu.DataSegmentLength);
570 1.1 agc }
571 1.1 agc hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE;
572 1.1 agc
573 1.1 agc pdu->io_vec[0].iov_base = &pdu->pdu;
574 1.1 agc pdu->io_vec[0].iov_len = hlen;
575 1.1 agc
576 1.1 agc uio = &pdu->uio;
577 1.1 agc
578 1.1 agc uio->uio_iov = pdu->io_vec;
579 1.1 agc uio->uio_iovcnt = 1;
580 1.1 agc uio->uio_rw = UIO_WRITE;
581 1.1 agc uio->uio_resid = hlen;
582 1.1 agc UIO_SETUP_SYSSPACE(uio);
583 1.1 agc
584 1.1 agc if (!read && dsl) {
585 1.1 agc uio->uio_iovcnt++;
586 1.1 agc pdu->io_vec[1].iov_base = data;
587 1.1 agc pdu->io_vec[1].iov_len = dsl;
588 1.1 agc uio->uio_resid += dsl;
589 1.1 agc
590 1.1 agc /* Pad to next multiple of 4 */
591 1.1 agc pad = uio->uio_resid & 0x03;
592 1.1 agc if (pad) {
593 1.1 agc i = uio->uio_iovcnt++;
594 1.1 agc pad = 4 - pad;
595 1.1 agc pdu->io_vec[i].iov_base = pad_bytes;
596 1.1 agc pdu->io_vec[i].iov_len = pad;
597 1.1 agc uio->uio_resid += pad;
598 1.1 agc }
599 1.1 agc
600 1.1 agc if (conn->DataDigest) {
601 1.1 agc pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad);
602 1.1 agc i = uio->uio_iovcnt++;
603 1.1 agc pdu->io_vec[i].iov_base = &pdu->data_digest;
604 1.1 agc pdu->io_vec[i].iov_len = 4;
605 1.1 agc uio->uio_resid += 4;
606 1.1 agc }
607 1.1 agc }
608 1.1 agc }
609 1.1 agc
610 1.1 agc /*
611 1.1 agc * init_login_pdu:
612 1.1 agc * Initialize the login PDU.
613 1.1 agc *
614 1.1 agc * Parameter:
615 1.1 agc * conn The connection
616 1.1 agc * pdu The PDU
617 1.1 agc */
618 1.1 agc
619 1.1 agc STATIC void
620 1.1 agc init_login_pdu(connection_t *conn, pdu_t *ppdu, bool next)
621 1.1 agc {
622 1.1 agc pdu_header_t *pdu = &ppdu->pdu;
623 1.1 agc login_isid_t *isid = (login_isid_t *) & pdu->LUN;
624 1.1 agc uint8_t c_phase;
625 1.1 agc
626 1.1 agc pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE;
627 1.1 agc
628 1.1 agc if (next) {
629 1.1 agc c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK;
630 1.1 agc pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) |
631 1.1 agc NEXT_PHASE(c_phase);
632 1.1 agc }
633 1.1 agc
634 1.1 agc memcpy(isid, &InitiatorISID, 6);
635 1.1 agc isid->TSIH = conn->session->TSIH;
636 1.1 agc
637 1.1 agc pdu->p.login_req.CID = htons(conn->id);
638 1.1 agc pdu->p.login_req.CmdSN = htonl(conn->session->CmdSN);
639 1.1 agc }
640 1.1 agc
641 1.1 agc
642 1.1 agc /*
643 1.1 agc * negotiate_login:
644 1.1 agc * Control login negotiation.
645 1.1 agc *
646 1.1 agc * Parameter:
647 1.1 agc * conn The connection
648 1.1 agc * rx_pdu The received login response PDU
649 1.1 agc * tx_ccb The originally sent login CCB
650 1.1 agc */
651 1.1 agc
652 1.1 agc void
653 1.1 agc negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
654 1.1 agc {
655 1.1 agc int rc;
656 1.1 agc bool next = TRUE;
657 1.1 agc pdu_t *tx_pdu;
658 1.1 agc uint8_t c_phase;
659 1.1 agc
660 1.1 agc if (rx_pdu->pdu.Flags & FLAG_TRANSIT)
661 1.1 agc c_phase = rx_pdu->pdu.Flags & SG_MASK;
662 1.1 agc else
663 1.1 agc c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK;
664 1.1 agc
665 1.1 agc DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n",
666 1.1 agc rx_pdu->pdu.Flags, c_phase));
667 1.1 agc
668 1.1 agc if (c_phase == SG_FULL_FEATURE_PHASE) {
669 1.1 agc session_t *sess = conn->session;
670 1.1 agc
671 1.1 agc if (!sess->TSIH)
672 1.1 agc sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH;
673 1.1 agc
674 1.1 agc if (rx_pdu->temp_data != NULL)
675 1.1 agc assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL);
676 1.1 agc
677 1.1 agc /* negotiated values are now valid */
678 1.1 agc set_negotiated_parameters(tx_ccb);
679 1.1 agc
680 1.1 agc DEBC(conn, 5, ("Login Successful!\n"));
681 1.1 agc wake_ccb(tx_ccb);
682 1.1 agc return;
683 1.1 agc }
684 1.1 agc
685 1.1 agc tx_pdu = get_pdu(conn);
686 1.1 agc if (tx_pdu == NULL)
687 1.1 agc return;
688 1.1 agc
689 1.1 agc tx_pdu->pdu.Flags = c_phase << CSG_SHIFT;
690 1.1 agc
691 1.1 agc switch (c_phase) {
692 1.1 agc case SG_SECURITY_NEGOTIATION:
693 1.1 agc rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
694 1.1 agc if (rc < 0)
695 1.1 agc next = FALSE;
696 1.1 agc break;
697 1.1 agc
698 1.1 agc case SG_LOGIN_OPERATIONAL_NEGOTIATION:
699 1.1 agc rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
700 1.1 agc break;
701 1.1 agc
702 1.1 agc default:
703 1.1 agc DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase));
704 1.1 agc rc = ISCSI_STATUS_TARGET_ERROR;
705 1.1 agc break;
706 1.1 agc }
707 1.1 agc
708 1.1 agc if (rc > 0) {
709 1.1 agc tx_ccb->status = rc;
710 1.1 agc wake_ccb(tx_ccb);
711 1.1 agc free_pdu(tx_pdu);
712 1.1 agc } else {
713 1.1 agc init_login_pdu(conn, tx_pdu, next);
714 1.1 agc setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE);
715 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
716 1.1 agc }
717 1.1 agc }
718 1.1 agc
719 1.1 agc
720 1.1 agc /*
721 1.1 agc * init_text_pdu:
722 1.1 agc * Initialize the text PDU.
723 1.1 agc *
724 1.1 agc * Parameter:
725 1.1 agc * conn The connection
726 1.1 agc * ppdu The transmit PDU
727 1.1 agc * rx_pdu The received PDU if this is an unsolicited negotiation
728 1.1 agc */
729 1.1 agc
730 1.1 agc STATIC void
731 1.1 agc init_text_pdu(connection_t *conn, pdu_t *ppdu, pdu_t *rx_pdu)
732 1.1 agc {
733 1.1 agc pdu_header_t *pdu = &ppdu->pdu;
734 1.1 agc
735 1.1 agc pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE;
736 1.1 agc pdu->Flags = FLAG_FINAL;
737 1.1 agc
738 1.1 agc if (rx_pdu != NULL) {
739 1.1 agc pdu->p.text_req.TargetTransferTag =
740 1.1 agc rx_pdu->pdu.p.text_rsp.TargetTransferTag;
741 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
742 1.1 agc } else
743 1.1 agc pdu->p.text_req.TargetTransferTag = 0xffffffff;
744 1.1 agc
745 1.1 agc pdu->p.text_req.CmdSN = htonl(conn->session->CmdSN);
746 1.1 agc }
747 1.1 agc
748 1.1 agc
749 1.1 agc /*
750 1.1 agc * acknowledge_text:
751 1.1 agc * Acknowledge a continued login or text response.
752 1.1 agc *
753 1.1 agc * Parameter:
754 1.1 agc * conn The connection
755 1.1 agc * rx_pdu The received login/text response PDU
756 1.1 agc * tx_ccb The originally sent login/text request CCB
757 1.1 agc */
758 1.1 agc
759 1.1 agc void
760 1.1 agc acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
761 1.1 agc {
762 1.1 agc pdu_t *tx_pdu;
763 1.1 agc
764 1.1 agc tx_pdu = get_pdu(conn);
765 1.1 agc if (tx_pdu == NULL)
766 1.1 agc return;
767 1.1 agc
768 1.1 agc if (rx_pdu != NULL &&
769 1.1 agc (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request)
770 1.1 agc init_login_pdu(conn, tx_pdu, FALSE);
771 1.1 agc else
772 1.1 agc init_text_pdu(conn, tx_pdu, rx_pdu);
773 1.1 agc
774 1.1 agc setup_tx_uio(tx_pdu, 0, NULL, FALSE);
775 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
776 1.1 agc }
777 1.1 agc
778 1.1 agc
779 1.1 agc /*
780 1.1 agc * start_text_negotiation:
781 1.1 agc * Handle target request to negotiate (via asynch event)
782 1.1 agc *
783 1.1 agc * Parameter:
784 1.1 agc * conn The connection
785 1.1 agc */
786 1.1 agc
787 1.1 agc void
788 1.1 agc start_text_negotiation(connection_t *conn)
789 1.1 agc {
790 1.1 agc pdu_t *pdu;
791 1.1 agc ccb_t *ccb;
792 1.1 agc
793 1.1 agc ccb = get_ccb(conn, TRUE);
794 1.1 agc pdu = get_pdu(conn);
795 1.1 agc if (ccb == NULL || pdu == NULL)
796 1.1 agc return;
797 1.1 agc
798 1.1 agc if (init_text_parameters(conn, ccb)) {
799 1.1 agc free_ccb(ccb);
800 1.1 agc free_pdu(pdu);
801 1.1 agc return;
802 1.1 agc }
803 1.1 agc
804 1.1 agc init_text_pdu(conn, pdu, NULL);
805 1.1 agc setup_tx_uio(pdu, 0, NULL, FALSE);
806 1.1 agc send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT);
807 1.1 agc }
808 1.1 agc
809 1.1 agc
810 1.1 agc /*
811 1.1 agc * negotiate_text:
812 1.1 agc * Handle received text negotiation.
813 1.1 agc *
814 1.1 agc * Parameter:
815 1.1 agc * conn The connection
816 1.1 agc * rx_pdu The received text response PDU
817 1.1 agc * tx_ccb The original CCB
818 1.1 agc */
819 1.1 agc
820 1.1 agc void
821 1.1 agc negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb)
822 1.1 agc {
823 1.1 agc int rc;
824 1.1 agc pdu_t *tx_pdu;
825 1.1 agc
826 1.1 agc if (tx_ccb->flags & CCBF_SENDTARGET) {
827 1.1 agc if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) {
828 1.1 agc handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR,
829 1.1 agc LOGOUT_CONNECTION);
830 1.1 agc return;
831 1.1 agc }
832 1.1 agc /* transfer ownership of text to CCB */
833 1.1 agc tx_ccb->text_data = rx_pdu->temp_data;
834 1.1 agc tx_ccb->text_len = rx_pdu->temp_data_len;
835 1.1 agc rx_pdu->temp_data = NULL;
836 1.1 agc wake_ccb(tx_ccb);
837 1.1 agc } else {
838 1.1 agc if (!(rx_pdu->pdu.Flags & FLAG_FINAL))
839 1.1 agc tx_pdu = get_pdu(conn);
840 1.1 agc else
841 1.1 agc tx_pdu = NULL;
842 1.1 agc
843 1.1 agc rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu);
844 1.1 agc if (rc) {
845 1.1 agc if (tx_pdu != NULL)
846 1.1 agc free_pdu(tx_pdu);
847 1.1 agc
848 1.1 agc handle_connection_error(conn, rc, LOGOUT_CONNECTION);
849 1.1 agc } else if (tx_pdu != NULL) {
850 1.1 agc init_text_pdu(conn, tx_pdu, rx_pdu);
851 1.1 agc setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data,
852 1.1 agc FALSE);
853 1.1 agc send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE);
854 1.1 agc } else {
855 1.1 agc set_negotiated_parameters(tx_ccb);
856 1.1 agc wake_ccb(tx_ccb);
857 1.1 agc }
858 1.1 agc }
859 1.1 agc }
860 1.1 agc
861 1.1 agc
862 1.1 agc /*
863 1.1 agc * send_send_targets:
864 1.1 agc * Send out a SendTargets text request.
865 1.1 agc * The result is stored in the fields in the session structure.
866 1.1 agc *
867 1.1 agc * Parameter:
868 1.1 agc * session The session
869 1.1 agc * key The text key to use
870 1.1 agc *
871 1.1 agc * Returns: 0 on success, else an error code.
872 1.1 agc */
873 1.1 agc
874 1.1 agc int
875 1.1 agc send_send_targets(session_t *session, uint8_t *key)
876 1.1 agc {
877 1.1 agc ccb_t *ccb;
878 1.1 agc pdu_t *pdu;
879 1.1 agc int rc = 0;
880 1.1 agc connection_t *conn;
881 1.1 agc
882 1.1 agc DEB(9, ("Send_send_targets\n"));
883 1.1 agc
884 1.1 agc conn = assign_connection(session, TRUE);
885 1.1 agc if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE)
886 1.1 agc return (conn != NULL && conn->terminating) ? conn->terminating
887 1.1 agc : ISCSI_STATUS_CONNECTION_FAILED;
888 1.1 agc
889 1.1 agc ccb = get_ccb(conn, TRUE);
890 1.1 agc pdu = get_pdu(conn);
891 1.1 agc /* can only happen if terminating... */
892 1.1 agc if (ccb == NULL || pdu == NULL)
893 1.1 agc return conn->terminating;
894 1.1 agc
895 1.1 agc ccb->flags |= CCBF_SENDTARGET;
896 1.1 agc
897 1.1 agc if ((rc = assemble_send_targets(pdu, key)) != 0) {
898 1.1 agc free_ccb(ccb);
899 1.1 agc free_pdu(pdu);
900 1.1 agc return rc;
901 1.1 agc }
902 1.1 agc
903 1.1 agc init_text_pdu(conn, pdu, NULL);
904 1.1 agc
905 1.1 agc setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
906 1.1 agc send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT);
907 1.1 agc
908 1.1 agc rc = ccb->status;
909 1.1 agc if (!rc) {
910 1.1 agc /* transfer ownership of data */
911 1.1 agc session->target_list = ccb->text_data;
912 1.1 agc session->target_list_len = ccb->text_len;
913 1.1 agc ccb->text_data = NULL;
914 1.1 agc }
915 1.1 agc free_ccb(ccb);
916 1.1 agc return rc;
917 1.1 agc }
918 1.1 agc
919 1.1 agc
920 1.1 agc /*
921 1.1 agc * send_nop_out:
922 1.1 agc * Send nop out request.
923 1.1 agc *
924 1.1 agc * Parameter:
925 1.1 agc * conn The connection
926 1.1 agc * rx_pdu The received Nop-In PDU
927 1.1 agc *
928 1.1 agc * Returns: 0 on success, else an error code.
929 1.1 agc */
930 1.1 agc
931 1.1 agc int
932 1.1 agc send_nop_out(connection_t *conn, pdu_t *rx_pdu)
933 1.1 agc {
934 1.1 agc ccb_t *ccb;
935 1.1 agc pdu_t *ppdu;
936 1.1 agc pdu_header_t *pdu;
937 1.1 agc
938 1.1 agc DEBC(conn, 10, ("Send NOP_Out rx_pdu=%p\n", rx_pdu));
939 1.1 agc
940 1.1 agc if (rx_pdu != NULL) {
941 1.1 agc ccb = NULL;
942 1.1 agc ppdu = get_pdu(conn);
943 1.1 agc if (ppdu == NULL)
944 1.1 agc return 1;
945 1.1 agc } else {
946 1.1 agc ccb = get_ccb(conn, FALSE);
947 1.1 agc if (ccb == NULL) {
948 1.1 agc DEBOUT(("Can't get CCB in send_nop_out\n"));
949 1.1 agc return 1;
950 1.1 agc }
951 1.1 agc ppdu = get_pdu_c(conn, FALSE);
952 1.1 agc if (ppdu == NULL) {
953 1.1 agc free_ccb(ccb);
954 1.1 agc DEBOUT(("Can't get PDU in send_nop_out\n"));
955 1.1 agc return 1;
956 1.1 agc }
957 1.1 agc }
958 1.1 agc
959 1.1 agc pdu = &ppdu->pdu;
960 1.1 agc pdu->Flags = FLAG_FINAL;
961 1.1 agc pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE;
962 1.1 agc
963 1.1 agc if (rx_pdu != NULL) {
964 1.1 agc pdu->p.nop_out.TargetTransferTag =
965 1.1 agc rx_pdu->pdu.p.nop_in.TargetTransferTag;
966 1.1 agc pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
967 1.1 agc pdu->p.nop_out.CmdSN = htonl(conn->session->CmdSN);
968 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
969 1.1 agc } else {
970 1.1 agc pdu->p.nop_out.TargetTransferTag = 0xffffffff;
971 1.1 agc ccb->CmdSN = ccb->session->CmdSN;
972 1.1 agc pdu->p.nop_out.CmdSN = htonl(ccb->CmdSN);
973 1.1 agc }
974 1.1 agc
975 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
976 1.1 agc send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE,
977 1.1 agc PDUDISP_FREE);
978 1.1 agc return 0;
979 1.1 agc }
980 1.1 agc
981 1.1 agc
982 1.1 agc /*
983 1.1 agc * snack_missing:
984 1.1 agc * Send SNACK request for missing data.
985 1.1 agc *
986 1.1 agc * Parameter:
987 1.1 agc * conn The connection
988 1.1 agc * ccb The task's CCB (for Data NAK only)
989 1.1 agc * type The SNACK type
990 1.1 agc * BegRun The BegRun field
991 1.1 agc * RunLength The RunLength field
992 1.1 agc */
993 1.1 agc
994 1.1 agc void
995 1.1 agc snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type,
996 1.1 agc uint32_t BegRun, uint32_t RunLength)
997 1.1 agc {
998 1.1 agc pdu_t *ppdu;
999 1.1 agc pdu_header_t *pdu;
1000 1.1 agc
1001 1.1 agc PDEBC(conn, 1, ("SNACK Missing type = %d, BegRun %d RunLength %d\n",
1002 1.1 agc type, BegRun, RunLength));
1003 1.1 agc
1004 1.1 agc ppdu = get_pdu(conn);
1005 1.1 agc if (ppdu == NULL)
1006 1.1 agc return;
1007 1.1 agc pdu = &ppdu->pdu;
1008 1.1 agc pdu->Opcode = IOP_SNACK_Request;
1009 1.1 agc pdu->Flags = FLAG_FINAL | type;
1010 1.1 agc
1011 1.1 agc pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff;
1012 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1013 1.1 agc pdu->p.snack.BegRun = htonl(BegRun);
1014 1.1 agc pdu->p.snack.RunLength = htonl(RunLength);
1015 1.1 agc
1016 1.1 agc ppdu->flags = PDUF_PRIORITY;
1017 1.1 agc
1018 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1019 1.1 agc send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1020 1.1 agc }
1021 1.1 agc
1022 1.1 agc
1023 1.1 agc /*
1024 1.1 agc * send_snack:
1025 1.1 agc * Send SNACK request.
1026 1.1 agc *
1027 1.1 agc * Parameter:
1028 1.1 agc * conn The connection
1029 1.1 agc * rx_pdu The received data in PDU
1030 1.1 agc * tx_ccb The original command CCB (required for Data ACK only)
1031 1.1 agc * type The SNACK type
1032 1.1 agc *
1033 1.1 agc * Returns: 0 on success, else an error code.
1034 1.1 agc */
1035 1.1 agc
1036 1.1 agc void
1037 1.1 agc send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type)
1038 1.1 agc {
1039 1.1 agc pdu_t *ppdu;
1040 1.1 agc pdu_header_t *pdu;
1041 1.1 agc
1042 1.1 agc PDEBC(conn, 1, ("Send SNACK type = %d\n", type));
1043 1.1 agc
1044 1.1 agc ppdu = get_pdu(conn);
1045 1.1 agc if (ppdu == NULL)
1046 1.1 agc return;
1047 1.1 agc pdu = &ppdu->pdu;
1048 1.1 agc pdu->Opcode = IOP_SNACK_Request;
1049 1.1 agc pdu->Flags = FLAG_FINAL | type;
1050 1.1 agc
1051 1.1 agc switch (type) {
1052 1.1 agc case SNACK_DATA_NAK:
1053 1.1 agc pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag;
1054 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1055 1.1 agc pdu->p.snack.BegRun = rx_pdu->pdu.p.data_in.DataSN;
1056 1.1 agc pdu->p.snack.RunLength = htonl(1);
1057 1.1 agc break;
1058 1.1 agc
1059 1.1 agc case SNACK_STATUS_NAK:
1060 1.1 agc pdu->InitiatorTaskTag = 0xffffffff;
1061 1.1 agc pdu->p.snack.TargetTransferTag = 0xffffffff;
1062 1.1 agc pdu->p.snack.BegRun = rx_pdu->pdu.p.response.StatSN;
1063 1.1 agc pdu->p.snack.RunLength = htonl(1);
1064 1.1 agc break;
1065 1.1 agc
1066 1.1 agc case SNACK_DATA_ACK:
1067 1.1 agc pdu->InitiatorTaskTag = 0xffffffff;
1068 1.1 agc pdu->p.snack.TargetTransferTag =
1069 1.1 agc rx_pdu->pdu.p.data_in.TargetTransferTag;
1070 1.1 agc pdu->p.snack.BegRun = tx_ccb->DataSN_buf.ExpSN;
1071 1.1 agc pdu->p.snack.RunLength = 0;
1072 1.1 agc break;
1073 1.1 agc
1074 1.1 agc default:
1075 1.1 agc DEBOUT(("Invalid type %d in send_snack\n", type));
1076 1.1 agc return;
1077 1.1 agc }
1078 1.1 agc
1079 1.1 agc pdu->LUN = rx_pdu->pdu.LUN;
1080 1.1 agc
1081 1.1 agc ppdu->flags = PDUF_PRIORITY;
1082 1.1 agc
1083 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1084 1.1 agc send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE);
1085 1.1 agc }
1086 1.1 agc
1087 1.1 agc
1088 1.1 agc /*
1089 1.1 agc * send_login:
1090 1.1 agc * Send login request.
1091 1.1 agc *
1092 1.1 agc * Parameter:
1093 1.1 agc * conn The connection
1094 1.1 agc * par The login parameters (for negotiation)
1095 1.1 agc *
1096 1.1 agc * Returns: 0 on success, else an error code.
1097 1.1 agc */
1098 1.1 agc
1099 1.1 agc int
1100 1.1 agc send_login(connection_t *conn)
1101 1.1 agc {
1102 1.1 agc ccb_t *ccb;
1103 1.1 agc pdu_t *pdu;
1104 1.1 agc int rc;
1105 1.1 agc
1106 1.1 agc DEBC(conn, 9, ("Send_login\n"));
1107 1.1 agc ccb = get_ccb(conn, TRUE);
1108 1.1 agc pdu = get_pdu(conn);
1109 1.1 agc
1110 1.1 agc /* only if terminating (which couldn't possibly happen here, but...) */
1111 1.1 agc if (ccb == NULL || pdu == NULL) {
1112 1.1 agc return conn->terminating;
1113 1.1 agc }
1114 1.1 agc if ((rc = assemble_login_parameters(conn, ccb, pdu)) >= 0) {
1115 1.1 agc init_login_pdu(conn, pdu, !rc);
1116 1.1 agc setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE);
1117 1.1 agc send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE);
1118 1.1 agc rc = ccb->status;
1119 1.1 agc } else {
1120 1.1 agc free_pdu(pdu);
1121 1.1 agc }
1122 1.1 agc free_ccb(ccb);
1123 1.1 agc return rc;
1124 1.1 agc }
1125 1.1 agc
1126 1.1 agc
1127 1.1 agc /*
1128 1.1 agc * send_logout:
1129 1.1 agc * Send logout request.
1130 1.1 agc * NOTE: This function does not wait for the logout to complete.
1131 1.1 agc *
1132 1.1 agc * Parameter:
1133 1.1 agc * conn The connection
1134 1.1 agc * refconn The referenced connection
1135 1.1 agc * reason The reason code
1136 1.1 agc * wait Wait for completion if TRUE
1137 1.1 agc *
1138 1.1 agc * Returns: 0 on success (logout sent), else an error code.
1139 1.1 agc */
1140 1.1 agc
1141 1.1 agc int
1142 1.1 agc send_logout(connection_t *conn, connection_t *refconn, int reason,
1143 1.1 agc bool wait)
1144 1.1 agc {
1145 1.1 agc ccb_t *ccb;
1146 1.1 agc pdu_t *ppdu;
1147 1.1 agc pdu_header_t *pdu;
1148 1.1 agc
1149 1.1 agc DEBC(conn, 5, ("Send_logout\n"));
1150 1.1 agc ccb = get_ccb(conn, TRUE);
1151 1.1 agc ppdu = get_pdu(conn);
1152 1.1 agc /* can only happen if terminating... */
1153 1.1 agc if (ccb == NULL || ppdu == NULL)
1154 1.1 agc return conn->terminating;
1155 1.1 agc
1156 1.1 agc pdu = &ppdu->pdu;
1157 1.1 agc pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE;
1158 1.1 agc
1159 1.1 agc pdu->Flags = FLAG_FINAL | reason;
1160 1.1 agc ccb->CmdSN = conn->session->CmdSN;
1161 1.1 agc pdu->p.logout_req.CmdSN = htonl(ccb->CmdSN);
1162 1.1 agc if (reason > 0)
1163 1.1 agc pdu->p.logout_req.CID = htons(refconn->id);
1164 1.1 agc
1165 1.1 agc ccb->par = refconn;
1166 1.1 agc if (refconn != conn) {
1167 1.1 agc ccb->flags |= CCBF_OTHERCONN;
1168 1.1 agc } else {
1169 1.1 agc conn->state = ST_LOGOUT_SENT;
1170 1.1 agc conn->loggedout = LOGOUT_SENT;
1171 1.1 agc }
1172 1.1 agc
1173 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1174 1.1 agc
1175 1.1 agc send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE);
1176 1.1 agc
1177 1.1 agc if (wait) {
1178 1.1 agc int rc = ccb->status;
1179 1.1 agc free_ccb (ccb);
1180 1.1 agc return rc;
1181 1.1 agc }
1182 1.1 agc return 0;
1183 1.1 agc }
1184 1.1 agc
1185 1.1 agc
1186 1.1 agc /*
1187 1.1 agc * send_task_management:
1188 1.1 agc * Send task management request.
1189 1.1 agc *
1190 1.1 agc * Parameter:
1191 1.1 agc * conn The connection
1192 1.1 agc * ref_ccb The referenced command (NULL if none)
1193 1.1 agc * xs The scsipi command structure (NULL if not a scsipi request)
1194 1.1 agc * function The function code
1195 1.1 agc *
1196 1.1 agc * Returns: 0 on success, else an error code.
1197 1.1 agc */
1198 1.1 agc
1199 1.1 agc int
1200 1.1 agc send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs,
1201 1.1 agc int function)
1202 1.1 agc {
1203 1.1 agc ccb_t *ccb;
1204 1.1 agc pdu_t *ppdu;
1205 1.1 agc pdu_header_t *pdu;
1206 1.1 agc
1207 1.1 agc DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n",
1208 1.1 agc ref_ccb, function));
1209 1.1 agc
1210 1.1 agc if (function == TASK_REASSIGN && conn->session->ErrorRecoveryLevel < 2)
1211 1.1 agc return ISCSI_STATUS_CANT_REASSIGN;
1212 1.1 agc
1213 1.1 agc ccb = get_ccb(conn, xs == NULL);
1214 1.1 agc ppdu = get_pdu(conn);
1215 1.1 agc /* can only happen if terminating... */
1216 1.1 agc if (ccb == NULL || ppdu == NULL)
1217 1.1 agc return conn->terminating;
1218 1.1 agc
1219 1.1 agc ccb->xs = xs;
1220 1.1 agc
1221 1.1 agc pdu = &ppdu->pdu;
1222 1.1 agc pdu->Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE;
1223 1.1 agc pdu->Flags = FLAG_FINAL | function;
1224 1.1 agc
1225 1.1 agc ccb->CmdSN = conn->session->CmdSN;
1226 1.1 agc pdu->p.task_req.CmdSN = htonl(ccb->CmdSN);
1227 1.1 agc
1228 1.1 agc if (ref_ccb != NULL) {
1229 1.1 agc pdu->p.task_req.ReferencedTaskTag = ref_ccb->ITT;
1230 1.1 agc pdu->p.task_req.RefCmdSN = htonl(ref_ccb->CmdSN);
1231 1.1 agc pdu->p.task_req.ExpDataSN = htonl(ref_ccb->DataSN_buf.ExpSN);
1232 1.1 agc } else
1233 1.1 agc pdu->p.task_req.ReferencedTaskTag = 0xffffffff;
1234 1.1 agc
1235 1.1 agc ppdu->flags |= PDUF_PRIORITY;
1236 1.1 agc
1237 1.1 agc setup_tx_uio(ppdu, 0, NULL, FALSE);
1238 1.1 agc send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE);
1239 1.1 agc
1240 1.1 agc if (xs == NULL) {
1241 1.1 agc int rc = ccb->status;
1242 1.1 agc free_ccb(ccb);
1243 1.1 agc return rc;
1244 1.1 agc }
1245 1.1 agc return 0;
1246 1.1 agc }
1247 1.1 agc
1248 1.1 agc
1249 1.1 agc /*
1250 1.1 agc * send_data_out:
1251 1.1 agc * Send data to target in response to an R2T or as unsolicited data.
1252 1.1 agc *
1253 1.1 agc * Parameter:
1254 1.1 agc * conn The connection
1255 1.1 agc * rx_pdu The received R2T PDU (NULL if unsolicited)
1256 1.1 agc * tx_ccb The originally sent command CCB
1257 1.1 agc * waitok Whether it's OK to wait for an available PDU or not
1258 1.1 agc */
1259 1.1 agc
1260 1.1 agc int
1261 1.1 agc send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb,
1262 1.1 agc ccb_disp_t disp, bool waitok)
1263 1.1 agc {
1264 1.1 agc pdu_header_t *pdu;
1265 1.1 agc uint32_t totlen, len, offs, sn;
1266 1.1 agc pdu_t *tx_pdu;
1267 1.1 agc
1268 1.1 agc assert(conn->max_transfer != 0);
1269 1.1 agc
1270 1.1 agc if (rx_pdu) {
1271 1.1 agc offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset);
1272 1.1 agc totlen = ntohl(rx_pdu->pdu.p.r2t.DesiredDataTransferLength);
1273 1.1 agc } else {
1274 1.1 agc offs = conn->max_firstimmed;
1275 1.1 agc totlen = min(conn->max_firstdata - offs, tx_ccb->data_len - offs);
1276 1.1 agc }
1277 1.1 agc sn = 0;
1278 1.1 agc
1279 1.1 agc while (totlen) {
1280 1.1 agc len = min(totlen, conn->max_transfer);
1281 1.1 agc
1282 1.1 agc tx_pdu = get_pdu_c(conn, waitok);
1283 1.1 agc if (tx_pdu == NULL) {
1284 1.1 agc DEBOUT(("No PDU in send_data_out\n"));
1285 1.1 agc
1286 1.1 agc tx_ccb->status = ISCSI_STATUS_NO_RESOURCES;
1287 1.1 agc handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT);
1288 1.1 agc
1289 1.1 agc return ISCSI_STATUS_NO_RESOURCES;
1290 1.1 agc }
1291 1.1 agc
1292 1.1 agc totlen -= len;
1293 1.1 agc pdu = &tx_pdu->pdu;
1294 1.1 agc pdu->Opcode = IOP_SCSI_Data_out;
1295 1.1 agc if (!totlen)
1296 1.1 agc pdu->Flags = FLAG_FINAL;
1297 1.1 agc
1298 1.1 agc if (rx_pdu != NULL)
1299 1.1 agc pdu->p.data_out.TargetTransferTag =
1300 1.1 agc rx_pdu->pdu.p.r2t.TargetTransferTag;
1301 1.1 agc else
1302 1.1 agc pdu->p.data_out.TargetTransferTag = 0xffffffff;
1303 1.1 agc pdu->p.data_out.BufferOffset = htonl(offs);
1304 1.1 agc pdu->p.data_out.DataSN = htonl(sn);
1305 1.1 agc
1306 1.1 agc PERF_PDUSET(tx_pdu, tx_ccb, PERF_BEGIN_PDUWRITEDATA);
1307 1.1 agc
1308 1.1 agc DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n",
1309 1.1 agc sn, len, offs, totlen));
1310 1.1 agc
1311 1.1 agc setup_tx_uio(tx_pdu, len, tx_ccb->data_ptr + offs, FALSE);
1312 1.1 agc
1313 1.1 agc send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE);
1314 1.1 agc
1315 1.1 agc sn++;
1316 1.1 agc offs += len;
1317 1.1 agc }
1318 1.1 agc return 0;
1319 1.1 agc }
1320 1.1 agc
1321 1.1 agc
1322 1.1 agc /*
1323 1.1 agc * send_command:
1324 1.1 agc * Send a SCSI command request.
1325 1.1 agc *
1326 1.1 agc * Parameter:
1327 1.1 agc * CCB The CCB
1328 1.1 agc * disp The CCB disposition
1329 1.1 agc */
1330 1.1 agc
1331 1.1 agc void
1332 1.1 agc send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed)
1333 1.1 agc {
1334 1.1 agc uint32_t totlen, len;
1335 1.1 agc connection_t *conn = ccb->connection;
1336 1.1 agc session_t *sess = ccb->session;
1337 1.1 agc pdu_t *ppdu;
1338 1.1 agc pdu_header_t *pdu;
1339 1.1 agc int s;
1340 1.1 agc
1341 1.1 agc PERF_BEGIN(ccb, !waitok);
1342 1.1 agc
1343 1.1 agc if (!waitok) {
1344 1.1 agc s = splbio();
1345 1.1 agc if (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
1346 1.1 agc /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
1347 1.1 agc !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
1348 1.1 agc TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
1349 1.1 agc splx(s);
1350 1.1 agc PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n",
1351 1.1 agc sess->CmdSN, sess->MaxCmdSN));
1352 1.1 agc return;
1353 1.1 agc }
1354 1.1 agc splx(s);
1355 1.1 agc ppdu = get_pdu_c(conn, FALSE);
1356 1.1 agc if (ppdu == NULL) {
1357 1.1 agc ccb->status = ISCSI_STATUS_NO_RESOURCES;
1358 1.1 agc iscsi_done(ccb);
1359 1.1 agc return;
1360 1.1 agc }
1361 1.1 agc } else {
1362 1.1 agc s = splbio();
1363 1.1 agc while (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED &&
1364 1.1 agc /*CONSTCOND*/ISCSI_SERVER_TRUSTED &&
1365 1.1 agc !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) {
1366 1.1 agc ccb->flags |= CCBF_WAITING;
1367 1.1 agc TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
1368 1.1 agc PDEBOUT(("Throttling W - CmdSN = %d, MaxCmdSN = %d\n",
1369 1.1 agc sess->CmdSN, sess->MaxCmdSN));
1370 1.1 agc tsleep(ccb, PWAIT, "waitMaxCmd", 0);
1371 1.1 agc splbio();
1372 1.1 agc }
1373 1.1 agc splx(s);
1374 1.1 agc ppdu = get_pdu(conn);
1375 1.1 agc }
1376 1.1 agc
1377 1.1 agc pdu = &ppdu->pdu;
1378 1.1 agc pdu->LUN = htonq(ccb->lun);
1379 1.1 agc memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen);
1380 1.1 agc totlen = len = ccb->data_len;
1381 1.1 agc pdu->Opcode = IOP_SCSI_Command;
1382 1.1 agc if (immed)
1383 1.1 agc pdu->Opcode |= OP_IMMEDIATE;
1384 1.1 agc pdu->p.command.ExpectedDataTransferLength = htonl(totlen);
1385 1.1 agc
1386 1.1 agc
1387 1.1 agc if (totlen) {
1388 1.1 agc if (ccb->data_in) {
1389 1.1 agc pdu->Flags = FLAG_READ;
1390 1.1 agc totlen = 0;
1391 1.1 agc } else {
1392 1.1 agc pdu->Flags = FLAG_WRITE;
1393 1.1 agc len = min(totlen, conn->max_firstimmed);
1394 1.1 agc /* this means InitialR2T=Yes or FirstBurstLength=0 */
1395 1.1 agc if (!len)
1396 1.1 agc totlen = 0;
1397 1.1 agc else
1398 1.1 agc totlen -= len;
1399 1.1 agc }
1400 1.1 agc }
1401 1.1 agc
1402 1.1 agc if (!totlen)
1403 1.1 agc pdu->Flags |= FLAG_FINAL;
1404 1.1 agc
1405 1.1 agc if (ccb->data_in)
1406 1.1 agc init_sernum(&ccb->DataSN_buf);
1407 1.1 agc
1408 1.1 agc ccb->sense_len_got = 0;
1409 1.1 agc ccb->xfer_len = 0;
1410 1.1 agc ccb->residual = 0;
1411 1.1 agc ccb->flags |= CCBF_REASSIGN;
1412 1.1 agc
1413 1.1 agc s = splbio();
1414 1.1 agc ccb->CmdSN = sess->CmdSN;
1415 1.1 agc if (!immed)
1416 1.1 agc sess->CmdSN++;
1417 1.1 agc splx(s);
1418 1.1 agc
1419 1.1 agc pdu->p.command.CmdSN = htonl(ccb->CmdSN);
1420 1.1 agc
1421 1.1 agc DEBC(conn, 10, ("Send Command: CmdSN %d, data_in %d, len %d, totlen %d\n",
1422 1.1 agc ccb->CmdSN, ccb->data_in, len, totlen));
1423 1.1 agc
1424 1.1 agc PERF_PDUSET(ppdu, ccb, PERF_BEGIN_PDUWRITECMD);
1425 1.1 agc
1426 1.1 agc setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in);
1427 1.1 agc
1428 1.1 agc send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT);
1429 1.1 agc
1430 1.1 agc if (totlen)
1431 1.1 agc send_data_out(conn, NULL, ccb, disp, waitok);
1432 1.1 agc }
1433 1.1 agc
1434 1.1 agc
1435 1.1 agc /*
1436 1.1 agc * send_run_xfer:
1437 1.1 agc * Handle a SCSI command transfer request from scsipi.
1438 1.1 agc *
1439 1.1 agc * Parameter:
1440 1.1 agc * session The session
1441 1.1 agc * xs The transfer parameters
1442 1.1 agc */
1443 1.1 agc
1444 1.1 agc void
1445 1.1 agc send_run_xfer(session_t *session, struct scsipi_xfer *xs)
1446 1.1 agc {
1447 1.1 agc ccb_t *ccb;
1448 1.1 agc connection_t *conn;
1449 1.1 agc bool waitok;
1450 1.1 agc
1451 1.1 agc waitok = !(xs->xs_control & XS_CTL_NOSLEEP);
1452 1.1 agc
1453 1.1 agc DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, "
1454 1.1 agc "waitok=%d\n", xs->xs_control, xs->data, xs->datalen,
1455 1.1 agc xs->resid, xs->cmdlen, waitok));
1456 1.1 agc
1457 1.1 agc conn = assign_connection(session, waitok);
1458 1.1 agc
1459 1.1 agc if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
1460 1.1 agc xs->error = XS_REQUEUE;
1461 1.1 agc DEBC(conn, 10, ("run_xfer on dead connection\n"));
1462 1.1 agc scsipi_done(xs);
1463 1.1 agc return;
1464 1.1 agc }
1465 1.1 agc
1466 1.1 agc if (xs->xs_control & XS_CTL_RESET) {
1467 1.1 agc if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) {
1468 1.1 agc xs->error = XS_SELTIMEOUT;
1469 1.1 agc scsipi_done(xs);
1470 1.1 agc }
1471 1.1 agc return;
1472 1.1 agc }
1473 1.1 agc
1474 1.1 agc ccb = get_ccb(conn, waitok);
1475 1.1 agc if (ccb == NULL) {
1476 1.1 agc xs->error = XS_RESOURCE_SHORTAGE;
1477 1.1 agc DEBC(conn, 0, ("No CCB in run_xfer\n"));
1478 1.1 agc scsipi_done(xs);
1479 1.1 agc return;
1480 1.1 agc }
1481 1.1 agc /* copy parameters into CCB for easier access */
1482 1.1 agc ccb->xs = xs;
1483 1.1 agc
1484 1.1 agc ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0;
1485 1.1 agc ccb->data_len = (uint32_t) xs->datalen;
1486 1.1 agc ccb->data_ptr = xs->data;
1487 1.1 agc
1488 1.1 agc ccb->sense_len_req = sizeof(xs->sense.scsi_sense);
1489 1.1 agc ccb->sense_ptr = &xs->sense;
1490 1.1 agc
1491 1.1 agc ccb->lun = (uint64_t) xs->xs_periph->periph_lun << 48;
1492 1.1 agc ccb->cmd = (uint8_t *) xs->cmd;
1493 1.1 agc ccb->cmdlen = xs->cmdlen;
1494 1.1 agc DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n",
1495 1.1 agc xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen));
1496 1.1 agc
1497 1.1 agc #ifdef LUN_1
1498 1.1 agc ccb->lun += 0x1000000000000LL;
1499 1.1 agc ccb->cmd[1] += 0x10;
1500 1.1 agc #endif
1501 1.1 agc send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE);
1502 1.1 agc }
1503 1.1 agc
1504 1.1 agc
1505 1.1 agc #ifndef ISCSI_MINIMAL
1506 1.1 agc /*
1507 1.1 agc * send_io_command:
1508 1.1 agc * Handle a SCSI io command request from user space.
1509 1.1 agc *
1510 1.1 agc * Parameter:
1511 1.1 agc * session The session
1512 1.1 agc * lun The LUN to use
1513 1.1 agc * req The SCSI request block
1514 1.1 agc * immed Immediate command if TRUE
1515 1.1 agc * conn_id Assign to this connection ID if nonzero
1516 1.1 agc */
1517 1.1 agc
1518 1.1 agc int
1519 1.1 agc send_io_command(session_t *session, uint64_t lun, scsireq_t *req,
1520 1.1 agc bool immed, uint32_t conn_id)
1521 1.1 agc {
1522 1.1 agc ccb_t *ccb;
1523 1.1 agc connection_t *conn;
1524 1.1 agc int rc;
1525 1.1 agc
1526 1.1 agc DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n",
1527 1.1 agc (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id));
1528 1.1 agc
1529 1.1 agc conn = (conn_id) ? find_connection(session, conn_id)
1530 1.1 agc : assign_connection(session, TRUE);
1531 1.1 agc
1532 1.1 agc if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) {
1533 1.1 agc DEBOUT(("io_command on dead connection (state = %d)\n",
1534 1.1 agc (conn != NULL) ? conn->state : -1));
1535 1.1 agc return ISCSI_STATUS_INVALID_CONNECTION_ID;
1536 1.1 agc }
1537 1.1 agc
1538 1.1 agc ccb = get_ccb(conn, TRUE);
1539 1.1 agc if (ccb == NULL) {
1540 1.1 agc DEBOUT(("No CCB in io_command\n"));
1541 1.1 agc return ISCSI_STATUS_NO_RESOURCES;
1542 1.1 agc }
1543 1.1 agc
1544 1.1 agc ccb->data_in = (req->flags & SCCMD_READ) != 0;
1545 1.1 agc ccb->data_len = (uint32_t) req->datalen;
1546 1.1 agc ccb->data_ptr = req->databuf;
1547 1.1 agc
1548 1.1 agc ccb->sense_len_req = req->senselen;
1549 1.1 agc ccb->sense_ptr = &req->sense;
1550 1.1 agc
1551 1.1 agc ccb->lun = lun;
1552 1.1 agc ccb->cmd = (uint8_t *) req->cmd;
1553 1.1 agc ccb->cmdlen = req->cmdlen;
1554 1.1 agc DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n",
1555 1.1 agc ccb->cmd[1], ccb->cmdlen));
1556 1.1 agc
1557 1.1 agc send_command(ccb, CCBDISP_WAIT, TRUE, immed);
1558 1.1 agc
1559 1.1 agc rc = ccb->status;
1560 1.1 agc
1561 1.1 agc req->senselen_used = ccb->sense_len_got;
1562 1.1 agc req->datalen_used = req->datalen - ccb->residual;
1563 1.1 agc
1564 1.1 agc free_ccb(ccb);
1565 1.1 agc
1566 1.1 agc return rc;
1567 1.1 agc }
1568 1.1 agc #endif
1569 1.1 agc
1570 1.1 agc
1571 1.1 agc /*****************************************************************************
1572 1.1 agc * Timeout handlers
1573 1.1 agc *****************************************************************************/
1574 1.1 agc /*
1575 1.1 agc * connection_timeout:
1576 1.1 agc * Handle prolonged silence on a connection by checking whether
1577 1.1 agc * it's still alive.
1578 1.1 agc * This has the side effect of discovering missing status or lost commands
1579 1.1 agc * before those time out.
1580 1.1 agc *
1581 1.1 agc * Parameter:
1582 1.1 agc * par The connection
1583 1.1 agc */
1584 1.1 agc
1585 1.1 agc void
1586 1.1 agc connection_timeout(void *par)
1587 1.1 agc {
1588 1.1 agc connection_t *conn = (connection_t *) par;
1589 1.1 agc
1590 1.1 agc PDEBC(conn, 1, ("Connection Timeout, num_timeouts=%d\n",
1591 1.1 agc conn->num_timeouts));
1592 1.1 agc
1593 1.1 agc if (++conn->num_timeouts > MAX_CONN_TIMEOUTS)
1594 1.1 agc handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT);
1595 1.1 agc else {
1596 1.1 agc if (conn->state == ST_FULL_FEATURE)
1597 1.1 agc send_nop_out(conn, NULL);
1598 1.1 agc
1599 1.1 agc SET_CONN_TIMEOUT(conn, CONNECTION_TIMEOUT);
1600 1.1 agc }
1601 1.1 agc }
1602 1.1 agc
1603 1.1 agc /*
1604 1.1 agc * ccb_timeout:
1605 1.1 agc * Handle timeout of a sent command.
1606 1.1 agc *
1607 1.1 agc * Parameter:
1608 1.1 agc * par The CCB
1609 1.1 agc */
1610 1.1 agc
1611 1.1 agc void
1612 1.1 agc ccb_timeout(void *par)
1613 1.1 agc {
1614 1.1 agc ccb_t *ccb = (ccb_t *) par;
1615 1.1 agc connection_t *conn = ccb->connection;
1616 1.1 agc
1617 1.1 agc PDEBC(conn, 1, ("CCB Timeout, ccb=%x, num_timeouts=%d\n",
1618 1.1 agc (int) ccb, ccb->num_timeouts));
1619 1.1 agc
1620 1.1 agc /* ignore CCB timeouts outside full feature phase */
1621 1.1 agc if (conn->state != ST_FULL_FEATURE)
1622 1.1 agc return;
1623 1.1 agc
1624 1.1 agc ccb->total_tries++;
1625 1.1 agc
1626 1.1 agc if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS ||
1627 1.1 agc ccb->total_tries > MAX_CCB_TRIES ||
1628 1.1 agc ccb->disp <= CCBDISP_FREE ||
1629 1.1 agc !ccb->session->ErrorRecoveryLevel) {
1630 1.1 agc handle_connection_error(conn, ISCSI_STATUS_TIMEOUT,
1631 1.1 agc (ccb->total_tries <= MAX_CCB_TRIES) ? RECOVER_CONNECTION
1632 1.1 agc : LOGOUT_CONNECTION);
1633 1.1 agc } else {
1634 1.1 agc if (ccb->data_in && ccb->xfer_len < ccb->data_len) {
1635 1.1 agc /* request resend of all missing data */
1636 1.1 agc snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0);
1637 1.1 agc } else {
1638 1.1 agc /* request resend of all missing status */
1639 1.1 agc snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0);
1640 1.1 agc }
1641 1.1 agc SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT);
1642 1.1 agc }
1643 1.1 agc }
1644