12 #include <gpxe/scsi.h>
14 /** Default iSCSI port */
15 #define ISCSI_PORT 3260
18 * iSCSI segment lengths
20 * iSCSI uses an icky structure with one one-byte field (a dword
21 * count) and one three-byte field (a byte count). This structure,
22 * and the accompanying macros, relieve some of the pain.
24 union iscsi_segment_lengths {
26 /** The AHS length (measured in dwords) */
28 /** The data length (measured in bytes), in network
33 /** Ths data length (measured in bytes), in network byte
34 * order, with ahs_len as the first byte.
36 uint32_t ahs_and_data_len;
39 /** The length of the additional header segment, in dwords */
40 #define ISCSI_AHS_LEN( segment_lengths ) \
41 ( (segment_lengths).bytes.ahs_len )
43 /** The length of the data segment, in bytes, excluding any padding */
44 #define ISCSI_DATA_LEN( segment_lengths ) \
45 ( ntohl ( (segment_lengths).ahs_and_data_len ) & 0xffffff )
47 /** The padding of the data segment, in bytes */
48 #define ISCSI_DATA_PAD_LEN( segment_lengths ) \
49 ( ( 0 - (segment_lengths).bytes.data_len[2] ) & 0x03 )
51 /** Set additional header and data segment lengths */
52 #define ISCSI_SET_LENGTHS( segment_lengths, ahs_len, data_len ) do { \
53 (segment_lengths).ahs_and_data_len = \
54 htonl ( data_len | ( ahs_len << 24 ) ); \
58 * iSCSI basic header segment common fields
61 struct iscsi_bhs_common {
66 /** Fields specific to the PDU type */
68 /** Segment lengths */
69 union iscsi_segment_lengths lengths;
70 /** Fields specific to the PDU type */
72 /** Initiator Task Tag */
74 /** Fields specific to the PDU type */
79 #define ISCSI_OPCODE_MASK 0x3f
81 /** Immediate delivery */
82 #define ISCSI_FLAG_IMMEDIATE 0x40
84 /** Final PDU of a sequence */
85 #define ISCSI_FLAG_FINAL 0x80
88 * iSCSI basic header segment common request fields
91 struct iscsi_bhs_common_response {
96 /** Fields specific to the PDU type */
98 /** Segment lengths */
99 union iscsi_segment_lengths lengths;
100 /** Fields specific to the PDU type */
102 /** Initiator Task Tag */
104 /** Fields specific to the PDU type */
106 /** Status sequence number */
108 /** Expected command sequence number */
110 /** Fields specific to the PDU type */
115 * iSCSI login request basic header segment
118 struct iscsi_bhs_login_request {
123 /** Maximum supported version number */
125 /** Minimum supported version number */
127 /** Segment lengths */
128 union iscsi_segment_lengths lengths;
129 /** Initiator session ID (IANA format) enterprise number and flags */
130 uint32_t isid_iana_en;
131 /** Initiator session ID (IANA format) qualifier */
132 uint16_t isid_iana_qual;
133 /** Target session identifying handle */
135 /** Initiator Task Tag */
141 /** Command sequence number */
143 /** Expected status sequence number */
146 uint8_t reserved_b[16];
149 /** Login request opcode */
150 #define ISCSI_OPCODE_LOGIN_REQUEST 0x03
152 /** Willingness to transition to next stage */
153 #define ISCSI_LOGIN_FLAG_TRANSITION 0x80
155 /** Key=value pairs continued in subsequent request */
156 #define ISCSI_LOGIN_FLAG_CONTINUE 0x40
158 /* Current stage values and mask */
159 #define ISCSI_LOGIN_CSG_MASK 0x0c
160 #define ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION 0x00
161 #define ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION 0x04
162 #define ISCSI_LOGIN_CSG_FULL_FEATURE_PHASE 0x0c
164 /* Next stage values and mask */
165 #define ISCSI_LOGIN_NSG_MASK 0x03
166 #define ISCSI_LOGIN_NSG_SECURITY_NEGOTIATION 0x00
167 #define ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION 0x01
168 #define ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE 0x03
170 /* Combined stage values and mask */
171 #define ISCSI_LOGIN_STAGE_MASK ( ISCSI_LOGIN_CSG_MASK | ISCSI_LOGIN_NSG_MASK )
172 #define ISCSI_LOGIN_STAGE_SEC ( ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION | \
173 ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION )
174 #define ISCSI_LOGIN_STAGE_OP ( ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION | \
175 ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE )
177 /** ISID IANA format marker */
178 #define ISCSI_ISID_IANA 0x40000000
180 /** Fen Systems Ltd. IANA enterprise number
182 * Permission is hereby granted to use Fen Systems Ltd.'s IANA
183 * enterprise number with this iSCSI implementation.
185 #define IANA_EN_FEN_SYSTEMS 10019
188 * iSCSI login response basic header segment
191 struct iscsi_bhs_login_response {
196 /** Maximum supported version number */
198 /** Minimum supported version number */
200 /** Segment lengths */
201 union iscsi_segment_lengths lengths;
202 /** Initiator session ID (IANA format) enterprise number and flags */
203 uint32_t isid_iana_en;
204 /** Initiator session ID (IANA format) qualifier */
205 uint16_t isid_iana_qual;
206 /** Target session identifying handle */
208 /** Initiator Task Tag */
212 /** Status sequence number */
214 /** Expected command sequence number */
216 /** Maximum command sequence number */
219 uint8_t status_class;
221 uint8_t status_detail;
223 uint8_t reserved_b[10];
226 /** Login response opcode */
227 #define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
230 * iSCSI SCSI command basic header segment
233 struct iscsi_bhs_scsi_command {
240 /** Segment lengths */
241 union iscsi_segment_lengths lengths;
242 /** SCSI Logical Unit Number */
244 /** Initiator Task Tag */
246 /** Expected data transfer length */
248 /** Command sequence number */
250 /** Expected status sequence number */
252 /** SCSI Command Descriptor Block (CDB) */
256 /** SCSI command opcode */
257 #define ISCSI_OPCODE_SCSI_COMMAND 0x01
259 /** Command will read data */
260 #define ISCSI_COMMAND_FLAG_READ 0x40
262 /** Command will write data */
263 #define ISCSI_COMMAND_FLAG_WRITE 0x20
265 /* Task attributes */
266 #define ISCSI_COMMAND_ATTR_UNTAGGED 0x00
267 #define ISCSI_COMMAND_ATTR_SIMPLE 0x01
268 #define ISCSI_COMMAND_ATTR_ORDERED 0x02
269 #define ISCSI_COMMAND_ATTR_HEAD_OF_QUEUE 0x03
270 #define ISCSI_COMMAND_ATTR_ACA 0x04
273 * iSCSI SCSI response basic header segment
276 struct iscsi_bhs_scsi_response {
283 /** SCSI status code */
285 /** Segment lengths */
286 union iscsi_segment_lengths lengths;
288 uint8_t reserved_a[8];
289 /** Initiator Task Tag */
293 /** Status sequence number */
295 /** Expected command sequence number */
297 /** Maximum command sequence number */
299 /** Expected data sequence number */
302 uint8_t reserved_b[8];
305 /** SCSI response opcode */
306 #define ISCSI_OPCODE_SCSI_RESPONSE 0x21
308 /** SCSI command completed at target */
309 #define ISCSI_RESPONSE_COMMAND_COMPLETE 0x00
311 /** SCSI target failure */
312 #define ISCSI_RESPONSE_TARGET_FAILURE 0x01
314 /** SCSI sense response code offset
316 * The SCSI response may contain unsolicited sense data in the data
317 * segment. If it does, this is the offset to the sense response code
318 * byte, which is the only byte we care about.
320 #define ISCSI_SENSE_RESPONSE_CODE_OFFSET 2
323 * iSCSI data-in basic header segment
326 struct iscsi_bhs_data_in {
333 /** SCSI status code */
335 /** Segment lengths */
336 union iscsi_segment_lengths lengths;
337 /** Logical Unit Number */
339 /** Initiator Task Tag */
341 /** Target Transfer Tag */
343 /** Status sequence number */
345 /** Expected command sequence number */
347 /** Maximum command sequence number */
349 /** Data sequence number */
353 /** Residual count */
354 uint32_t residual_count;
357 /** Data-in opcode */
358 #define ISCSI_OPCODE_DATA_IN 0x25
360 /** Data requires acknowledgement */
361 #define ISCSI_DATA_FLAG_ACKNOWLEDGE 0x40
363 /** Data overflow occurred */
364 #define ISCSI_DATA_FLAG_OVERFLOW 0x04
366 /** Data underflow occurred */
367 #define ISCSI_DATA_FLAG_UNDERFLOW 0x02
369 /** SCSI status code and overflow/underflow flags are valid */
370 #define ISCSI_DATA_FLAG_STATUS 0x01
373 * iSCSI data-out basic header segment
376 struct iscsi_bhs_data_out {
383 /** Segment lengths */
384 union iscsi_segment_lengths lengths;
385 /** Logical Unit Number */
387 /** Initiator Task Tag */
389 /** Target Transfer Tag */
393 /** Expected status sequence number */
397 /** Data sequence number */
405 /** Data-out opcode */
406 #define ISCSI_OPCODE_DATA_OUT 0x05
409 * iSCSI request to transfer basic header segment
412 struct iscsi_bhs_r2t {
419 /** Segment lengths */
420 union iscsi_segment_lengths lengths;
421 /** Logical Unit Number */
423 /** Initiator Task Tag */
425 /** Target Transfer Tag */
427 /** Status sequence number */
429 /** Expected command sequence number */
431 /** Maximum command sequence number */
433 /** R2T sequence number */
437 /** Desired data transfer length */
442 #define ISCSI_OPCODE_R2T 0x31
445 * An iSCSI basic header segment
448 struct iscsi_bhs_common common;
449 struct iscsi_bhs_common_response common_response;
450 struct iscsi_bhs_login_request login_request;
451 struct iscsi_bhs_login_response login_response;
452 struct iscsi_bhs_scsi_command scsi_command;
453 struct iscsi_bhs_scsi_response scsi_response;
454 struct iscsi_bhs_data_in data_in;
455 struct iscsi_bhs_data_out data_out;
456 struct iscsi_bhs_r2t r2t;
457 unsigned char bytes[ sizeof ( struct iscsi_bhs_common ) ];
460 /** State of an iSCSI TX engine */
461 enum iscsi_tx_state {
462 /** Nothing to send */
464 /** Sending the basic header segment */
466 /** Sending the additional header segment */
468 /** Sending the data segment */
470 /** Sending the data segment padding */
471 ISCSI_TX_DATA_PADDING,
474 /** State of an iSCSI RX engine */
475 enum iscsi_rx_state {
476 /** Receiving the basic header segment */
478 /** Receiving the additional header segment */
480 /** Receiving the data segment */
482 /** Receiving the data segment padding */
483 ISCSI_RX_DATA_PADDING,
486 /** An iSCSI session */
487 struct iscsi_session {
488 /** TCP connection for this session */
489 struct tcp_connection tcp;
492 * This is the bitwise-OR of zero or more ISCSI_STATUS_XXX
498 * Number of times that the connection has been retried.
499 * Reset upon a successful connection.
504 const char *initiator;
507 /** Logical Unit Number (LUN) */
510 /** Target session identifying handle
512 * This is assigned by the target when we first log in, and
513 * must be reused on subsequent login attempts.
516 /** Initiator task tag
518 * This is the tag of the current command. It is incremented
519 * whenever a new command is started.
522 /** Target transfer tag
524 * This is the tag attached to a sequence of data-out PDUs in
525 * response to an R2T.
531 * This is the offset for an in-progress sequence of data-out
532 * PDUs in response to an R2T.
534 uint32_t transfer_offset;
538 * This is the length for an in-progress sequence of data-out
539 * PDUs in response to an R2T.
541 uint32_t transfer_len;
542 /** Command sequence number
544 * This is the sequence number of the current command, used to
545 * fill out the CmdSN field in iSCSI request PDUs. It is
546 * updated with the value of the ExpCmdSN field whenever we
547 * receive an iSCSI response PDU containing such a field.
550 /** Status sequence number
552 * This is the most recent status sequence number present in
553 * the StatSN field of an iSCSI response PDU containing such a
554 * field. Whenever we send an iSCSI request PDU, we fill out
555 * the ExpStatSN field with this value plus one.
559 /** Basic header segment for current TX PDU */
560 union iscsi_bhs tx_bhs;
561 /** State of the TX engine */
562 enum iscsi_tx_state tx_state;
563 /** Byte offset within the current TX state */
566 /** Basic header segment for current RX PDU */
567 union iscsi_bhs rx_bhs;
568 /** State of the RX engine */
569 enum iscsi_rx_state rx_state;
570 /** Byte offset within the current RX state */
573 /** Current SCSI command
575 * Set to NULL when command is complete.
577 struct scsi_command *command;
580 /** Session is currently connected */
581 #define ISCSI_STATUS_CONNECTED 0x01
583 /** Session has completed */
584 #define ISCSI_STATUS_DONE 0x02
586 /** Session failed */
587 #define ISCSI_STATUS_ERR 0x04
589 /** Maximum number of retries at connecting */
590 #define ISCSI_MAX_RETRIES 2
592 extern int iscsi_issue ( struct iscsi_session *iscsi,
593 struct scsi_command *command );
595 /** An iSCSI device */
596 struct iscsi_device {
597 /** SCSI device interface */
598 struct scsi_device scsi;
599 /** iSCSI protocol instance */
600 struct iscsi_session iscsi;
603 extern int init_iscsidev ( struct iscsi_device *iscsidev );
605 #endif /* _GPXE_ISCSI_H */