summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/scsi.h
blob: 28b55b2d51459f70f8b020f2f25155b3d0cab078 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
#ifndef _IPXE_SCSI_H
#define _IPXE_SCSI_H

#include <stdint.h>
#include <ipxe/uaccess.h>
#include <ipxe/interface.h>

/** @file
 *
 * SCSI devices
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

/** Maximum block for READ/WRITE (10) commands */
#define SCSI_MAX_BLOCK_10 0xffffffffULL

/**
 * @defgroup scsiops SCSI operation codes
 * @{
 */

#define SCSI_OPCODE_READ_10		0x28	/**< READ (10) */
#define SCSI_OPCODE_READ_16		0x88	/**< READ (16) */
#define SCSI_OPCODE_WRITE_10		0x2a	/**< WRITE (10) */
#define SCSI_OPCODE_WRITE_16		0x8a	/**< WRITE (16) */
#define SCSI_OPCODE_READ_CAPACITY_10	0x25	/**< READ CAPACITY (10) */
#define SCSI_OPCODE_SERVICE_ACTION_IN	0x9e	/**< SERVICE ACTION IN */
#define SCSI_SERVICE_ACTION_READ_CAPACITY_16 0x10 /**< READ CAPACITY (16) */
#define SCSI_OPCODE_TEST_UNIT_READY	0x00	/**< TEST UNIT READY */

/** @} */

/**
 * @defgroup scsiflags SCSI flags
 * @{
 */

#define SCSI_FL_FUA_NV		0x02	/**< Force unit access to NVS */
#define SCSI_FL_FUA		0x08	/**< Force unit access */
#define SCSI_FL_DPO		0x10	/**< Disable cache page out */

/** @} */

/**
 * @defgroup scsicdbs SCSI command data blocks
 * @{
 */

