1 /*
2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
24
25 #ifdef HAVE_ARPA_INET_H
26 #include <arpa/inet.h>
27 #endif
28
29 #ifdef HAVE_INTTYPES_H
30 #include <inttypes.h>
31 #else
32 #define PRIu64 "llu"
33 #define PRIx32 "x"
34 #endif
35
36 #if defined(_WIN32)
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 #include "win32/win32_compat.h"
40 #else
41 #include <strings.h>
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "iscsi.h"
48 #include "iscsi-private.h"
49 #include "scsi-lowlevel.h"
50 #include "slist.h"
51
52 /* This adds 32-bit serial comparision as defined in RFC1982.
53 * It returns 0 for equality, 1 if s1 is greater than s2 and
54 * -1 if s1 is less than s2. According to RFC1982 section 3.2
55 * there are rare cases where the result of the comparision is
56 * undefined e.g. when s1 = 0 and s2=2^31. This cases should
57 * not happen in iSCSI protocol.
58 */
59 int
iscsi_serial32_compare(uint32_t s1,uint32_t s2)60 iscsi_serial32_compare(uint32_t s1, uint32_t s2) {
61 if (s1 == s2) return 0;
62 if (s1 < s2 && s2-s1 < (uint32_t)1<<31) return -1;
63 if (s1 > s2 && s1-s2 < (uint32_t)1<<31) return 1;
64 if (s1 > s2 && s1-s2 > (uint32_t)1<<31) return -1;
65 if (s1 < s2 && s2-s1 > (uint32_t)1<<31) return 1;
66 /* undefined result */
67 return -1;
68 }
69
70 uint32_t
iscsi_itt_post_increment(struct iscsi_context * iscsi)71 iscsi_itt_post_increment(struct iscsi_context *iscsi) {
72 uint32_t old_itt = iscsi->itt;
73 iscsi->itt++;
74 /* 0xffffffff is a reserved value */
75 if (iscsi->itt == 0xffffffff) {
76 iscsi->itt = 0;
77 }
78 return old_itt;
79 }
80
iscsi_dump_pdu_header(struct iscsi_context * iscsi,unsigned char * data)81 void iscsi_dump_pdu_header(struct iscsi_context *iscsi, unsigned char *data) {
82 char dump[ISCSI_RAW_HEADER_SIZE*3+1]={0};
83 int i;
84 for (i=0;i<ISCSI_RAW_HEADER_SIZE;i++) {
85 snprintf(&dump[i * 3], 4, " %02x", data[i]);
86 }
87 ISCSI_LOG(iscsi, 2, "PDU header:%s", dump);
88 }
89
90 struct iscsi_pdu*
iscsi_tcp_new_pdu(struct iscsi_context * iscsi,size_t size)91 iscsi_tcp_new_pdu(struct iscsi_context *iscsi, size_t size)
92 {
93 struct iscsi_pdu *pdu;
94
95 pdu = iscsi_szmalloc(iscsi, size);
96
97 return pdu;
98 }
99
100 struct iscsi_pdu *
iscsi_allocate_pdu(struct iscsi_context * iscsi,enum iscsi_opcode opcode,enum iscsi_opcode response_opcode,uint32_t itt,uint32_t flags)101 iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode,
102 enum iscsi_opcode response_opcode, uint32_t itt,
103 uint32_t flags)
104 {
105 struct iscsi_pdu *pdu;
106
107 pdu = iscsi->drv->new_pdu(iscsi, sizeof(struct iscsi_pdu));
108 if (pdu == NULL) {
109 iscsi_set_error(iscsi, "failed to allocate pdu");
110 return NULL;
111 }
112
113 pdu->outdata.size = ISCSI_HEADER_SIZE(iscsi->header_digest);
114 pdu->outdata.data = iscsi_szmalloc(iscsi, pdu->outdata.size);
115
116 if (pdu->outdata.data == NULL) {
117 iscsi_set_error(iscsi, "failed to allocate pdu header");
118 iscsi_free(iscsi, pdu);
119 return NULL;
120 }
121
122 /* opcode */
123 pdu->outdata.data[0] = opcode;
124 pdu->response_opcode = response_opcode;
125
126 /* isid */
127 if (opcode == ISCSI_PDU_LOGIN_REQUEST) {
128 memcpy(&pdu->outdata.data[8], &iscsi->isid[0], 6);
129 }
130
131 /* itt */
132 iscsi_pdu_set_itt(pdu, itt);
133 pdu->itt = itt;
134
135 /* flags */
136 pdu->flags = flags;
137
138 return pdu;
139 }
140
141 void
iscsi_tcp_free_pdu(struct iscsi_context * iscsi,struct iscsi_pdu * pdu)142 iscsi_tcp_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
143 {
144 if (pdu == NULL) {
145 iscsi_set_error(iscsi, "trying to free NULL pdu");
146 return;
147 }
148
149 if (pdu->outdata.size <= iscsi->smalloc_size) {
150 iscsi_sfree(iscsi, pdu->outdata.data);
151 } else {
152 iscsi_free(iscsi, pdu->outdata.data);
153 }
154 pdu->outdata.data = NULL;
155
156 if (pdu->indata.size <= iscsi->smalloc_size) {
157 iscsi_sfree(iscsi, pdu->indata.data);
158 } else {
159 iscsi_free(iscsi, pdu->indata.data);
160 }
161 pdu->indata.data = NULL;
162
163 if (iscsi->outqueue_current == pdu) {
164 iscsi->outqueue_current = NULL;
165 }
166
167 iscsi_sfree(iscsi, pdu);
168 }
169
170 int
iscsi_add_data(struct iscsi_context * iscsi,struct iscsi_data * data,unsigned char * dptr,int dsize,int pdualignment)171 iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data,
172 unsigned char *dptr, int dsize, int pdualignment)
173 {
174 size_t len, aligned;
175
176 if (dsize == 0) {
177 iscsi_set_error(iscsi, "Trying to append zero size data to "
178 "iscsi_data");
179 return -1;
180 }
181
182 len = data->size + dsize;
183
184 aligned = len;
185 if (pdualignment) {
186 aligned = (aligned+3)&0xfffffffc;
187 }
188
189 if (data->size == 0) {
190 if (aligned <= iscsi->smalloc_size) {
191 data->data = iscsi_szmalloc(iscsi, aligned);
192 } else {
193 data->data = iscsi_malloc(iscsi, aligned);
194 }
195 } else {
196 if (aligned > iscsi->smalloc_size) {
197 data->data = iscsi_realloc(iscsi, data->data, aligned);
198 }
199 }
200 if (data->data == NULL) {
201 iscsi_set_error(iscsi, "failed to allocate buffer for %d "
202 "bytes", (int) len);
203 return -1;
204 }
205
206 memcpy(data->data + data->size, dptr, dsize);
207 data->size += dsize;
208
209 if (len != aligned) {
210 /* zero out any padding at the end */
211 memset(data->data + len, 0, aligned - len);
212 }
213
214 return 0;
215 }
216
217 int
iscsi_pdu_add_data(struct iscsi_context * iscsi,struct iscsi_pdu * pdu,unsigned char * dptr,int dsize)218 iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
219 unsigned char *dptr, int dsize)
220 {
221 if (pdu == NULL) {
222 iscsi_set_error(iscsi, "trying to add data to NULL pdu");
223 return -1;
224 }
225 if (dsize == 0) {
226 iscsi_set_error(iscsi, "Trying to append zero size data to "
227 "pdu");
228 return -1;
229 }
230
231 if (iscsi_add_data(iscsi, &pdu->outdata, dptr, dsize, 1) != 0) {
232 iscsi_set_error(iscsi, "failed to add data to pdu buffer");
233 return -1;
234 }
235
236 /* update data segment length */
237 scsi_set_uint32(&pdu->outdata.data[4], pdu->outdata.size
238 - ISCSI_HEADER_SIZE(iscsi->header_digest));
239
240 return 0;
241 }
242
243 int
iscsi_get_pdu_data_size(const unsigned char * hdr)244 iscsi_get_pdu_data_size(const unsigned char *hdr)
245 {
246 int size;
247
248 size = scsi_get_uint32(&hdr[4]) & 0x00ffffff;
249
250 return size;
251 }
252
253 int
iscsi_get_pdu_padding_size(const unsigned char * hdr)254 iscsi_get_pdu_padding_size(const unsigned char *hdr)
255 {
256 int data_size, padded_size;
257
258 data_size = scsi_get_uint32(&hdr[4]) & 0x00ffffff;
259 padded_size = (data_size+3) & 0xfffffffc;
260
261 return padded_size - data_size;
262 }
263
264 enum iscsi_reject_reason {
265 ISCSI_REJECT_RESERVED = 0x01,
266 ISCSI_REJECT_DATA_DIGEST_ERROR = 0x02,
267 ISCSI_REJECT_SNACK_REJECT = 0x03,
268 ISCSI_REJECT_PROTOCOL_ERROR = 0x04,
269 ISCSI_REJECT_COMMAND_NOT_SUPPORTED = 0x05,
270 ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT = 0x06,
271 ISCSI_REJECT_TASK_IN_PROCESS = 0x07,
272 ISCSI_REJECT_INVALID_DATA_ACK = 0x08,
273 ISCSI_REJECT_INVALID_PDU_FIELD = 0x09,
274 ISCSI_REJECT_LONG_OPERATION_REJECT = 0x0a,
275 ISCSI_REJECT_NEGOTIATION_RESET = 0x0b,
276 ISCSI_REJECT_WAITING_FOR_LOGOUT = 0x0c
277 };
278
iscsi_reject_reason_str(enum iscsi_reject_reason reason)279 static const char *iscsi_reject_reason_str(enum iscsi_reject_reason reason)
280 {
281 switch (reason) {
282 case ISCSI_REJECT_RESERVED:
283 return "Reserved";
284 case ISCSI_REJECT_DATA_DIGEST_ERROR:
285 return "Data Digest Error";
286 case ISCSI_REJECT_SNACK_REJECT:
287 return "SNACK Reject";
288 case ISCSI_REJECT_PROTOCOL_ERROR:
289 return "Protocol Error";
290 case ISCSI_REJECT_COMMAND_NOT_SUPPORTED:
291 return "Command Not Supported";
292 case ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT:
293 return "Immediate Command Reject";
294 case ISCSI_REJECT_TASK_IN_PROCESS:
295 return "Task In Process";
296 case ISCSI_REJECT_INVALID_DATA_ACK:
297 return "Invalid Data ACK";
298 case ISCSI_REJECT_INVALID_PDU_FIELD:
299 return "Invalid PDU Field";
300 case ISCSI_REJECT_LONG_OPERATION_REJECT:
301 return "Long Operation Reject";
302 case ISCSI_REJECT_NEGOTIATION_RESET:
303 return "Negotiation Reset";
304 case ISCSI_REJECT_WAITING_FOR_LOGOUT:
305 return "Waiting For Logout";
306 }
307
308 return "Unknown";
309 }
310
iscsi_process_target_nop_in(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)311 int iscsi_process_target_nop_in(struct iscsi_context *iscsi,
312 struct iscsi_in_pdu *in)
313 {
314 uint32_t ttt = scsi_get_uint32(&in->hdr[20]);
315 uint32_t itt = scsi_get_uint32(&in->hdr[16]);
316 uint32_t lun = scsi_get_uint16(&in->hdr[8]);
317
318 ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
319 "NOP-In received (pdu->itt %08x, pdu->ttt %08x, pdu->lun %8x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)",
320 itt, ttt, lun, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn);
321
322 /* if the server does not want a response */
323 if (ttt == 0xffffffff) {
324 return 0;
325 }
326
327 iscsi_send_target_nop_out(iscsi, ttt, lun);
328
329 return 0;
330 }
331
iscsi_reconnect_after_logout(struct iscsi_context * iscsi,int status,void * command_data _U_,void * opaque _U_)332 static void iscsi_reconnect_after_logout(struct iscsi_context *iscsi, int status,
333 void *command_data _U_, void *opaque _U_)
334 {
335 if (status) {
336 ISCSI_LOG(iscsi, 1, "logout failed: %s", iscsi_get_error(iscsi));
337 }
338 iscsi->pending_reconnect = 1;
339 }
340
iscsi_process_reject(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)341 int iscsi_process_reject(struct iscsi_context *iscsi,
342 struct iscsi_in_pdu *in)
343 {
344 int size = in->data_pos;
345 uint32_t itt;
346 struct iscsi_pdu *pdu;
347 uint8_t reason = in->hdr[2];
348
349 if (size < ISCSI_RAW_HEADER_SIZE) {
350 iscsi_set_error(iscsi, "size of REJECT payload is too small."
351 "Need >= %d bytes but got %d.",
352 ISCSI_RAW_HEADER_SIZE, (int)size);
353 return -1;
354 }
355
356 if (reason == ISCSI_REJECT_WAITING_FOR_LOGOUT) {
357 ISCSI_LOG(iscsi, 1, "target rejects request with reason: %s", iscsi_reject_reason_str(reason));
358 iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
359 return 0;
360 }
361
362 iscsi_set_error(iscsi, "Request was rejected with reason: 0x%02x (%s)", reason, iscsi_reject_reason_str(reason));
363
364 itt = scsi_get_uint32(&in->data[16]);
365
366 iscsi_dump_pdu_header(iscsi, in->data);
367
368 for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
369 if (pdu->itt == itt) {
370 break;
371 }
372 }
373
374 if (pdu == NULL) {
375 iscsi_set_error(iscsi, "Can not match REJECT with"
376 "any outstanding pdu with itt:0x%08x",
377 itt);
378 return -1;
379 }
380
381 if (pdu->callback) {
382 pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
383 pdu->private_data);
384 }
385
386 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
387 iscsi->drv->free_pdu(iscsi, pdu);
388 return 0;
389 }
390
iscsi_process_pdu_serials(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)391 static void iscsi_process_pdu_serials(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
392 {
393 uint32_t itt = scsi_get_uint32(&in->hdr[16]);
394 uint32_t statsn = scsi_get_uint32(&in->hdr[24]);
395 uint32_t maxcmdsn = scsi_get_uint32(&in->hdr[32]);
396 uint32_t expcmdsn = scsi_get_uint32(&in->hdr[28]);
397 uint16_t status = scsi_get_uint16(&in->hdr[36]);
398 uint8_t flags = in->hdr[1];
399 enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
400
401 /* RFC3720 10.13.5 (serials are invalid if status class != 0) */
402 if (opcode == ISCSI_PDU_LOGIN_RESPONSE && (status >> 8)) {
403 return;
404 }
405
406 if (iscsi_serial32_compare(maxcmdsn, iscsi->maxcmdsn) > 0) {
407 iscsi->maxcmdsn = maxcmdsn;
408 }
409 if (iscsi_serial32_compare(expcmdsn, iscsi->expcmdsn) > 0) {
410 iscsi->expcmdsn = expcmdsn;
411 }
412
413 /* RFC3720 10.7.3 (StatSN is invalid if S bit unset in flags) */
414 if (opcode == ISCSI_PDU_DATA_IN &&
415 !(flags & ISCSI_PDU_DATA_CONTAINS_STATUS)) {
416 return;
417 }
418
419 if (itt == 0xffffffff) {
420 /* target will not increase statsn if itt == 0xffffffff */
421 statsn--;
422 }
423 if (iscsi_serial32_compare(statsn, iscsi->statsn) > 0) {
424 iscsi->statsn = statsn;
425 }
426 }
427
428 int
iscsi_process_pdu(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)429 iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
430 {
431 uint32_t itt = scsi_get_uint32(&in->hdr[16]);
432 enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
433 uint8_t ahslen = in->hdr[4];
434 struct iscsi_pdu *pdu;
435
436 /* verify header checksum */
437 if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) {
438 uint32_t crc, crc_rcvd = 0;
439 crc = crc32c(in->hdr, ISCSI_RAW_HEADER_SIZE);
440 crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+0];
441 crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+1] << 8;
442 crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+2] << 16;
443 crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+3] << 24;
444 if (crc != crc_rcvd) {
445 iscsi_set_error(iscsi, "header checksum verification failed: calculated 0x%" PRIx32 " received 0x%" PRIx32, crc, crc_rcvd);
446 return -1;
447 }
448 }
449
450 if (ahslen != 0) {
451 iscsi_set_error(iscsi, "cant handle expanded headers yet");
452 return -1;
453 }
454
455 /* All target PDUs update the serials */
456 iscsi_process_pdu_serials(iscsi, in);
457
458 if (opcode == ISCSI_PDU_ASYNC_MSG) {
459 uint8_t event = in->hdr[36];
460 uint16_t param1 = scsi_get_uint16(&in->hdr[38]);
461 uint16_t param2 = scsi_get_uint16(&in->hdr[40]);
462 uint16_t param3 = scsi_get_uint16(&in->hdr[42]);
463 switch (event) {
464 case 0x0:
465 /* Just ignore these ones for now. It could be
466 * a UNIT_ATTENTION for some changes on the
467 * target but we don't have an API to pass this on
468 * to the application yet.
469 */
470 ISCSI_LOG(iscsi, 2, "Ignoring received iSCSI AsyncMsg/"
471 "SCSI Async Event");
472 return 0;
473 case 0x1:
474 ISCSI_LOG(iscsi, 2, "target requests logout within %u seconds", param3);
475 /* this is an ugly workaround for DELL Equallogic FW 7.x bugs:
476 * Bug_71409 - I/O errors during volume move (present before 7.0.7)
477 * Bug_73732 - I/O errors during volume move operation (still present in 7.0.9)
478 */
479 if (getenv("LIBISCSI_DROP_CONN_ON_ASYNC_EVENT1") != NULL) {
480 ISCSI_LOG(iscsi, 2, "dropping connection to fix errors with broken DELL Equallogic firmware 7.x");
481 return -1;
482 }
483 iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
484 return 0;
485 case 0x2:
486 ISCSI_LOG(iscsi, 2, "target will drop this connection. Time2Wait is %u seconds", param2);
487 iscsi->next_reconnect = time(NULL) + param2;
488 return 0;
489 case 0x3:
490 ISCSI_LOG(iscsi, 2, "target will drop all connections of this session. Time2Wait is %u seconds", param2);
491 iscsi->next_reconnect = time(NULL) + param2;
492 return 0;
493 case 0x4:
494 ISCSI_LOG(iscsi, 2, "target requests parameter renogitiation.");
495 iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
496 return 0;
497 default:
498 ISCSI_LOG(iscsi, 1, "unhandled async event %u: param1 %u param2 %u param3 %u", event, param1, param2, param3);
499 return -1;
500 }
501 }
502
503 if (opcode == ISCSI_PDU_REJECT) {
504 return iscsi_process_reject(iscsi, in);
505 }
506
507 if (opcode == ISCSI_PDU_NOP_IN && itt == 0xffffffff) {
508 if (iscsi_process_target_nop_in(iscsi, in) != 0) {
509 return -1;
510 }
511 return 0;
512 }
513
514 for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
515 enum iscsi_opcode expected_response = pdu->response_opcode;
516 int is_finished = 1;
517
518 if (pdu->itt != itt) {
519 continue;
520 }
521
522 /* we have a special case with scsi-command opcodes,
523 * they are replied to by either a scsi-response
524 * or a data-in, or a combination of both.
525 */
526 if (opcode == ISCSI_PDU_DATA_IN
527 && expected_response == ISCSI_PDU_SCSI_RESPONSE) {
528 expected_response = ISCSI_PDU_DATA_IN;
529 }
530
531 /* Another special case is if we get a R2T.
532 * In this case we should find the original request and just send an additional
533 * DATAOUT segment for this task.
534 */
535 if (opcode == ISCSI_PDU_R2T) {
536 expected_response = ISCSI_PDU_R2T;
537 }
538
539 if (opcode != expected_response) {
540 iscsi_set_error(iscsi, "Got wrong opcode back for "
541 "itt:%d got:%d expected %d",
542 itt, opcode, pdu->response_opcode);
543 return -1;
544 }
545 switch (opcode) {
546 case ISCSI_PDU_LOGIN_RESPONSE:
547 if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
548 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
549 iscsi->drv->free_pdu(iscsi, pdu);
550 iscsi_set_error(iscsi, "iscsi login reply "
551 "failed");
552 return -1;
553 }
554 break;
555 case ISCSI_PDU_TEXT_RESPONSE:
556 if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
557 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
558 iscsi->drv->free_pdu(iscsi, pdu);
559 iscsi_set_error(iscsi, "iscsi text reply "
560 "failed");
561 return -1;
562 }
563 break;
564 case ISCSI_PDU_LOGOUT_RESPONSE:
565 if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
566 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
567 iscsi->drv->free_pdu(iscsi, pdu);
568 iscsi_set_error(iscsi, "iscsi logout reply "
569 "failed");
570 return -1;
571 }
572 break;
573 case ISCSI_PDU_SCSI_RESPONSE:
574 if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
575 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
576 iscsi->drv->free_pdu(iscsi, pdu);
577 iscsi_set_error(iscsi, "iscsi response reply "
578 "failed");
579 return -1;
580 }
581 break;
582 case ISCSI_PDU_DATA_IN:
583 if (iscsi_process_scsi_data_in(iscsi, pdu, in,
584 &is_finished) != 0) {
585 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
586 iscsi->drv->free_pdu(iscsi, pdu);
587 iscsi_set_error(iscsi, "iscsi data in "
588 "failed");
589 return -1;
590 }
591 break;
592 case ISCSI_PDU_NOP_IN:
593 if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
594 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
595 iscsi->drv->free_pdu(iscsi, pdu);
596 iscsi_set_error(iscsi, "iscsi nop-in failed");
597 return -1;
598 }
599 break;
600 case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
601 if (iscsi_process_task_mgmt_reply(iscsi, pdu,
602 in) != 0) {
603 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
604 iscsi->drv->free_pdu(iscsi, pdu);
605 iscsi_set_error(iscsi, "iscsi task-mgmt failed");
606 return -1;
607 }
608 break;
609 case ISCSI_PDU_R2T:
610 if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
611 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
612 iscsi->drv->free_pdu(iscsi, pdu);
613 iscsi_set_error(iscsi, "iscsi r2t "
614 "failed");
615 return -1;
616 }
617 is_finished = 0;
618 break;
619 default:
620 iscsi_set_error(iscsi, "Don't know how to handle "
621 "opcode 0x%02x", opcode);
622 return -1;
623 }
624
625 if (is_finished) {
626 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
627 iscsi->drv->free_pdu(iscsi, pdu);
628 }
629 return 0;
630 }
631
632 return 0;
633 }
634
635 void
iscsi_pdu_set_itt(struct iscsi_pdu * pdu,uint32_t itt)636 iscsi_pdu_set_itt(struct iscsi_pdu *pdu, uint32_t itt)
637 {
638 scsi_set_uint32(&pdu->outdata.data[16], itt);
639 }
640
641 void
iscsi_pdu_set_ritt(struct iscsi_pdu * pdu,uint32_t ritt)642 iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt)
643 {
644 scsi_set_uint32(&pdu->outdata.data[20], ritt);
645 }
646
647 void
iscsi_pdu_set_pduflags(struct iscsi_pdu * pdu,unsigned char flags)648 iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags)
649 {
650 pdu->outdata.data[1] = flags;
651 }
652
653 void
iscsi_pdu_set_immediate(struct iscsi_pdu * pdu)654 iscsi_pdu_set_immediate(struct iscsi_pdu *pdu)
655 {
656 pdu->outdata.data[0] |= ISCSI_PDU_IMMEDIATE;
657 }
658
659 void
iscsi_pdu_set_ttt(struct iscsi_pdu * pdu,uint32_t ttt)660 iscsi_pdu_set_ttt(struct iscsi_pdu *pdu, uint32_t ttt)
661 {
662 scsi_set_uint32(&pdu->outdata.data[20], ttt);
663 }
664
665 void
iscsi_pdu_set_cmdsn(struct iscsi_pdu * pdu,uint32_t cmdsn)666 iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn)
667 {
668 scsi_set_uint32(&pdu->outdata.data[24], cmdsn);
669 pdu->cmdsn = cmdsn;
670 }
671
672 void
iscsi_pdu_set_rcmdsn(struct iscsi_pdu * pdu,uint32_t rcmdsn)673 iscsi_pdu_set_rcmdsn(struct iscsi_pdu *pdu, uint32_t rcmdsn)
674 {
675 scsi_set_uint32(&pdu->outdata.data[32], rcmdsn);
676 }
677
678 void
iscsi_pdu_set_datasn(struct iscsi_pdu * pdu,uint32_t datasn)679 iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn)
680 {
681 scsi_set_uint32(&pdu->outdata.data[36], datasn);
682 }
683
684 void
iscsi_pdu_set_expstatsn(struct iscsi_pdu * pdu,uint32_t expstatsnsn)685 iscsi_pdu_set_expstatsn(struct iscsi_pdu *pdu, uint32_t expstatsnsn)
686 {
687 scsi_set_uint32(&pdu->outdata.data[28], expstatsnsn);
688 }
689
690 void
iscsi_pdu_set_bufferoffset(struct iscsi_pdu * pdu,uint32_t bufferoffset)691 iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset)
692 {
693 scsi_set_uint32(&pdu->outdata.data[40], bufferoffset);
694 }
695
696 void
iscsi_pdu_set_cdb(struct iscsi_pdu * pdu,struct scsi_task * task)697 iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task)
698 {
699 memset(&pdu->outdata.data[32], 0, 16);
700 memcpy(&pdu->outdata.data[32], task->cdb, task->cdb_size);
701 }
702
703 void
iscsi_pdu_set_lun(struct iscsi_pdu * pdu,uint32_t lun)704 iscsi_pdu_set_lun(struct iscsi_pdu *pdu, uint32_t lun)
705 {
706 scsi_set_uint16(&pdu->outdata.data[8], lun);
707 }
708
709 void
iscsi_pdu_set_expxferlen(struct iscsi_pdu * pdu,uint32_t expxferlen)710 iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen)
711 {
712 pdu->expxferlen = expxferlen;
713 scsi_set_uint32(&pdu->outdata.data[20], expxferlen);
714 }
715
716 void
iscsi_timeout_scan(struct iscsi_context * iscsi)717 iscsi_timeout_scan(struct iscsi_context *iscsi)
718 {
719 struct iscsi_pdu *pdu;
720 struct iscsi_pdu *next_pdu;
721 time_t t = time(NULL);
722
723 for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
724 next_pdu = pdu->next;
725
726 if (pdu->scsi_timeout == 0) {
727 /* no timeout for this pdu */
728 continue;
729 }
730 if (t < pdu->scsi_timeout) {
731 /* not expired yet */
732 continue;
733 }
734 ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
735 iscsi_set_error(iscsi, "command timed out");
736 iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
737 if (pdu->callback) {
738 pdu->callback(iscsi, SCSI_STATUS_TIMEOUT,
739 NULL, pdu->private_data);
740 }
741 iscsi->drv->free_pdu(iscsi, pdu);
742 }
743 for (pdu = iscsi->waitpdu; pdu; pdu = next_pdu) {
744 next_pdu = pdu->next;
745
746 if (pdu->scsi_timeout == 0) {
747 /* no timeout for this pdu */
748 continue;
749 }
750 if (t < pdu->scsi_timeout) {
751 /* not expired yet */
752 continue;
753 }
754 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
755 iscsi_set_error(iscsi, "command timed out");
756 iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
757 if (pdu->callback) {
758 pdu->callback(iscsi, SCSI_STATUS_TIMEOUT,
759 NULL, pdu->private_data);
760 }
761 iscsi->drv->free_pdu(iscsi, pdu);
762 }
763 }
764
765 int
iscsi_queue_pdu(struct iscsi_context * iscsi,struct iscsi_pdu * pdu)766 iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
767 {
768 return iscsi->drv->queue_pdu(iscsi, pdu);
769 }
770
771 void
iscsi_cancel_pdus(struct iscsi_context * iscsi)772 iscsi_cancel_pdus(struct iscsi_context *iscsi)
773 {
774 struct iscsi_pdu *pdu;
775
776 while ((pdu = iscsi->outqueue)) {
777 ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
778 if (iscsi->is_loggedin && pdu->callback) {
779 /* If an error happened during connect/login,
780 we don't want to call any of the callbacks.
781 */
782 pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
783 NULL, pdu->private_data);
784 }
785 iscsi->drv->free_pdu(iscsi, pdu);
786 }
787 while ((pdu = iscsi->waitpdu)) {
788 ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
789 if (iscsi->is_loggedin && pdu->callback) {
790 /* If an error happened during connect/login,
791 we don't want to call any of the callbacks.
792 */
793 pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
794 NULL, pdu->private_data);
795 }
796 iscsi->drv->free_pdu(iscsi, pdu);
797 }
798 }
799