2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
34 #include <ipxe/vsprintf.h>
35 #include <ipxe/socket.h>
36 #include <ipxe/iobuf.h>
38 #include <ipxe/xfer.h>
39 #include <ipxe/open.h>
40 #include <ipxe/scsi.h>
41 #include <ipxe/process.h>
42 #include <ipxe/uaccess.h>
43 #include <ipxe/tcpip.h>
44 #include <ipxe/settings.h>
45 #include <ipxe/features.h>
46 #include <ipxe/base16.h>
47 #include <ipxe/base64.h>
48 #include <ipxe/ibft.h>
49 #include <ipxe/iscsi.h>
57 FEATURE ( FEATURE_PROTOCOL
, "iSCSI", DHCP_EB_FEATURE_ISCSI
, 1 );
59 /* Disambiguate the various error causes */
60 #define EACCES_INCORRECT_TARGET_USERNAME \
61 __einfo_error ( EINFO_EACCES_INCORRECT_TARGET_USERNAME )
62 #define EINFO_EACCES_INCORRECT_TARGET_USERNAME \
63 __einfo_uniqify ( EINFO_EACCES, 0x01, "Incorrect target username" )
64 #define EACCES_INCORRECT_TARGET_PASSWORD \
65 __einfo_error ( EINFO_EACCES_INCORRECT_TARGET_PASSWORD )
66 #define EINFO_EACCES_INCORRECT_TARGET_PASSWORD \
67 __einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect target password" )
68 #define EINVAL_ROOT_PATH_TOO_SHORT \
69 __einfo_error ( EINFO_EINVAL_ROOT_PATH_TOO_SHORT )
70 #define EINFO_EINVAL_ROOT_PATH_TOO_SHORT \
71 __einfo_uniqify ( EINFO_EINVAL, 0x01, "Root path too short" )
72 #define EINVAL_BAD_CREDENTIAL_MIX \
73 __einfo_error ( EINFO_EINVAL_BAD_CREDENTIAL_MIX )
74 #define EINFO_EINVAL_BAD_CREDENTIAL_MIX \
75 __einfo_uniqify ( EINFO_EINVAL, 0x02, "Bad credential mix" )
76 #define EINVAL_NO_ROOT_PATH \
77 __einfo_error ( EINFO_EINVAL_NO_ROOT_PATH )
78 #define EINFO_EINVAL_NO_ROOT_PATH \
79 __einfo_uniqify ( EINFO_EINVAL, 0x03, "No root path" )
80 #define EINVAL_NO_TARGET_IQN \
81 __einfo_error ( EINFO_EINVAL_NO_TARGET_IQN )
82 #define EINFO_EINVAL_NO_TARGET_IQN \
83 __einfo_uniqify ( EINFO_EINVAL, 0x04, "No target IQN" )
84 #define EINVAL_NO_INITIATOR_IQN \
85 __einfo_error ( EINFO_EINVAL_NO_INITIATOR_IQN )
86 #define EINFO_EINVAL_NO_INITIATOR_IQN \
87 __einfo_uniqify ( EINFO_EINVAL, 0x05, "No initiator IQN" )
88 #define EIO_TARGET_UNAVAILABLE \
89 __einfo_error ( EINFO_EIO_TARGET_UNAVAILABLE )
90 #define EINFO_EIO_TARGET_UNAVAILABLE \
91 __einfo_uniqify ( EINFO_EIO, 0x01, "Target not currently operational" )
92 #define EIO_TARGET_NO_RESOURCES \
93 __einfo_error ( EINFO_EIO_TARGET_NO_RESOURCES )
94 #define EINFO_EIO_TARGET_NO_RESOURCES \
95 __einfo_uniqify ( EINFO_EIO, 0x02, "Target out of resources" )
96 #define ENOTSUP_INITIATOR_STATUS \
97 __einfo_error ( EINFO_ENOTSUP_INITIATOR_STATUS )
98 #define EINFO_ENOTSUP_INITIATOR_STATUS \
99 __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported initiator status" )
100 #define ENOTSUP_OPCODE \
101 __einfo_error ( EINFO_ENOTSUP_OPCODE )
102 #define EINFO_ENOTSUP_OPCODE \
103 __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported opcode" )
104 #define ENOTSUP_DISCOVERY \
105 __einfo_error ( EINFO_ENOTSUP_DISCOVERY )
106 #define EINFO_ENOTSUP_DISCOVERY \
107 __einfo_uniqify ( EINFO_ENOTSUP, 0x03, "Discovery not supported" )
108 #define ENOTSUP_TARGET_STATUS \
109 __einfo_error ( EINFO_ENOTSUP_TARGET_STATUS )
110 #define EINFO_ENOTSUP_TARGET_STATUS \
111 __einfo_uniqify ( EINFO_ENOTSUP, 0x04, "Unsupported target status" )
112 #define EPERM_INITIATOR_AUTHENTICATION \
113 __einfo_error ( EINFO_EPERM_INITIATOR_AUTHENTICATION )
114 #define EINFO_EPERM_INITIATOR_AUTHENTICATION \
115 __einfo_uniqify ( EINFO_EPERM, 0x01, "Initiator authentication failed" )
116 #define EPERM_INITIATOR_AUTHORISATION \
117 __einfo_error ( EINFO_EPERM_INITIATOR_AUTHORISATION )
118 #define EINFO_EPERM_INITIATOR_AUTHORISATION \
119 __einfo_uniqify ( EINFO_EPERM, 0x02, "Initiator not authorised" )
120 #define EPROTO_INVALID_CHAP_ALGORITHM \
121 __einfo_error ( EINFO_EPROTO_INVALID_CHAP_ALGORITHM )
122 #define EINFO_EPROTO_INVALID_CHAP_ALGORITHM \
123 __einfo_uniqify ( EINFO_EPROTO, 0x01, "Invalid CHAP algorithm" )
124 #define EPROTO_INVALID_CHAP_IDENTIFIER \
125 __einfo_error ( EINFO_EPROTO_INVALID_CHAP_IDENTIFIER )
126 #define EINFO_EPROTO_INVALID_CHAP_IDENTIFIER \
127 __einfo_uniqify ( EINFO_EPROTO, 0x02, "Invalid CHAP identifier" )
128 #define EPROTO_INVALID_LARGE_BINARY \
129 __einfo_error ( EINFO_EPROTO_INVALID_LARGE_BINARY )
130 #define EINFO_EPROTO_INVALID_LARGE_BINARY \
131 __einfo_uniqify ( EINFO_EPROTO, 0x03, "Invalid large binary value" )
132 #define EPROTO_INVALID_CHAP_RESPONSE \
133 __einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
134 #define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
135 __einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
136 #define EPROTO_INVALID_KEY_VALUE_PAIR \
137 __einfo_error ( EINFO_EPROTO_INVALID_KEY_VALUE_PAIR )
138 #define EINFO_EPROTO_INVALID_KEY_VALUE_PAIR \
139 __einfo_uniqify ( EINFO_EPROTO, 0x05, "Invalid key/value pair" )
140 #define EPROTO_VALUE_REJECTED \
141 __einfo_error ( EINFO_EPROTO_VALUE_REJECTED )
142 #define EINFO_EPROTO_VALUE_REJECTED \
143 __einfo_uniqify ( EINFO_EPROTO, 0x06, "Parameter rejected" )
145 static void iscsi_start_tx ( struct iscsi_session
*iscsi
);
146 static void iscsi_start_login ( struct iscsi_session
*iscsi
);
147 static void iscsi_start_data_out ( struct iscsi_session
*iscsi
,
148 unsigned int datasn
);
151 * Finish receiving PDU data into buffer
153 * @v iscsi iSCSI session
155 static void iscsi_rx_buffered_data_done ( struct iscsi_session
*iscsi
) {
156 free ( iscsi
->rx_buffer
);
157 iscsi
->rx_buffer
= NULL
;
161 * Receive PDU data into buffer
163 * @v iscsi iSCSI session
164 * @v data Data to receive
165 * @v len Length of data
166 * @ret rc Return status code
168 * This can be used when the RX PDU type handler wishes to buffer up
169 * all received data and process the PDU as a single unit. The caller
170 * is repsonsible for calling iscsi_rx_buffered_data_done() after
171 * processing the data.
173 static int iscsi_rx_buffered_data ( struct iscsi_session
*iscsi
,
174 const void *data
, size_t len
) {
176 /* Allocate buffer on first call */
177 if ( ! iscsi
->rx_buffer
) {
178 iscsi
->rx_buffer
= malloc ( iscsi
->rx_len
);
179 if ( ! iscsi
->rx_buffer
)
183 /* Copy data to buffer */
184 assert ( ( iscsi
->rx_offset
+ len
) <= iscsi
->rx_len
);
185 memcpy ( ( iscsi
->rx_buffer
+ iscsi
->rx_offset
), data
, len
);
193 * @v refcnt Reference counter
195 static void iscsi_free ( struct refcnt
*refcnt
) {
196 struct iscsi_session
*iscsi
=
197 container_of ( refcnt
, struct iscsi_session
, refcnt
);
199 free ( iscsi
->initiator_iqn
);
200 free ( iscsi
->target_address
);
201 free ( iscsi
->target_iqn
);
202 free ( iscsi
->initiator_username
);
203 free ( iscsi
->initiator_password
);
204 free ( iscsi
->target_username
);
205 free ( iscsi
->target_password
);
206 chap_finish ( &iscsi
->chap
);
207 iscsi_rx_buffered_data_done ( iscsi
);
208 free ( iscsi
->command
);
213 * Shut down iSCSI interface
215 * @v iscsi iSCSI session
216 * @v rc Reason for close
218 static void iscsi_close ( struct iscsi_session
*iscsi
, int rc
) {
220 /* A TCP graceful close is still an error from our point of view */
224 DBGC ( iscsi
, "iSCSI %p closed: %s\n", iscsi
, strerror ( rc
) );
226 /* Stop transmission process */
227 process_del ( &iscsi
->process
);
229 /* Shut down interfaces */
230 intfs_shutdown ( rc
, &iscsi
->socket
, &iscsi
->control
, &iscsi
->data
,
235 * Assign new iSCSI initiator task tag
237 * @v iscsi iSCSI session
239 static void iscsi_new_itt ( struct iscsi_session
*iscsi
) {
240 static uint16_t itt_idx
;
242 iscsi
->itt
= ( ISCSI_TAG_MAGIC
| (++itt_idx
) );
246 * Open iSCSI transport-layer connection
248 * @v iscsi iSCSI session
249 * @ret rc Return status code
251 static int iscsi_open_connection ( struct iscsi_session
*iscsi
) {
252 struct sockaddr_tcpip target
;
255 assert ( iscsi
->tx_state
== ISCSI_TX_IDLE
);
256 assert ( iscsi
->rx_state
== ISCSI_RX_BHS
);
257 assert ( iscsi
->rx_offset
== 0 );
260 memset ( &target
, 0, sizeof ( target
) );
261 target
.st_port
= htons ( iscsi
->target_port
);
262 if ( ( rc
= xfer_open_named_socket ( &iscsi
->socket
, SOCK_STREAM
,
263 ( struct sockaddr
* ) &target
,
264 iscsi
->target_address
,
266 DBGC ( iscsi
, "iSCSI %p could not open socket: %s\n",
267 iscsi
, strerror ( rc
) );
271 /* Enter security negotiation phase */
272 iscsi
->status
= ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE
|
273 ISCSI_STATUS_STRINGS_SECURITY
);
274 if ( iscsi
->target_username
)
275 iscsi
->status
|= ISCSI_STATUS_AUTH_REVERSE_REQUIRED
;
277 /* Assign new ISID */
278 iscsi
->isid_iana_qual
= ( random() & 0xffff );
280 /* Assign fresh initiator task tag */
281 iscsi_new_itt ( iscsi
);
284 iscsi_start_login ( iscsi
);
290 * Close iSCSI transport-layer connection
292 * @v iscsi iSCSI session
293 * @v rc Reason for close
295 * Closes the transport-layer connection and resets the session state
296 * ready to attempt a fresh login.
298 static void iscsi_close_connection ( struct iscsi_session
*iscsi
, int rc
) {
300 /* Close all data transfer interfaces */
301 intf_restart ( &iscsi
->socket
, rc
);
303 /* Clear connection status */
306 /* Reset TX and RX state machines */
307 iscsi
->tx_state
= ISCSI_TX_IDLE
;
308 iscsi
->rx_state
= ISCSI_RX_BHS
;
309 iscsi
->rx_offset
= 0;
311 /* Free any temporary dynamically allocated memory */
312 chap_finish ( &iscsi
->chap
);
313 iscsi_rx_buffered_data_done ( iscsi
);
317 * Mark iSCSI SCSI operation as complete
319 * @v iscsi iSCSI session
320 * @v rc Return status code
321 * @v rsp SCSI response, if any
323 * Note that iscsi_scsi_done() will not close the connection, and must
324 * therefore be called only when the internal state machines are in an
325 * appropriate state, otherwise bad things may happen on the next call
326 * to iscsi_scsi_command(). The general rule is to call
327 * iscsi_scsi_done() only at the end of receiving a PDU; at this point
328 * the TX and RX engines should both be idle.
330 static void iscsi_scsi_done ( struct iscsi_session
*iscsi
, int rc
,
331 struct scsi_rsp
*rsp
) {
332 uint32_t itt
= iscsi
->itt
;
334 assert ( iscsi
->tx_state
== ISCSI_TX_IDLE
);
337 free ( iscsi
->command
);
338 iscsi
->command
= NULL
;
340 /* Send SCSI response, if any */
342 scsi_response ( &iscsi
->data
, rsp
);
344 /* Close SCSI command, if this is still the same command. (It
345 * is possible that the command interface has already been
346 * closed as a result of the SCSI response we sent.)
348 if ( iscsi
->itt
== itt
)
349 intf_restart ( &iscsi
->data
, rc
);
352 /****************************************************************************
354 * iSCSI SCSI command issuing
359 * Build iSCSI SCSI command BHS
361 * @v iscsi iSCSI session
363 * We don't currently support bidirectional commands (i.e. with both
364 * Data-In and Data-Out segments); these would require providing code
365 * to generate an AHS, and there doesn't seem to be any need for it at
368 static void iscsi_start_command ( struct iscsi_session
*iscsi
) {
369 struct iscsi_bhs_scsi_command
*command
= &iscsi
->tx_bhs
.scsi_command
;
371 assert ( ! ( iscsi
->command
->data_in
&& iscsi
->command
->data_out
) );
373 /* Construct BHS and initiate transmission */
374 iscsi_start_tx ( iscsi
);
375 command
->opcode
= ISCSI_OPCODE_SCSI_COMMAND
;
376 command
->flags
= ( ISCSI_FLAG_FINAL
|
377 ISCSI_COMMAND_ATTR_SIMPLE
);
378 if ( iscsi
->command
->data_in
)
379 command
->flags
|= ISCSI_COMMAND_FLAG_READ
;
380 if ( iscsi
->command
->data_out
)
381 command
->flags
|= ISCSI_COMMAND_FLAG_WRITE
;
382 /* lengths left as zero */
383 memcpy ( &command
->lun
, &iscsi
->command
->lun
,
384 sizeof ( command
->lun
) );
385 command
->itt
= htonl ( iscsi
->itt
);
386 command
->exp_len
= htonl ( iscsi
->command
->data_in_len
|
387 iscsi
->command
->data_out_len
);
388 command
->cmdsn
= htonl ( iscsi
->cmdsn
);
389 command
->expstatsn
= htonl ( iscsi
->statsn
+ 1 );
390 memcpy ( &command
->cdb
, &iscsi
->command
->cdb
, sizeof ( command
->cdb
));
391 DBGC2 ( iscsi
, "iSCSI %p start " SCSI_CDB_FORMAT
" %s %#zx\n",
392 iscsi
, SCSI_CDB_DATA ( command
->cdb
),
393 ( iscsi
->command
->data_in
? "in" : "out" ),
394 ( iscsi
->command
->data_in
?
395 iscsi
->command
->data_in_len
:
396 iscsi
->command
->data_out_len
) );
400 * Receive data segment of an iSCSI SCSI response PDU
402 * @v iscsi iSCSI session
403 * @v data Received data
404 * @v len Length of received data
405 * @v remaining Data remaining after this data
406 * @ret rc Return status code
408 static int iscsi_rx_scsi_response ( struct iscsi_session
*iscsi
,
409 const void *data
, size_t len
,
411 struct iscsi_bhs_scsi_response
*response
412 = &iscsi
->rx_bhs
.scsi_response
;
414 uint32_t residual_count
;
418 /* Buffer up the PDU data */
419 if ( ( rc
= iscsi_rx_buffered_data ( iscsi
, data
, len
) ) != 0 ) {
420 DBGC ( iscsi
, "iSCSI %p could not buffer SCSI response: %s\n",
421 iscsi
, strerror ( rc
) );
427 /* Parse SCSI response and discard buffer */
428 memset ( &rsp
, 0, sizeof ( rsp
) );
429 rsp
.status
= response
->status
;
430 residual_count
= ntohl ( response
->residual_count
);
431 if ( response
->flags
& ISCSI_DATA_FLAG_OVERFLOW
) {
432 rsp
.overrun
= residual_count
;
433 } else if ( response
->flags
& ISCSI_DATA_FLAG_UNDERFLOW
) {
434 rsp
.overrun
= -(residual_count
);
436 data_len
= ISCSI_DATA_LEN ( response
->lengths
);
438 scsi_parse_sense ( ( iscsi
->rx_buffer
+ 2 ), ( data_len
- 2 ),
441 iscsi_rx_buffered_data_done ( iscsi
);
443 /* Check for errors */
444 if ( response
->response
!= ISCSI_RESPONSE_COMMAND_COMPLETE
)
447 /* Mark as completed */
448 iscsi_scsi_done ( iscsi
, 0, &rsp
);
453 * Receive data segment of an iSCSI data-in PDU
455 * @v iscsi iSCSI session
456 * @v data Received data
457 * @v len Length of received data
458 * @v remaining Data remaining after this data
459 * @ret rc Return status code
461 static int iscsi_rx_data_in ( struct iscsi_session
*iscsi
,
462 const void *data
, size_t len
,
464 struct iscsi_bhs_data_in
*data_in
= &iscsi
->rx_bhs
.data_in
;
465 unsigned long offset
;
467 /* Copy data to data-in buffer */
468 offset
= ntohl ( data_in
->offset
) + iscsi
->rx_offset
;
469 assert ( iscsi
->command
!= NULL
);
470 assert ( iscsi
->command
->data_in
);
471 assert ( ( offset
+ len
) <= iscsi
->command
->data_in_len
);
472 copy_to_user ( iscsi
->command
->data_in
, offset
, data
, len
);
474 /* Wait for whole SCSI response to arrive */
478 /* Mark as completed if status is present */
479 if ( data_in
->flags
& ISCSI_DATA_FLAG_STATUS
) {
480 assert ( ( offset
+ len
) == iscsi
->command
->data_in_len
);
481 assert ( data_in
->flags
& ISCSI_FLAG_FINAL
);
482 /* iSCSI cannot return an error status via a data-in */
483 iscsi_scsi_done ( iscsi
, 0, NULL
);
490 * Receive data segment of an iSCSI R2T PDU
492 * @v iscsi iSCSI session
493 * @v data Received data
494 * @v len Length of received data
495 * @v remaining Data remaining after this data
496 * @ret rc Return status code
498 static int iscsi_rx_r2t ( struct iscsi_session
*iscsi
,
499 const void *data __unused
, size_t len __unused
,
500 size_t remaining __unused
) {
501 struct iscsi_bhs_r2t
*r2t
= &iscsi
->rx_bhs
.r2t
;
503 /* Record transfer parameters and trigger first data-out */
504 iscsi
->ttt
= ntohl ( r2t
->ttt
);
505 iscsi
->transfer_offset
= ntohl ( r2t
->offset
);
506 iscsi
->transfer_len
= ntohl ( r2t
->len
);
507 iscsi_start_data_out ( iscsi
, 0 );
513 * Build iSCSI data-out BHS
515 * @v iscsi iSCSI session
516 * @v datasn Data sequence number within the transfer
519 static void iscsi_start_data_out ( struct iscsi_session
*iscsi
,
520 unsigned int datasn
) {
521 struct iscsi_bhs_data_out
*data_out
= &iscsi
->tx_bhs
.data_out
;
522 unsigned long offset
;
523 unsigned long remaining
;
526 /* We always send 512-byte Data-Out PDUs; this removes the
527 * need to worry about the target's MaxRecvDataSegmentLength.
529 offset
= datasn
* 512;
530 remaining
= iscsi
->transfer_len
- offset
;
535 /* Construct BHS and initiate transmission */
536 iscsi_start_tx ( iscsi
);
537 data_out
->opcode
= ISCSI_OPCODE_DATA_OUT
;
538 if ( len
== remaining
)
539 data_out
->flags
= ( ISCSI_FLAG_FINAL
);
540 ISCSI_SET_LENGTHS ( data_out
->lengths
, 0, len
);
541 data_out
->lun
= iscsi
->command
->lun
;
542 data_out
->itt
= htonl ( iscsi
->itt
);
543 data_out
->ttt
= htonl ( iscsi
->ttt
);
544 data_out
->expstatsn
= htonl ( iscsi
->statsn
+ 1 );
545 data_out
->datasn
= htonl ( datasn
);
546 data_out
->offset
= htonl ( iscsi
->transfer_offset
+ offset
);
547 DBGC ( iscsi
, "iSCSI %p start data out DataSN %#x len %#lx\n",
548 iscsi
, datasn
, len
);
552 * Complete iSCSI data-out PDU transmission
554 * @v iscsi iSCSI session
557 static void iscsi_data_out_done ( struct iscsi_session
*iscsi
) {
558 struct iscsi_bhs_data_out
*data_out
= &iscsi
->tx_bhs
.data_out
;
560 /* If we haven't reached the end of the sequence, start
561 * sending the next data-out PDU.
563 if ( ! ( data_out
->flags
& ISCSI_FLAG_FINAL
) )
564 iscsi_start_data_out ( iscsi
, ntohl ( data_out
->datasn
) + 1 );
568 * Send iSCSI data-out data segment
570 * @v iscsi iSCSI session
571 * @ret rc Return status code
573 static int iscsi_tx_data_out ( struct iscsi_session
*iscsi
) {
574 struct iscsi_bhs_data_out
*data_out
= &iscsi
->tx_bhs
.data_out
;
575 struct io_buffer
*iobuf
;
576 unsigned long offset
;
580 offset
= ntohl ( data_out
->offset
);
581 len
= ISCSI_DATA_LEN ( data_out
->lengths
);
582 pad_len
= ISCSI_DATA_PAD_LEN ( data_out
->lengths
);
584 assert ( iscsi
->command
!= NULL
);
585 assert ( iscsi
->command
->data_out
);
586 assert ( ( offset
+ len
) <= iscsi
->command
->data_out_len
);
588 iobuf
= xfer_alloc_iob ( &iscsi
->socket
, ( len
+ pad_len
) );
592 copy_from_user ( iob_put ( iobuf
, len
),
593 iscsi
->command
->data_out
, offset
, len
);
594 memset ( iob_put ( iobuf
, pad_len
), 0, pad_len
);
596 return xfer_deliver_iob ( &iscsi
->socket
, iobuf
);
600 * Receive data segment of an iSCSI NOP-In
602 * @v iscsi iSCSI session
603 * @v data Received data
604 * @v len Length of received data
605 * @v remaining Data remaining after this data
606 * @ret rc Return status code
608 static int iscsi_rx_nop_in ( struct iscsi_session
*iscsi
,
609 const void *data __unused
, size_t len __unused
,
610 size_t remaining __unused
) {
611 struct iscsi_nop_in
*nop_in
= &iscsi
->rx_bhs
.nop_in
;
613 DBGC2 ( iscsi
, "iSCSI %p received NOP-In\n", iscsi
);
615 /* We don't currently have the ability to respond to NOP-Ins
616 * sent as ping requests, but we can happily accept NOP-Ins
617 * sent merely to update CmdSN.
619 if ( nop_in
->ttt
== htonl ( ISCSI_TAG_RESERVED
) )
622 /* Ignore any other NOP-Ins. The target may eventually
623 * disconnect us for failing to respond, but this minimises
624 * unnecessary connection closures.
626 DBGC ( iscsi
, "iSCSI %p received unsupported NOP-In with TTT %08x\n",
627 iscsi
, ntohl ( nop_in
->ttt
) );
631 /****************************************************************************
638 * Build iSCSI login request strings
640 * @v iscsi iSCSI session
642 * These are the initial set of strings sent in the first login
643 * request PDU. We want the following settings:
647 * MaxConnections=1 (irrelevant; we make only one connection anyway) [4]
649 * ImmediateData=No (irrelevant; we never send immediate data) [4]
650 * MaxRecvDataSegmentLength=8192 (default; we don't care) [3]
651 * MaxBurstLength=262144 (default; we don't care) [3]
652 * FirstBurstLength=65536 (irrelevant due to other settings) [5]
653 * DefaultTime2Wait=0 [2]
654 * DefaultTime2Retain=0 [2]
655 * MaxOutstandingR2T=1
657 * DataSequenceInOrder=Yes
658 * ErrorRecoveryLevel=0
660 * [1] InitialR2T has an OR resolution function, so the target may
661 * force us to use it. We therefore simplify our logic by always
664 * [2] These ensure that we can safely start a new task once we have
665 * reconnected after a failure, without having to manually tidy up
668 * [3] We are quite happy to use the RFC-defined default values for
669 * these parameters, but some targets (notably OpenSolaris)
670 * incorrectly assume a default value of zero, so we explicitly
671 * specify the default values.
673 * [4] We are quite happy to use the RFC-defined default values for
674 * these parameters, but some targets (notably a QNAP TS-639Pro) fail
675 * unless they are supplied, so we explicitly specify the default
678 * [5] FirstBurstLength is defined to be irrelevant since we already
679 * force InitialR2T=Yes and ImmediateData=No, but some targets
680 * (notably LIO as of kernel 4.11) fail unless it is specified, so we
681 * explicitly specify the default value.
683 static int iscsi_build_login_request_strings ( struct iscsi_session
*iscsi
,
684 void *data
, size_t len
) {
685 unsigned int used
= 0;
686 const char *auth_method
;
688 if ( iscsi
->status
& ISCSI_STATUS_STRINGS_SECURITY
) {
689 /* Default to allowing no authentication */
690 auth_method
= "None";
691 /* If we have a credential to supply, permit CHAP */
692 if ( iscsi
->initiator_username
)
693 auth_method
= "CHAP,None";
694 /* If we have a credential to check, force CHAP */
695 if ( iscsi
->target_username
)
696 auth_method
= "CHAP";
697 used
+= ssnprintf ( data
+ used
, len
- used
,
700 "SessionType=Normal%c"
702 iscsi
->initiator_iqn
, 0,
703 iscsi
->target_iqn
, 0, 0,
707 if ( iscsi
->status
& ISCSI_STATUS_STRINGS_CHAP_ALGORITHM
) {
708 used
+= ssnprintf ( data
+ used
, len
- used
, "CHAP_A=5%c", 0 );
711 if ( ( iscsi
->status
& ISCSI_STATUS_STRINGS_CHAP_RESPONSE
) ) {
712 char buf
[ base16_encoded_len ( iscsi
->chap
.response_len
) + 1 ];
713 assert ( iscsi
->initiator_username
!= NULL
);
714 base16_encode ( iscsi
->chap
.response
, iscsi
->chap
.response_len
,
715 buf
, sizeof ( buf
) );
716 used
+= ssnprintf ( data
+ used
, len
- used
,
717 "CHAP_N=%s%cCHAP_R=0x%s%c",
718 iscsi
->initiator_username
, 0, buf
, 0 );
721 if ( ( iscsi
->status
& ISCSI_STATUS_STRINGS_CHAP_CHALLENGE
) ) {
722 size_t challenge_len
= ( sizeof ( iscsi
->chap_challenge
) - 1 );
723 char buf
[ base16_encoded_len ( challenge_len
) + 1 ];
724 base16_encode ( ( iscsi
->chap_challenge
+ 1 ), challenge_len
,
725 buf
, sizeof ( buf
) );
726 used
+= ssnprintf ( data
+ used
, len
- used
,
727 "CHAP_I=%d%cCHAP_C=0x%s%c",
728 iscsi
->chap_challenge
[0], 0, buf
, 0 );
731 if ( iscsi
->status
& ISCSI_STATUS_STRINGS_OPERATIONAL
) {
732 used
+= ssnprintf ( data
+ used
, len
- used
,
733 "HeaderDigest=None%c"
738 "MaxRecvDataSegmentLength=8192%c"
739 "MaxBurstLength=262144%c"
740 "FirstBurstLength=65536%c"
741 "DefaultTime2Wait=0%c"
742 "DefaultTime2Retain=0%c"
743 "MaxOutstandingR2T=1%c"
744 "DataPDUInOrder=Yes%c"
745 "DataSequenceInOrder=Yes%c"
746 "ErrorRecoveryLevel=0%c",
747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
754 * Build iSCSI login request BHS
756 * @v iscsi iSCSI session
758 static void iscsi_start_login ( struct iscsi_session
*iscsi
) {
759 struct iscsi_bhs_login_request
*request
= &iscsi
->tx_bhs
.login_request
;
762 switch ( iscsi
->status
& ISCSI_LOGIN_CSG_MASK
) {
763 case ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION
:
764 DBGC ( iscsi
, "iSCSI %p entering security negotiation\n",
767 case ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION
:
768 DBGC ( iscsi
, "iSCSI %p entering operational negotiation\n",
775 /* Construct BHS and initiate transmission */
776 iscsi_start_tx ( iscsi
);
777 request
->opcode
= ( ISCSI_OPCODE_LOGIN_REQUEST
|
778 ISCSI_FLAG_IMMEDIATE
);
779 request
->flags
= ( ( iscsi
->status
& ISCSI_STATUS_PHASE_MASK
) |
780 ISCSI_LOGIN_FLAG_TRANSITION
);
781 /* version_max and version_min left as zero */
782 len
= iscsi_build_login_request_strings ( iscsi
, NULL
, 0 );
783 ISCSI_SET_LENGTHS ( request
->lengths
, 0, len
);
784 request
->isid_iana_en
= htonl ( ISCSI_ISID_IANA
|
785 IANA_EN_FEN_SYSTEMS
);
786 request
->isid_iana_qual
= htons ( iscsi
->isid_iana_qual
);
787 /* tsih left as zero */
788 request
->itt
= htonl ( iscsi
->itt
);
789 /* cid left as zero */
790 request
->cmdsn
= htonl ( iscsi
->cmdsn
);
791 request
->expstatsn
= htonl ( iscsi
->statsn
+ 1 );
795 * Complete iSCSI login request PDU transmission
797 * @v iscsi iSCSI session
800 static void iscsi_login_request_done ( struct iscsi_session
*iscsi
) {
802 /* Clear any "strings to send" flags */
803 iscsi
->status
&= ~ISCSI_STATUS_STRINGS_MASK
;
805 /* Free any dynamically allocated storage used for login */
806 chap_finish ( &iscsi
->chap
);
810 * Transmit data segment of an iSCSI login request PDU
812 * @v iscsi iSCSI session
813 * @ret rc Return status code
815 * For login requests, the data segment consists of the login strings.
817 static int iscsi_tx_login_request ( struct iscsi_session
*iscsi
) {
818 struct iscsi_bhs_login_request
*request
= &iscsi
->tx_bhs
.login_request
;
819 struct io_buffer
*iobuf
;
823 len
= ISCSI_DATA_LEN ( request
->lengths
);
824 pad_len
= ISCSI_DATA_PAD_LEN ( request
->lengths
);
825 iobuf
= xfer_alloc_iob ( &iscsi
->socket
, ( len
+ pad_len
) );
828 iob_put ( iobuf
, len
);
829 iscsi_build_login_request_strings ( iscsi
, iobuf
->data
, len
);
830 memset ( iob_put ( iobuf
, pad_len
), 0, pad_len
);
832 return xfer_deliver_iob ( &iscsi
->socket
, iobuf
);
836 * Decode large binary value
838 * @v encoded Encoded large binary value
840 * @v len Length of data buffer
841 * @ret len Length of raw data, or negative error
843 static int iscsi_large_binary_decode ( const char *encoded
, uint8_t *raw
,
846 /* Check for initial '0x' or '0b' and decode as appropriate */
847 if ( *(encoded
++) == '0' ) {
848 switch ( tolower ( *(encoded
++) ) ) {
850 return base16_decode ( encoded
, raw
, len
);
852 return base64_decode ( encoded
, raw
, len
);
856 return -EPROTO_INVALID_LARGE_BINARY
;
860 * Handle iSCSI TargetAddress text value
862 * @v iscsi iSCSI session
863 * @v value TargetAddress value
864 * @ret rc Return status code
866 static int iscsi_handle_targetaddress_value ( struct iscsi_session
*iscsi
,
867 const char *value
) {
870 DBGC ( iscsi
, "iSCSI %p will redirect to %s\n", iscsi
, value
);
872 /* Replace target address */
873 free ( iscsi
->target_address
);
874 iscsi
->target_address
= strdup ( value
);
875 if ( ! iscsi
->target_address
)
878 /* Replace target port */
879 iscsi
->target_port
= htons ( ISCSI_PORT
);
880 separator
= strchr ( iscsi
->target_address
, ':' );
883 iscsi
->target_port
= strtoul ( ( separator
+ 1 ), NULL
, 0 );
890 * Handle iSCSI AuthMethod text value
892 * @v iscsi iSCSI session
893 * @v value AuthMethod value
894 * @ret rc Return status code
896 static int iscsi_handle_authmethod_value ( struct iscsi_session
*iscsi
,
897 const char *value
) {
899 /* If server requests CHAP, send the CHAP_A string */
900 if ( strcmp ( value
, "CHAP" ) == 0 ) {
901 DBGC ( iscsi
, "iSCSI %p initiating CHAP authentication\n",
903 iscsi
->status
|= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM
|
904 ISCSI_STATUS_AUTH_FORWARD_REQUIRED
);
911 * Handle iSCSI CHAP_A text value
913 * @v iscsi iSCSI session
914 * @v value CHAP_A value
915 * @ret rc Return status code
917 static int iscsi_handle_chap_a_value ( struct iscsi_session
*iscsi
,
918 const char *value
) {
920 /* We only ever offer "5" (i.e. MD5) as an algorithm, so if
921 * the server responds with anything else it is a protocol
924 if ( strcmp ( value
, "5" ) != 0 ) {
925 DBGC ( iscsi
, "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
927 return -EPROTO_INVALID_CHAP_ALGORITHM
;
934 * Handle iSCSI CHAP_I text value
936 * @v iscsi iSCSI session
937 * @v value CHAP_I value
938 * @ret rc Return status code
940 static int iscsi_handle_chap_i_value ( struct iscsi_session
*iscsi
,
941 const char *value
) {
942 unsigned int identifier
;
946 /* The CHAP identifier is an integer value */
947 identifier
= strtoul ( value
, &endp
, 0 );
948 if ( *endp
!= '\0' ) {
949 DBGC ( iscsi
, "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
951 return -EPROTO_INVALID_CHAP_IDENTIFIER
;
954 /* Prepare for CHAP with MD5 */
955 chap_finish ( &iscsi
->chap
);
956 if ( ( rc
= chap_init ( &iscsi
->chap
, &md5_algorithm
) ) != 0 ) {
957 DBGC ( iscsi
, "iSCSI %p could not initialise CHAP: %s\n",
958 iscsi
, strerror ( rc
) );
962 /* Identifier and secret are the first two components of the
965 chap_set_identifier ( &iscsi
->chap
, identifier
);
966 if ( iscsi
->initiator_password
) {
967 chap_update ( &iscsi
->chap
, iscsi
->initiator_password
,
968 strlen ( iscsi
->initiator_password
) );
975 * Handle iSCSI CHAP_C text value
977 * @v iscsi iSCSI session
978 * @v value CHAP_C value
979 * @ret rc Return status code
981 static int iscsi_handle_chap_c_value ( struct iscsi_session
*iscsi
,
982 const char *value
) {
983 uint8_t buf
[ strlen ( value
) ]; /* Decoding never expands data */
988 /* Process challenge */
989 len
= iscsi_large_binary_decode ( value
, buf
, sizeof ( buf
) );
992 DBGC ( iscsi
, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
993 iscsi
, value
, strerror ( rc
) );
996 chap_update ( &iscsi
->chap
, buf
, len
);
998 /* Build CHAP response */
999 DBGC ( iscsi
, "iSCSI %p sending CHAP response\n", iscsi
);
1000 chap_respond ( &iscsi
->chap
);
1001 iscsi
->status
|= ISCSI_STATUS_STRINGS_CHAP_RESPONSE
;
1003 /* Send CHAP challenge, if applicable */
1004 if ( iscsi
->target_username
) {
1005 iscsi
->status
|= ISCSI_STATUS_STRINGS_CHAP_CHALLENGE
;
1006 /* Generate CHAP challenge data */
1007 for ( i
= 0 ; i
< sizeof ( iscsi
->chap_challenge
) ; i
++ ) {
1008 iscsi
->chap_challenge
[i
] = random();
1016 * Handle iSCSI CHAP_N text value
1018 * @v iscsi iSCSI session
1019 * @v value CHAP_N value
1020 * @ret rc Return status code
1022 static int iscsi_handle_chap_n_value ( struct iscsi_session
*iscsi
,
1023 const char *value
) {
1025 /* The target username isn't actually involved at any point in
1026 * the authentication process; it merely serves to identify
1027 * which password the target is using to generate the CHAP
1028 * response. We unnecessarily verify that the username is as
1029 * expected, in order to provide mildly helpful diagnostics if
1030 * the target is supplying the wrong username/password
1033 if ( iscsi
->target_username
&&
1034 ( strcmp ( iscsi
->target_username
, value
) != 0 ) ) {
1035 DBGC ( iscsi
, "iSCSI %p target username \"%s\" incorrect "
1036 "(wanted \"%s\")\n",
1037 iscsi
, value
, iscsi
->target_username
);
1038 return -EACCES_INCORRECT_TARGET_USERNAME
;
1045 * Handle iSCSI CHAP_R text value
1047 * @v iscsi iSCSI session
1048 * @v value CHAP_R value
1049 * @ret rc Return status code
1051 static int iscsi_handle_chap_r_value ( struct iscsi_session
*iscsi
,
1052 const char *value
) {
1053 uint8_t buf
[ strlen ( value
) ]; /* Decoding never expands data */
1057 /* Generate CHAP response for verification */
1058 chap_finish ( &iscsi
->chap
);
1059 if ( ( rc
= chap_init ( &iscsi
->chap
, &md5_algorithm
) ) != 0 ) {
1060 DBGC ( iscsi
, "iSCSI %p could not initialise CHAP: %s\n",
1061 iscsi
, strerror ( rc
) );
1064 chap_set_identifier ( &iscsi
->chap
, iscsi
->chap_challenge
[0] );
1065 if ( iscsi
->target_password
) {
1066 chap_update ( &iscsi
->chap
, iscsi
->target_password
,
1067 strlen ( iscsi
->target_password
) );
1069 chap_update ( &iscsi
->chap
, &iscsi
->chap_challenge
[1],
1070 ( sizeof ( iscsi
->chap_challenge
) - 1 ) );
1071 chap_respond ( &iscsi
->chap
);
1073 /* Process response */
1074 len
= iscsi_large_binary_decode ( value
, buf
, sizeof ( buf
) );
1077 DBGC ( iscsi
, "iSCSI %p invalid CHAP response \"%s\": %s\n",
1078 iscsi
, value
, strerror ( rc
) );
1082 /* Check CHAP response */
1083 if ( len
!= ( int ) iscsi
->chap
.response_len
) {
1084 DBGC ( iscsi
, "iSCSI %p invalid CHAP response length\n",
1086 return -EPROTO_INVALID_CHAP_RESPONSE
;
1088 if ( memcmp ( buf
, iscsi
->chap
.response
, len
) != 0 ) {
1089 DBGC ( iscsi
, "iSCSI %p incorrect CHAP response \"%s\"\n",
1091 return -EACCES_INCORRECT_TARGET_PASSWORD
;
1094 /* Mark session as authenticated */
1095 iscsi
->status
|= ISCSI_STATUS_AUTH_REVERSE_OK
;
1100 /** An iSCSI text string that we want to handle */
1101 struct iscsi_string_type
{
1104 * This is the portion preceding the "=" sign,
1105 * e.g. "InitiatorName", "CHAP_A", etc.
1108 /** Handle iSCSI string value
1110 * @v iscsi iSCSI session
1111 * @v value iSCSI string value
1112 * @ret rc Return status code
1114 int ( * handle
) ( struct iscsi_session
*iscsi
, const char *value
);
1117 /** iSCSI text strings that we want to handle */
1118 static struct iscsi_string_type iscsi_string_types
[] = {
1119 { "TargetAddress", iscsi_handle_targetaddress_value
},
1120 { "AuthMethod", iscsi_handle_authmethod_value
},
1121 { "CHAP_A", iscsi_handle_chap_a_value
},
1122 { "CHAP_I", iscsi_handle_chap_i_value
},
1123 { "CHAP_C", iscsi_handle_chap_c_value
},
1124 { "CHAP_N", iscsi_handle_chap_n_value
},
1125 { "CHAP_R", iscsi_handle_chap_r_value
},
1130 * Handle iSCSI string
1132 * @v iscsi iSCSI session
1133 * @v string iSCSI string (in "key=value" format)
1134 * @ret rc Return status code
1136 static int iscsi_handle_string ( struct iscsi_session
*iscsi
,
1137 const char *string
) {
1138 struct iscsi_string_type
*type
;
1139 const char *separator
;
1144 /* Find separator */
1145 separator
= strchr ( string
, '=' );
1146 if ( ! separator
) {
1147 DBGC ( iscsi
, "iSCSI %p malformed string %s\n",
1149 return -EPROTO_INVALID_KEY_VALUE_PAIR
;
1151 key_len
= ( separator
- string
);
1152 value
= ( separator
+ 1 );
1154 /* Check for rejections. Since we send only non-rejectable
1155 * values, any rejection is a fatal protocol error.
1157 if ( strcmp ( value
, "Reject" ) == 0 ) {
1158 DBGC ( iscsi
, "iSCSI %p rejection: %s\n", iscsi
, string
);
1159 return -EPROTO_VALUE_REJECTED
;
1162 /* Handle key/value pair */
1163 for ( type
= iscsi_string_types
; type
->key
; type
++ ) {
1164 if ( strncmp ( string
, type
->key
, key_len
) != 0 )
1166 DBGC ( iscsi
, "iSCSI %p handling %s\n", iscsi
, string
);
1167 if ( ( rc
= type
->handle ( iscsi
, value
) ) != 0 ) {
1168 DBGC ( iscsi
, "iSCSI %p could not handle %s: %s\n",
1169 iscsi
, string
, strerror ( rc
) );
1174 DBGC ( iscsi
, "iSCSI %p ignoring %s\n", iscsi
, string
);
1179 * Handle iSCSI strings
1181 * @v iscsi iSCSI session
1182 * @v string iSCSI string buffer
1183 * @v len Length of string buffer
1184 * @ret rc Return status code
1186 static int iscsi_handle_strings ( struct iscsi_session
*iscsi
,
1187 const char *strings
, size_t len
) {
1191 /* Handle each string in turn, taking care not to overrun the
1192 * data buffer in case of badly-terminated data.
1195 string_len
= ( strnlen ( strings
, len
) + 1 );
1196 if ( string_len
> len
)
1198 if ( ( rc
= iscsi_handle_string ( iscsi
, strings
) ) != 0 )
1200 strings
+= string_len
;
1207 * Convert iSCSI response status to return status code
1209 * @v status_class iSCSI status class
1210 * @v status_detail iSCSI status detail
1211 * @ret rc Return status code
1213 static int iscsi_status_to_rc ( unsigned int status_class
,
1214 unsigned int status_detail
) {
1215 switch ( status_class
) {
1216 case ISCSI_STATUS_INITIATOR_ERROR
:
1217 switch ( status_detail
) {
1218 case ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION
:
1219 return -EPERM_INITIATOR_AUTHENTICATION
;
1220 case ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION
:
1221 return -EPERM_INITIATOR_AUTHORISATION
;
1222 case ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND
:
1223 case ISCSI_STATUS_INITIATOR_ERROR_REMOVED
:
1226 return -ENOTSUP_INITIATOR_STATUS
;
1228 case ISCSI_STATUS_TARGET_ERROR
:
1229 switch ( status_detail
) {
1230 case ISCSI_STATUS_TARGET_ERROR_UNAVAILABLE
:
1231 return -EIO_TARGET_UNAVAILABLE
;
1232 case ISCSI_STATUS_TARGET_ERROR_NO_RESOURCES
:
1233 return -EIO_TARGET_NO_RESOURCES
;
1235 return -ENOTSUP_TARGET_STATUS
;
1243 * Receive data segment of an iSCSI login response PDU
1245 * @v iscsi iSCSI session
1246 * @v data Received data
1247 * @v len Length of received data
1248 * @v remaining Data remaining after this data
1249 * @ret rc Return status code
1251 static int iscsi_rx_login_response ( struct iscsi_session
*iscsi
,
1252 const void *data
, size_t len
,
1253 size_t remaining
) {
1254 struct iscsi_bhs_login_response
*response
1255 = &iscsi
->rx_bhs
.login_response
;
1258 /* Buffer up the PDU data */
1259 if ( ( rc
= iscsi_rx_buffered_data ( iscsi
, data
, len
) ) != 0 ) {
1260 DBGC ( iscsi
, "iSCSI %p could not buffer login response: %s\n",
1261 iscsi
, strerror ( rc
) );
1267 /* Process string data and discard string buffer */
1268 if ( ( rc
= iscsi_handle_strings ( iscsi
, iscsi
->rx_buffer
,
1269 iscsi
->rx_len
) ) != 0 )
1271 iscsi_rx_buffered_data_done ( iscsi
);
1273 /* Check for login redirection */
1274 if ( response
->status_class
== ISCSI_STATUS_REDIRECT
) {
1275 DBGC ( iscsi
, "iSCSI %p redirecting to new server\n", iscsi
);
1276 iscsi_close_connection ( iscsi
, 0 );
1277 if ( ( rc
= iscsi_open_connection ( iscsi
) ) != 0 ) {
1278 DBGC ( iscsi
, "iSCSI %p could not redirect: %s\n ",
1279 iscsi
, strerror ( rc
) );
1285 /* Check for fatal errors */
1286 if ( response
->status_class
!= 0 ) {
1287 DBGC ( iscsi
, "iSCSI login failure: class %02x detail %02x\n",
1288 response
->status_class
, response
->status_detail
);
1289 rc
= iscsi_status_to_rc ( response
->status_class
,
1290 response
->status_detail
);
1294 /* Handle login transitions */
1295 if ( response
->flags
& ISCSI_LOGIN_FLAG_TRANSITION
) {
1296 iscsi
->status
&= ~( ISCSI_STATUS_PHASE_MASK
|
1297 ISCSI_STATUS_STRINGS_MASK
);
1298 switch ( response
->flags
& ISCSI_LOGIN_NSG_MASK
) {
1299 case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION
:
1301 ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE
|
1302 ISCSI_STATUS_STRINGS_OPERATIONAL
);
1304 case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE
:
1305 iscsi
->status
|= ISCSI_STATUS_FULL_FEATURE_PHASE
;
1308 DBGC ( iscsi
, "iSCSI %p got invalid response flags "
1309 "%02x\n", iscsi
, response
->flags
);
1314 /* Send next login request PDU if we haven't reached the full
1315 * feature phase yet.
1317 if ( ( iscsi
->status
& ISCSI_STATUS_PHASE_MASK
) !=
1318 ISCSI_STATUS_FULL_FEATURE_PHASE
) {
1319 iscsi_start_login ( iscsi
);
1323 /* Check that target authentication was successful (if required) */
1324 if ( ( iscsi
->status
& ISCSI_STATUS_AUTH_REVERSE_REQUIRED
) &&
1325 ! ( iscsi
->status
& ISCSI_STATUS_AUTH_REVERSE_OK
) ) {
1326 DBGC ( iscsi
, "iSCSI %p nefarious target tried to bypass "
1327 "authentication\n", iscsi
);
1331 /* Notify SCSI layer of window change */
1332 DBGC ( iscsi
, "iSCSI %p entering full feature phase\n", iscsi
);
1333 xfer_window_changed ( &iscsi
->control
);
1338 /****************************************************************************
1340 * iSCSI to socket interface
1347 * @v iscsi iSCSI session
1349 static void iscsi_tx_pause ( struct iscsi_session
*iscsi
) {
1350 process_del ( &iscsi
->process
);
1356 * @v iscsi iSCSI session
1358 static void iscsi_tx_resume ( struct iscsi_session
*iscsi
) {
1359 process_add ( &iscsi
->process
);
1363 * Start up a new TX PDU
1365 * @v iscsi iSCSI session
1367 * This initiates the process of sending a new PDU. Only one PDU may
1368 * be in transit at any one time.
1370 static void iscsi_start_tx ( struct iscsi_session
*iscsi
) {
1372 assert ( iscsi
->tx_state
== ISCSI_TX_IDLE
);
1374 /* Initialise TX BHS */
1375 memset ( &iscsi
->tx_bhs
, 0, sizeof ( iscsi
->tx_bhs
) );
1377 /* Flag TX engine to start transmitting */
1378 iscsi
->tx_state
= ISCSI_TX_BHS
;
1380 /* Start transmission process */
1381 iscsi_tx_resume ( iscsi
);
1387 * @v iscsi iSCSI session
1388 * @ret rc Return status code
1390 static int iscsi_tx_nothing ( struct iscsi_session
*iscsi __unused
) {
1395 * Transmit basic header segment of an iSCSI PDU
1397 * @v iscsi iSCSI session
1398 * @ret rc Return status code
1400 static int iscsi_tx_bhs ( struct iscsi_session
*iscsi
) {
1401 return xfer_deliver_raw ( &iscsi
->socket
, &iscsi
->tx_bhs
,
1402 sizeof ( iscsi
->tx_bhs
) );
1406 * Transmit data segment of an iSCSI PDU
1408 * @v iscsi iSCSI session
1409 * @ret rc Return status code
1411 * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
1412 * will be valid when this is called.
1414 static int iscsi_tx_data ( struct iscsi_session
*iscsi
) {
1415 struct iscsi_bhs_common
*common
= &iscsi
->tx_bhs
.common
;
1417 switch ( common
->opcode
& ISCSI_OPCODE_MASK
) {
1418 case ISCSI_OPCODE_DATA_OUT
:
1419 return iscsi_tx_data_out ( iscsi
);
1420 case ISCSI_OPCODE_LOGIN_REQUEST
:
1421 return iscsi_tx_login_request ( iscsi
);
1423 /* Nothing to send in other states */
1429 * Complete iSCSI PDU transmission
1431 * @v iscsi iSCSI session
1433 * Called when a PDU has been completely transmitted and the TX state
1434 * machine is about to enter the idle state. iscsi::tx_bhs will be
1435 * valid for the just-completed PDU when this is called.
1437 static void iscsi_tx_done ( struct iscsi_session
*iscsi
) {
1438 struct iscsi_bhs_common
*common
= &iscsi
->tx_bhs
.common
;
1440 /* Stop transmission process */
1441 iscsi_tx_pause ( iscsi
);
1443 switch ( common
->opcode
& ISCSI_OPCODE_MASK
) {
1444 case ISCSI_OPCODE_DATA_OUT
:
1445 iscsi_data_out_done ( iscsi
);
1447 case ISCSI_OPCODE_LOGIN_REQUEST
:
1448 iscsi_login_request_done ( iscsi
);
1457 * Transmit iSCSI PDU
1459 * @v iscsi iSCSI session
1460 * @v buf Temporary data buffer
1461 * @v len Length of temporary data buffer
1463 * Constructs data to be sent for the current TX state
1465 static void iscsi_tx_step ( struct iscsi_session
*iscsi
) {
1466 struct iscsi_bhs_common
*common
= &iscsi
->tx_bhs
.common
;
1467 int ( * tx
) ( struct iscsi_session
*iscsi
);
1468 enum iscsi_tx_state next_state
;
1472 /* Select fragment to transmit */
1474 switch ( iscsi
->tx_state
) {
1477 tx_len
= sizeof ( iscsi
->tx_bhs
);
1478 next_state
= ISCSI_TX_AHS
;
1481 tx
= iscsi_tx_nothing
;
1483 next_state
= ISCSI_TX_DATA
;
1487 tx_len
= ISCSI_DATA_LEN ( common
->lengths
);
1488 next_state
= ISCSI_TX_IDLE
;
1491 /* Nothing to do; pause processing */
1492 iscsi_tx_pause ( iscsi
);
1499 /* Check for window availability, if needed */
1500 if ( tx_len
&& ( xfer_window ( &iscsi
->socket
) == 0 ) ) {
1501 /* Cannot transmit at this point; pause
1502 * processing and wait for window to reopen
1504 iscsi_tx_pause ( iscsi
);
1509 if ( ( rc
= tx ( iscsi
) ) != 0 ) {
1510 DBGC ( iscsi
, "iSCSI %p could not transmit: %s\n",
1511 iscsi
, strerror ( rc
) );
1512 /* Transmission errors are fatal */
1513 iscsi_close ( iscsi
, rc
);
1517 /* Move to next state */
1518 iscsi
->tx_state
= next_state
;
1520 /* If we have moved to the idle state, mark
1521 * transmission as complete
1523 if ( iscsi
->tx_state
== ISCSI_TX_IDLE
)
1524 iscsi_tx_done ( iscsi
);
1528 /** iSCSI TX process descriptor */
1529 static struct process_descriptor iscsi_process_desc
=
1530 PROC_DESC ( struct iscsi_session
, process
, iscsi_tx_step
);
1533 * Receive basic header segment of an iSCSI PDU
1535 * @v iscsi iSCSI session
1536 * @v data Received data
1537 * @v len Length of received data
1538 * @v remaining Data remaining after this data
1539 * @ret rc Return status code
1541 * This fills in iscsi::rx_bhs with the data from the BHS portion of
1544 static int iscsi_rx_bhs ( struct iscsi_session
*iscsi
, const void *data
,
1545 size_t len
, size_t remaining __unused
) {
1546 memcpy ( &iscsi
->rx_bhs
.bytes
[iscsi
->rx_offset
], data
, len
);
1547 if ( ( iscsi
->rx_offset
+ len
) >= sizeof ( iscsi
->rx_bhs
) ) {
1548 DBGC2 ( iscsi
, "iSCSI %p received PDU opcode %#x len %#x\n",
1549 iscsi
, iscsi
->rx_bhs
.common
.opcode
,
1550 ISCSI_DATA_LEN ( iscsi
->rx_bhs
.common
.lengths
) );
1556 * Discard portion of an iSCSI PDU.
1558 * @v iscsi iSCSI session
1559 * @v data Received data
1560 * @v len Length of received data
1561 * @v remaining Data remaining after this data
1562 * @ret rc Return status code
1564 * This discards data from a portion of a received PDU.
1566 static int iscsi_rx_discard ( struct iscsi_session
*iscsi __unused
,
1567 const void *data __unused
, size_t len __unused
,
1568 size_t remaining __unused
) {
1574 * Receive data segment of an iSCSI PDU
1576 * @v iscsi iSCSI session
1577 * @v data Received data
1578 * @v len Length of received data
1579 * @v remaining Data remaining after this data
1580 * @ret rc Return status code
1582 * Handle processing of part of a PDU data segment. iscsi::rx_bhs
1583 * will be valid when this is called.
1585 static int iscsi_rx_data ( struct iscsi_session
*iscsi
, const void *data
,
1586 size_t len
, size_t remaining
) {
1587 struct iscsi_bhs_common_response
*response
1588 = &iscsi
->rx_bhs
.common_response
;
1590 /* Update cmdsn and statsn */
1591 iscsi
->cmdsn
= ntohl ( response
->expcmdsn
);
1592 iscsi
->statsn
= ntohl ( response
->statsn
);
1594 switch ( response
->opcode
& ISCSI_OPCODE_MASK
) {
1595 case ISCSI_OPCODE_LOGIN_RESPONSE
:
1596 return iscsi_rx_login_response ( iscsi
, data
, len
, remaining
);
1597 case ISCSI_OPCODE_SCSI_RESPONSE
:
1598 return iscsi_rx_scsi_response ( iscsi
, data
, len
, remaining
);
1599 case ISCSI_OPCODE_DATA_IN
:
1600 return iscsi_rx_data_in ( iscsi
, data
, len
, remaining
);
1601 case ISCSI_OPCODE_R2T
:
1602 return iscsi_rx_r2t ( iscsi
, data
, len
, remaining
);
1603 case ISCSI_OPCODE_NOP_IN
:
1604 return iscsi_rx_nop_in ( iscsi
, data
, len
, remaining
);
1608 DBGC ( iscsi
, "iSCSI %p unknown opcode %02x\n", iscsi
,
1610 return -ENOTSUP_OPCODE
;
1617 * @v iscsi iSCSI session
1618 * @v iobuf I/O buffer
1619 * @v meta Data transfer metadata
1620 * @ret rc Return status code
1622 * This handles received PDUs. The receive strategy is to fill in
1623 * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
1624 * throw away any AHS portion, and then process each part of the data
1625 * portion as it arrives. The data processing routine therefore
1626 * always has a full copy of the BHS available, even for portions of
1627 * the data in different packets to the BHS.
1629 static int iscsi_socket_deliver ( struct iscsi_session
*iscsi
,
1630 struct io_buffer
*iobuf
,
1631 struct xfer_metadata
*meta __unused
) {
1632 struct iscsi_bhs_common
*common
= &iscsi
->rx_bhs
.common
;
1633 int ( * rx
) ( struct iscsi_session
*iscsi
, const void *data
,
1634 size_t len
, size_t remaining
);
1635 enum iscsi_rx_state next_state
;
1641 switch ( iscsi
->rx_state
) {
1644 iscsi
->rx_len
= sizeof ( iscsi
->rx_bhs
);
1645 next_state
= ISCSI_RX_AHS
;
1648 rx
= iscsi_rx_discard
;
1649 iscsi
->rx_len
= 4 * ISCSI_AHS_LEN ( common
->lengths
);
1650 next_state
= ISCSI_RX_DATA
;
1654 iscsi
->rx_len
= ISCSI_DATA_LEN ( common
->lengths
);
1655 next_state
= ISCSI_RX_DATA_PADDING
;
1657 case ISCSI_RX_DATA_PADDING
:
1658 rx
= iscsi_rx_discard
;
1659 iscsi
->rx_len
= ISCSI_DATA_PAD_LEN ( common
->lengths
);
1660 next_state
= ISCSI_RX_BHS
;
1668 frag_len
= iscsi
->rx_len
- iscsi
->rx_offset
;
1669 if ( frag_len
> iob_len ( iobuf
) )
1670 frag_len
= iob_len ( iobuf
);
1671 remaining
= iscsi
->rx_len
- iscsi
->rx_offset
- frag_len
;
1672 if ( ( rc
= rx ( iscsi
, iobuf
->data
, frag_len
,
1673 remaining
) ) != 0 ) {
1674 DBGC ( iscsi
, "iSCSI %p could not process received "
1675 "data: %s\n", iscsi
, strerror ( rc
) );
1679 iscsi
->rx_offset
+= frag_len
;
1680 iob_pull ( iobuf
, frag_len
);
1682 /* If all the data for this state has not yet been
1683 * received, stay in this state for now.
1685 if ( iscsi
->rx_offset
!= iscsi
->rx_len
) {
1690 iscsi
->rx_state
= next_state
;
1691 iscsi
->rx_offset
= 0;
1695 /* Free I/O buffer */
1698 /* Destroy session on error */
1700 iscsi_close ( iscsi
, rc
);
1706 * Handle redirection event
1708 * @v iscsi iSCSI session
1709 * @v type Location type
1710 * @v args Remaining arguments depend upon location type
1711 * @ret rc Return status code
1713 static int iscsi_vredirect ( struct iscsi_session
*iscsi
, int type
,
1716 struct sockaddr
*peer
;
1719 /* Intercept redirects to a LOCATION_SOCKET and record the IP
1720 * address for the iBFT. This is a bit of a hack, but avoids
1721 * inventing an ioctl()-style call to retrieve the socket
1722 * address from a data-xfer interface.
1724 if ( type
== LOCATION_SOCKET
) {
1725 va_copy ( tmp
, args
);
1726 ( void ) va_arg ( tmp
, int ); /* Discard "semantics" */
1727 peer
= va_arg ( tmp
, struct sockaddr
* );
1728 memcpy ( &iscsi
->target_sockaddr
, peer
,
1729 sizeof ( iscsi
->target_sockaddr
) );
1733 /* Redirect to new location */
1734 if ( ( rc
= xfer_vreopen ( &iscsi
->socket
, type
, args
) ) != 0 )
1740 iscsi_close ( iscsi
, rc
);
1744 /** iSCSI socket interface operations */
1745 static struct interface_operation iscsi_socket_operations
[] = {
1746 INTF_OP ( xfer_deliver
, struct iscsi_session
*, iscsi_socket_deliver
),
1747 INTF_OP ( xfer_window_changed
, struct iscsi_session
*,
1749 INTF_OP ( xfer_vredirect
, struct iscsi_session
*, iscsi_vredirect
),
1750 INTF_OP ( intf_close
, struct iscsi_session
*, iscsi_close
),
1753 /** iSCSI socket interface descriptor */
1754 static struct interface_descriptor iscsi_socket_desc
=
1755 INTF_DESC ( struct iscsi_session
, socket
, iscsi_socket_operations
);
1757 /****************************************************************************
1759 * iSCSI command issuing
1764 * Check iSCSI flow-control window
1766 * @v iscsi iSCSI session
1767 * @ret len Length of window
1769 static size_t iscsi_scsi_window ( struct iscsi_session
*iscsi
) {
1771 if ( ( ( iscsi
->status
& ISCSI_STATUS_PHASE_MASK
) ==
1772 ISCSI_STATUS_FULL_FEATURE_PHASE
) &&
1773 ( iscsi
->command
== NULL
) ) {
1774 /* We cannot handle concurrent commands */
1782 * Issue iSCSI SCSI command
1784 * @v iscsi iSCSI session
1785 * @v parent Parent interface
1786 * @v command SCSI command
1787 * @ret tag Command tag, or negative error
1789 static int iscsi_scsi_command ( struct iscsi_session
*iscsi
,
1790 struct interface
*parent
,
1791 struct scsi_cmd
*command
) {
1793 /* This iSCSI implementation cannot handle multiple concurrent
1794 * commands or commands arriving before login is complete.
1796 if ( iscsi_scsi_window ( iscsi
) == 0 ) {
1797 DBGC ( iscsi
, "iSCSI %p cannot handle concurrent commands\n",
1803 iscsi
->command
= malloc ( sizeof ( *command
) );
1804 if ( ! iscsi
->command
)
1806 memcpy ( iscsi
->command
, command
, sizeof ( *command
) );
1808 /* Assign new ITT */
1809 iscsi_new_itt ( iscsi
);
1811 /* Start sending command */
1812 iscsi_start_command ( iscsi
);
1814 /* Attach to parent interface and return */
1815 intf_plug_plug ( &iscsi
->data
, parent
);
1820 * Get iSCSI ACPI descriptor
1822 * @v iscsi iSCSI session
1823 * @ret desc ACPI descriptor
1825 static struct acpi_descriptor
* iscsi_describe ( struct iscsi_session
*iscsi
) {
1827 return &iscsi
->desc
;
1830 /** iSCSI SCSI command-issuing interface operations */
1831 static struct interface_operation iscsi_control_op
[] = {
1832 INTF_OP ( scsi_command
, struct iscsi_session
*, iscsi_scsi_command
),
1833 INTF_OP ( xfer_window
, struct iscsi_session
*, iscsi_scsi_window
),
1834 INTF_OP ( intf_close
, struct iscsi_session
*, iscsi_close
),
1835 INTF_OP ( acpi_describe
, struct iscsi_session
*, iscsi_describe
),
1838 /** iSCSI SCSI command-issuing interface descriptor */
1839 static struct interface_descriptor iscsi_control_desc
=
1840 INTF_DESC ( struct iscsi_session
, control
, iscsi_control_op
);
1843 * Close iSCSI command
1845 * @v iscsi iSCSI session
1846 * @v rc Reason for close
1848 static void iscsi_command_close ( struct iscsi_session
*iscsi
, int rc
) {
1850 /* Restart interface */
1851 intf_restart ( &iscsi
->data
, rc
);
1853 /* Treat unsolicited command closures mid-command as fatal,
1854 * because we have no code to handle partially-completed PDUs.
1856 if ( iscsi
->command
!= NULL
)
1857 iscsi_close ( iscsi
, ( ( rc
== 0 ) ? -ECANCELED
: rc
) );
1860 /** iSCSI SCSI command interface operations */
1861 static struct interface_operation iscsi_data_op
[] = {
1862 INTF_OP ( intf_close
, struct iscsi_session
*, iscsi_command_close
),
1865 /** iSCSI SCSI command interface descriptor */
1866 static struct interface_descriptor iscsi_data_desc
=
1867 INTF_DESC ( struct iscsi_session
, data
, iscsi_data_op
);
1869 /****************************************************************************
1875 /** iSCSI root path components (as per RFC4173) */
1876 enum iscsi_root_path_component
{
1885 /** iSCSI initiator IQN setting */
1886 const struct setting initiator_iqn_setting
__setting ( SETTING_SANBOOT_EXTRA
,
1888 .name
= "initiator-iqn",
1889 .description
= "iSCSI initiator name",
1890 .tag
= DHCP_ISCSI_INITIATOR_IQN
,
1891 .type
= &setting_type_string
,
1894 /** iSCSI reverse username setting */
1895 const struct setting reverse_username_setting
__setting ( SETTING_AUTH_EXTRA
,
1896 reverse
-username
) = {
1897 .name
= "reverse-username",
1898 .description
= "Reverse user name",
1899 .tag
= DHCP_EB_REVERSE_USERNAME
,
1900 .type
= &setting_type_string
,
1903 /** iSCSI reverse password setting */
1904 const struct setting reverse_password_setting
__setting ( SETTING_AUTH_EXTRA
,
1905 reverse
-password
) = {
1906 .name
= "reverse-password",
1907 .description
= "Reverse password",
1908 .tag
= DHCP_EB_REVERSE_PASSWORD
,
1909 .type
= &setting_type_string
,
1913 * Parse iSCSI root path
1915 * @v iscsi iSCSI session
1916 * @v root_path iSCSI root path (as per RFC4173)
1917 * @ret rc Return status code
1919 static int iscsi_parse_root_path ( struct iscsi_session
*iscsi
,
1920 const char *root_path
) {
1921 char rp_copy
[ strlen ( root_path
) + 1 ];
1922 char *rp_comp
[NUM_RP_COMPONENTS
];
1928 /* Split root path into component parts */
1929 strcpy ( rp_copy
, root_path
);
1932 if ( i
== NUM_RP_COMPONENTS
)
1934 for ( ; ( ( *rp
!= ':' ) || skip
) ; rp
++ ) {
1936 DBGC ( iscsi
, "iSCSI %p root path \"%s\" "
1937 "too short\n", iscsi
, root_path
);
1938 return -EINVAL_ROOT_PATH_TOO_SHORT
;
1939 } else if ( *rp
== '[' ) {
1941 } else if ( *rp
== ']' ) {
1948 /* Use root path components to configure iSCSI session */
1949 iscsi
->target_address
= strdup ( rp_comp
[RP_SERVERNAME
] );
1950 if ( ! iscsi
->target_address
)
1952 iscsi
->target_port
= strtoul ( rp_comp
[RP_PORT
], NULL
, 10 );
1953 if ( ! iscsi
->target_port
)
1954 iscsi
->target_port
= ISCSI_PORT
;
1955 if ( ( rc
= scsi_parse_lun ( rp_comp
[RP_LUN
], &iscsi
->lun
) ) != 0 ) {
1956 DBGC ( iscsi
, "iSCSI %p invalid LUN \"%s\"\n",
1957 iscsi
, rp_comp
[RP_LUN
] );
1960 iscsi
->target_iqn
= strdup ( rp_comp
[RP_TARGETNAME
] );
1961 if ( ! iscsi
->target_iqn
)
1968 * Fetch iSCSI settings
1970 * @v iscsi iSCSI session
1971 * @ret rc Return status code
1973 static int iscsi_fetch_settings ( struct iscsi_session
*iscsi
) {
1978 /* Fetch relevant settings. Don't worry about freeing on
1979 * error, since iscsi_free() will take care of that anyway.
1981 fetch_string_setting_copy ( NULL
, &username_setting
,
1982 &iscsi
->initiator_username
);
1983 fetch_string_setting_copy ( NULL
, &password_setting
,
1984 &iscsi
->initiator_password
);
1985 fetch_string_setting_copy ( NULL
, &reverse_username_setting
,
1986 &iscsi
->target_username
);
1987 fetch_string_setting_copy ( NULL
, &reverse_password_setting
,
1988 &iscsi
->target_password
);
1990 /* Use explicit initiator IQN if provided */
1991 fetch_string_setting_copy ( NULL
, &initiator_iqn_setting
,
1992 &iscsi
->initiator_iqn
);
1993 if ( iscsi
->initiator_iqn
)
1996 /* Otherwise, try to construct an initiator IQN from the hostname */
1997 fetch_string_setting_copy ( NULL
, &hostname_setting
, &hostname
);
1999 len
= asprintf ( &iscsi
->initiator_iqn
,
2000 ISCSI_DEFAULT_IQN_PREFIX
":%s", hostname
);
2003 DBGC ( iscsi
, "iSCSI %p could not allocate initiator "
2007 assert ( iscsi
->initiator_iqn
);
2011 /* Otherwise, try to construct an initiator IQN from the UUID */
2012 if ( ( len
= fetch_uuid_setting ( NULL
, &uuid_setting
, &uuid
) ) < 0 ) {
2013 DBGC ( iscsi
, "iSCSI %p has no suitable initiator IQN\n",
2015 return -EINVAL_NO_INITIATOR_IQN
;
2017 if ( ( len
= asprintf ( &iscsi
->initiator_iqn
,
2018 ISCSI_DEFAULT_IQN_PREFIX
":%s",
2019 uuid_ntoa ( &uuid
) ) ) < 0 ) {
2020 DBGC ( iscsi
, "iSCSI %p could not allocate initiator IQN\n",
2024 assert ( iscsi
->initiator_iqn
);
2031 * Check iSCSI authentication details
2033 * @v iscsi iSCSI session
2034 * @ret rc Return status code
2036 static int iscsi_check_auth ( struct iscsi_session
*iscsi
) {
2038 /* Check for invalid authentication combinations */
2039 if ( ( /* Initiator username without password (or vice-versa) */
2040 ( !! iscsi
->initiator_username
) ^
2041 ( !! iscsi
->initiator_password
) ) ||
2042 ( /* Target username without password (or vice-versa) */
2043 ( !! iscsi
->target_username
) ^
2044 ( !! iscsi
->target_password
) ) ||
2045 ( /* Target (reverse) without initiator (forward) */
2046 ( iscsi
->target_username
&&
2047 ( ! iscsi
->initiator_username
) ) ) ) {
2048 DBGC ( iscsi
, "iSCSI %p invalid credentials: initiator "
2049 "%sname,%spw, target %sname,%spw\n", iscsi
,
2050 ( iscsi
->initiator_username
? "" : "no " ),
2051 ( iscsi
->initiator_password
? "" : "no " ),
2052 ( iscsi
->target_username
? "" : "no " ),
2053 ( iscsi
->target_password
? "" : "no " ) );
2054 return -EINVAL_BAD_CREDENTIAL_MIX
;
2063 * @v parent Parent interface
2065 * @ret rc Return status code
2067 static int iscsi_open ( struct interface
*parent
, struct uri
*uri
) {
2068 struct iscsi_session
*iscsi
;
2072 if ( ! uri
->opaque
) {
2073 rc
= -EINVAL_NO_ROOT_PATH
;
2074 goto err_sanity_uri
;
2077 /* Allocate and initialise structure */
2078 iscsi
= zalloc ( sizeof ( *iscsi
) );
2083 ref_init ( &iscsi
->refcnt
, iscsi_free
);
2084 intf_init ( &iscsi
->control
, &iscsi_control_desc
, &iscsi
->refcnt
);
2085 intf_init ( &iscsi
->data
, &iscsi_data_desc
, &iscsi
->refcnt
);
2086 intf_init ( &iscsi
->socket
, &iscsi_socket_desc
, &iscsi
->refcnt
);
2087 process_init_stopped ( &iscsi
->process
, &iscsi_process_desc
,
2089 // acpi_init ( &iscsi->desc, &ibft_model, &iscsi->refcnt );
2091 /* Parse root path */
2092 if ( ( rc
= iscsi_parse_root_path ( iscsi
, uri
->opaque
) ) != 0 )
2093 goto err_parse_root_path
;
2094 /* Set fields not specified by root path */
2095 if ( ( rc
= iscsi_fetch_settings ( iscsi
) ) != 0 )
2096 goto err_fetch_settings
;
2097 /* Validate authentication */
2098 if ( ( rc
= iscsi_check_auth ( iscsi
) ) != 0 )
2099 goto err_check_auth
;
2102 if ( ! iscsi
->target_address
) {
2103 DBGC ( iscsi
, "iSCSI %p does not yet support discovery\n",
2105 rc
= -ENOTSUP_DISCOVERY
;
2106 goto err_sanity_address
;
2108 if ( ! iscsi
->target_iqn
) {
2109 DBGC ( iscsi
, "iSCSI %p no target address supplied in %s\n",
2110 iscsi
, uri
->opaque
);
2111 rc
= -EINVAL_NO_TARGET_IQN
;
2112 goto err_sanity_iqn
;
2114 DBGC ( iscsi
, "iSCSI %p initiator %s\n",iscsi
, iscsi
->initiator_iqn
);
2115 DBGC ( iscsi
, "iSCSI %p target %s %s\n",
2116 iscsi
, iscsi
->target_address
, iscsi
->target_iqn
);
2119 if ( ( rc
= iscsi_open_connection ( iscsi
) ) != 0 )
2120 goto err_open_connection
;
2122 /* Attach SCSI device to parent interface */
2123 if ( ( rc
= scsi_open ( parent
, &iscsi
->control
,
2124 &iscsi
->lun
) ) != 0 ) {
2125 DBGC ( iscsi
, "iSCSI %p could not create SCSI device: %s\n",
2126 iscsi
, strerror ( rc
) );
2130 /* Mortalise self, and return */
2131 ref_put ( &iscsi
->refcnt
);
2135 err_open_connection
:
2140 err_parse_root_path
:
2141 iscsi_close ( iscsi
, rc
);
2142 ref_put ( &iscsi
->refcnt
);
2148 /** iSCSI URI opener */
2149 struct uri_opener iscsi_uri_opener __uri_opener
= {