/** A SCSI "READ (10)" CDB */
struct scsi_cdb_read_10 {
	/** Opcode (0x28) */
	uint8_t opcode;
	/** Flags */
	uint8_t flags;
	/** Start address
	 *
	 * This is a logical block number, in big-endian order.
	 */
	uint32_t lba;
	/** Group number */
	uint8_t group;
	/** Transfer length
	 *
	 * This is a logical block count, in big-endian order.
	 */
	uint16_t len;
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** A SCSI "READ (16)" CDB */
struct scsi_cdb_read_16 {
	/** Opcode (0x88) */
	uint8_t opcode;
	/** Flags */
	uint8_t flags;
	/** Start address
	 *
	 * This is a logical block number, in big-endian order.
	 */
	uint64_t lba;
	/** Transfer length
	 *
	 * This is a logical block count, in big-endian order.
	 */
	uint32_t len;
	/** Group number */
	uint8_t group;
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** A SCSI "WRITE (10)" CDB */
struct scsi_cdb_write_10 {
	/** Opcode (0x2a) */
	uint8_t opcode;
	/** Flags */
	uint8_t flags;
	/** Start address
	 *
	 * This is a logical block number, in big-endian order.
	 */
	uint32_t lba;
	/** Group number */
	uint8_t group;
	/** Transfer length
	 *
	 * This is a logical block count, in big-endian order.
	 */
	uint16_t len;
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** A SCSI "WRITE (16)" CDB */
struct scsi_cdb_write_16 {
	/** Opcode (0x8a) */
	uint8_t opcode;
	/** Flags */
	uint8_t flags;
	/** Start address
	 *
	 * This is a logical block number, in big-endian order.
	 */
	uint64_t lba;
	/** Transfer length
	 *
	 * This is a logical block count, in big-endian order.
	 */
	uint32_t len;
	/** Group number */
	uint8_t group;
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** A SCSI "READ CAPACITY (10)" CDB */
struct scsi_cdb_read_capacity_10 {
	/** Opcode (0x25) */
	uint8_t opcode;
	/** Reserved */
	uint8_t reserved_a;
	/** Logical block address
	 *
	 * Applicable only if the PMI bit is set.
	 */
	uint32_t lba;
	/** Reserved */
	uint8_t reserved_b[3];
	/** Control byte */
	uint8_t control;	
} __attribute__ (( packed ));

/** SCSI "READ CAPACITY (10)" parameter data */
struct scsi_capacity_10 {
	/** Maximum logical block number */
	uint32_t lba;
	/** Block length in bytes */
	uint32_t blksize;
} __attribute__ (( packed ));

/** A SCSI "READ CAPACITY (16)" CDB */
struct scsi_cdb_read_capacity_16 {
	/** Opcode (0x9e) */
	uint8_t opcode;
	/** Service action */
	uint8_t service_action;
	/** Logical block address
	 *
	 * Applicable only if the PMI bit is set.
	 */
	uint64_t lba;
	/** Transfer length
	 *
	 * This is the size of the data-in buffer, in bytes.
	 */
	uint32_t len;
	/** Reserved */
	uint8_t reserved;
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** SCSI "READ CAPACITY (16)" parameter data */
struct scsi_capacity_16 {
	/** Maximum logical block number */
	uint64_t lba;
	/** Block length in bytes */
	uint32_t blksize;
	/** Reserved */
	uint8_t reserved[20];
} __attribute__ (( packed ));

/** A SCSI "TEST UNIT READY" CDB */
struct scsi_cdb_test_unit_ready {
	/** Opcode (0x00) */
	uint8_t opcode;
	/** Reserved */
	uint8_t reserved[4];
	/** Control byte */
	uint8_t control;
} __attribute__ (( packed ));

/** A SCSI Command Data Block */
union scsi_cdb {
	struct scsi_cdb_read_10 read10;
	struct scsi_cdb_read_16 read16;
	struct scsi_cdb_write_10 write10;
	struct scsi_cdb_write_16 write16;
	struct scsi_cdb_read_capacity_10 readcap10;
	struct scsi_cdb_read_capacity_16 readcap16;
	struct scsi_cdb_test_unit_ready testready;
	unsigned char bytes[16];
};

/** printf() format for dumping a scsi_cdb */
#define SCSI_CDB_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
			"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"

/** printf() parameters for dumping a scsi_cdb */
#define SCSI_CDB_DATA(cdb)						  \
	(cdb).bytes[0], (cdb).bytes[1], (cdb).bytes[2], (cdb).bytes[3],	  \
	(cdb).bytes[4], (cdb).bytes[5], (cdb).bytes[6], (cdb).bytes[7],	  \
	(cdb).bytes[8], (cdb).bytes[9], (cdb).bytes[10], (cdb).bytes[11], \
	(cdb).bytes[12], (cdb).bytes[13], (cdb).bytes[14], (cdb).bytes[15]

/** @} */

/** A SCSI LUN
 *
 * This is a four-level LUN as specified by SAM-2, in big-endian
 * order.
 */
struct scsi_lun {
	uint16_t u16[4];
}  __attribute__ (( packed ));

/** printf() format for dumping a scsi_lun */
#define SCSI_LUN_FORMAT "%04x-%04x-%04x-%04x"

/** printf() parameters for dumping a scsi_lun */
#define SCSI_LUN_DATA(lun)						  \
	ntohs ( (lun).u16[0] ), ntohs ( (lun).u16[1] ),			  \
	ntohs ( (lun).u16[2] ), ntohs ( (lun).u16[3] )

/** A SCSI command information unit */
struct scsi_cmd {
	/** LUN */
	struct scsi_lun lun;
	/** CDB for this command */
	union scsi_cdb cdb;
	/** Data-out buffer (may be NULL) */
	userptr_t data_out;
	/** Data-out buffer length
	 *
	 * Must be zero if @c data_out is NULL
	 */
	size_t data_out_len;
	/** Data-in buffer (may be NULL) */
	userptr_t data_in;
	/** Data-in buffer length
	 *
	 * Must be zero if @c data_in is NULL
	 */
	size_t data_in_len;
};

/** SCSI fixed-format sense data */
struct scsi_sns_fixed {
	/** Response code */
	uint8_t code;
	/** Reserved */
	uint8_t reserved;
	/** Sense key */
	uint8_t key;
	/** Information */
	uint32_t info;
	/** Additional sense length */
	uint8_t len;
	/** Command-specific information */
	uint32_t cs_info;
	/** Additional sense code and qualifier */
	uint16_t additional;
} __attribute__ (( packed ));

/** SCSI descriptor-format sense data */
struct scsi_sns_descriptor {
	/** Response code */
	uint8_t code;
	/** Sense key */
	uint8_t key;
	/** Additional sense code and qualifier */
	uint16_t additional;
} __attribute__ (( packed ));

/** SCSI sense data */
union scsi_sns {
	/** Response code */
	uint8_t code;
	/** Fixed-format sense data */
	struct scsi_sns_fixed fixed;
	/** Descriptor-format sense data */
	struct scsi_sns_descriptor desc;
};

/** SCSI sense response code mask */
#define SCSI_SENSE_CODE_MASK 0x7f

/** Test if SCSI sense data is in fixed format
 *
 * @v code		Response code
 * @ret is_fixed	Sense data is in fixed format
 */
#define SCSI_SENSE_FIXED( code ) ( ( (code) & 0x7e ) == 0x70 )

/** SCSI sense key mask */
#define SCSI_SENSE_KEY_MASK 0x0f

/** A SCSI response information unit */
struct scsi_rsp {
	/** SCSI status code */
	uint8_t status;
	/** Data overrun (or negative underrun) */
	ssize_t overrun;
	/** Autosense data (if any)
	 *
	 * To minimise code size, this is stored as the first four
	 * bytes of a descriptor-format sense data block (even if the
	 * response code indicates fixed-format sense data).
	 */
	struct scsi_sns_descriptor sense;
};

extern int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun );
extern void scsi_parse_sense ( const void *data, size_t len,
			       struct scsi_sns_descriptor *sense );

extern int scsi_command ( struct interface *control, struct interface *data,
			  struct scsi_cmd *command );
#define scsi_command_TYPE( object_type )				\
	typeof ( int ( object_type, struct interface *data,		\
		       struct scsi_cmd *command ) )

extern void scsi_response ( struct interface *intf, struct scsi_rsp *response );
#define scsi_response_TYPE( object_type ) \
	typeof ( void ( object_type, struct scsi_rsp *response ) )

extern int scsi_open ( struct interface *block, struct interface *scsi,
		       struct scsi_lun *lun );

#endif /* _IPXE_SCSI_H */