]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiScsiLib/UefiScsiLib.c
a33cadd716462a6c79854c93e58b7bc6f13e07b7
[mirror_edk2.git] / MdePkg / Library / UefiScsiLib / UefiScsiLib.c
1 /** @file
2 UEFI SCSI Library implementation
3
4 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Uefi.h>
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/UefiScsiLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16
17 #include <IndustryStandard/Scsi.h>
18
19 //
20 // Scsi Command Length
21 //
22 #define EFI_SCSI_OP_LENGTH_SIX 0x6
23 #define EFI_SCSI_OP_LENGTH_TEN 0xa
24 #define EFI_SCSI_OP_LENGTH_TWELVE 0xc
25 #define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10
26
27 //
28 // The context structure used when non-blocking SCSI read/write operation
29 // completes.
30 //
31 typedef struct {
32 ///
33 /// The SCSI request packet to send to the SCSI controller specified by
34 /// the device handle.
35 ///
36 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
37 ///
38 /// The length of the output sense data.
39 ///
40 UINT8 *SenseDataLength;
41 ///
42 /// The status of the SCSI host adapter.
43 ///
44 UINT8 *HostAdapterStatus;
45 ///
46 /// The status of the target SCSI device.
47 ///
48 UINT8 *TargetStatus;
49 ///
50 /// The length of the data buffer for the SCSI read/write command.
51 ///
52 UINT32 *DataLength;
53 ///
54 /// The caller event to be signaled when the SCSI read/write command
55 /// completes.
56 ///
57 EFI_EVENT CallerEvent;
58 } EFI_SCSI_LIB_ASYNC_CONTEXT;
59
60 /**
61 Execute Test Unit Ready SCSI command on a specific SCSI target.
62
63 Executes the Test Unit Ready command on the SCSI target specified by ScsiIo.
64 If Timeout is zero, then this function waits indefinitely for the command to complete.
65 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
66 If ScsiIo is NULL, then ASSERT().
67 If SenseDataLength is NULL, then ASSERT().
68 If HostAdapterStatus is NULL, then ASSERT().
69 If TargetStatus is NULL, then ASSERT().
70
71 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
72 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
73 gets returned.
74
75 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
76 for the specific SCSI target.
77 @param[in] Timeout The timeout in 100 ns units to use for the execution
78 of this SCSI Request Packet. A Timeout value of
79 zero means that this function will wait indefinitely
80 for the SCSI Request Packet to execute. If Timeout
81 is greater than zero, then this function will return
82 EFI_TIMEOUT if the time required to execute the SCSI
83 Request Packet is greater than Timeout.
84 @param[in, out] SenseData A pointer to sense data that was generated by
85 the execution of the SCSI Request Packet. This
86 buffer must be allocated by the caller.
87 If SenseDataLength is 0, then this parameter is
88 optional and may be NULL.
89 @param[in, out] SenseDataLength On input, a pointer to the length in bytes of
90 the SenseData buffer. On output, a pointer to
91 the number of bytes written to the SenseData buffer.
92 @param[out] HostAdapterStatus The status of the SCSI Host Controller that produces
93 the SCSI bus containing the SCSI target specified by
94 ScsiIo when the SCSI Request Packet was executed.
95 See the EFI SCSI I/O Protocol in the UEFI Specification
96 for details on the possible return values.
97 @param[out] TargetStatus The status returned by the SCSI target specified
98 by ScsiIo when the SCSI Request Packet was executed
99 on the SCSI Host Controller. See the EFI SCSI I/O
100 Protocol in the UEFI Specification for details on
101 the possible return values.
102
103 @retval EFI_SUCCESS The command was executed successfully.
104 See HostAdapterStatus, TargetStatus, SenseDataLength,
105 and SenseData in that order for additional status
106 information.
107 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
108 there are too many SCSI Command Packets already
109 queued. The SCSI Request Packet was not sent, so
110 no additional status information is available.
111 The caller may retry again later.
112 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
113 SCSI Request Packet. See HostAdapterStatus,
114 TargetStatus, SenseDataLength, and SenseData in that
115 order for additional status information.
116 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
117 is not supported by the SCSI initiator(i.e., SCSI
118 Host Controller). The SCSI Request Packet was not
119 sent, so no additional status information is available.
120 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
121 Packet to execute. See HostAdapterStatus, TargetStatus,
122 SenseDataLength, and SenseData in that order for
123 additional status information.
124 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
125
126 **/
127 EFI_STATUS
128 EFIAPI
129 ScsiTestUnitReadyCommand (
130 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
131 IN UINT64 Timeout,
132 IN OUT VOID *SenseData OPTIONAL,
133 IN OUT UINT8 *SenseDataLength,
134 OUT UINT8 *HostAdapterStatus,
135 OUT UINT8 *TargetStatus
136 )
137 {
138 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
139 EFI_STATUS Status;
140 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
141
142 ASSERT (SenseDataLength != NULL);
143 ASSERT (HostAdapterStatus != NULL);
144 ASSERT (TargetStatus != NULL);
145 ASSERT (ScsiIo != NULL);
146
147 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
148 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
149
150 CommandPacket.Timeout = Timeout;
151 CommandPacket.InDataBuffer = NULL;
152 CommandPacket.InTransferLength = 0;
153 CommandPacket.OutDataBuffer = NULL;
154 CommandPacket.OutTransferLength = 0;
155 CommandPacket.SenseData = SenseData;
156 CommandPacket.Cdb = Cdb;
157 //
158 // Fill Cdb for Test Unit Ready Command
159 //
160 Cdb[0] = EFI_SCSI_OP_TEST_UNIT_READY;
161 CommandPacket.CdbLength = (UINT8)EFI_SCSI_OP_LENGTH_SIX;
162 CommandPacket.SenseDataLength = *SenseDataLength;
163
164 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
165
166 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
167 *TargetStatus = CommandPacket.TargetStatus;
168 *SenseDataLength = CommandPacket.SenseDataLength;
169
170 return Status;
171 }
172
173 /**
174 Execute Inquiry SCSI command on a specific SCSI target.
175
176 Executes the Inquiry command on the SCSI target specified by ScsiIo.
177 If Timeout is zero, then this function waits indefinitely for the command to complete.
178 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
179 If ScsiIo is NULL, then ASSERT().
180 If SenseDataLength is NULL, then ASSERT().
181 If HostAdapterStatus is NULL, then ASSERT().
182 If TargetStatus is NULL, then ASSERT().
183 If InquiryDataLength is NULL, then ASSERT().
184
185 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
186 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
187 gets returned.
188
189 If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer
190 must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
191 EFI_INVALID_PARAMETER gets returned.
192
193 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
194 for the specific SCSI target.
195 @param[in] Timeout The timeout in 100 ns units to use for the
196 execution of this SCSI Request Packet. A Timeout
197 value of zero means that this function will wait
198 indefinitely for the SCSI Request Packet to execute.
199 If Timeout is greater than zero, then this function
200 will return EFI_TIMEOUT if the time required to
201 execute the SCSI Request Packet is greater than Timeout.
202 @param[in, out] SenseData A pointer to sense data that was generated
203 by the execution of the SCSI Request Packet.
204 This buffer must be allocated by the caller.
205 If SenseDataLength is 0, then this parameter
206 is optional and may be NULL.
207 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
208 On output, the number of bytes written to the SenseData buffer.
209 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
210 produces the SCSI bus containing the SCSI
211 target specified by ScsiIo when the SCSI
212 Request Packet was executed. See the EFI
213 SCSI I/O Protocol in the UEFI Specification
214 for details on the possible return values.
215 @param[out] TargetStatus The status returned by the SCSI target specified
216 by ScsiIo when the SCSI Request Packet was
217 executed on the SCSI Host Controller.
218 See the EFI SCSI I/O Protocol in the UEFI
219 Specification for details on the possible
220 return values.
221 @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
222 by the execution of the SCSI Request Packet.
223 This buffer must be allocated by the caller.
224 If InquiryDataLength is 0, then this parameter
225 is optional and may be NULL.
226 @param[in, out] InquiryDataLength On input, a pointer to the length in bytes
227 of the InquiryDataBuffer buffer.
228 On output, a pointer to the number of bytes
229 written to the InquiryDataBuffer buffer.
230 @param[in] EnableVitalProductData If TRUE, then the supported vital product
231 data for the PageCode is returned in InquiryDataBuffer.
232 If FALSE, then the standard inquiry data is
233 returned in InquiryDataBuffer and PageCode is ignored.
234 @param[in] PageCode The page code of the vital product data.
235 It's ignored if EnableVitalProductData is FALSE.
236
237 @retval EFI_SUCCESS The command executed successfully. See HostAdapterStatus,
238 TargetStatus, SenseDataLength, and SenseData in that order
239 for additional status information.
240 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
241 InquiryDataBuffer could not be transferred. The actual
242 number of bytes transferred is returned in InquiryDataLength.
243 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
244 are too many SCSI Command Packets already queued.
245 The SCSI Request Packet was not sent, so no additional
246 status information is available. The caller may retry again later.
247 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
248 Request Packet. See HostAdapterStatus, TargetStatus,
249 SenseDataLength, and SenseData in that order for additional
250 status information.
251 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
252 supported by the SCSI initiator(i.e., SCSI Host Controller).
253 The SCSI Request Packet was not sent, so no additional
254 status information is available.
255 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
256 Packet to execute. See HostAdapterStatus, TargetStatus,
257 SenseDataLength, and SenseData in that order for
258 additional status information.
259 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
260
261 **/
262 EFI_STATUS
263 EFIAPI
264 ScsiInquiryCommandEx (
265 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
266 IN UINT64 Timeout,
267 IN OUT VOID *SenseData OPTIONAL,
268 IN OUT UINT8 *SenseDataLength,
269 OUT UINT8 *HostAdapterStatus,
270 OUT UINT8 *TargetStatus,
271 IN OUT VOID *InquiryDataBuffer OPTIONAL,
272 IN OUT UINT32 *InquiryDataLength,
273 IN BOOLEAN EnableVitalProductData,
274 IN UINT8 PageCode
275 )
276 {
277 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
278 EFI_STATUS Status;
279 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
280
281 ASSERT (SenseDataLength != NULL);
282 ASSERT (HostAdapterStatus != NULL);
283 ASSERT (TargetStatus != NULL);
284 ASSERT (InquiryDataLength != NULL);
285 ASSERT (ScsiIo != NULL);
286
287 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
288 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
289
290 CommandPacket.Timeout = Timeout;
291 CommandPacket.InDataBuffer = InquiryDataBuffer;
292 CommandPacket.InTransferLength = *InquiryDataLength;
293 CommandPacket.SenseData = SenseData;
294 CommandPacket.SenseDataLength = *SenseDataLength;
295 CommandPacket.Cdb = Cdb;
296
297 Cdb[0] = EFI_SCSI_OP_INQUIRY;
298 if (EnableVitalProductData) {
299 Cdb[1] |= 0x01;
300 Cdb[2] = PageCode;
301 }
302
303 if (*InquiryDataLength > 0xff) {
304 *InquiryDataLength = 0xff;
305 }
306
307 Cdb[4] = (UINT8)(*InquiryDataLength);
308 CommandPacket.CdbLength = (UINT8)EFI_SCSI_OP_LENGTH_SIX;
309 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
310
311 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
312
313 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
314 *TargetStatus = CommandPacket.TargetStatus;
315 *SenseDataLength = CommandPacket.SenseDataLength;
316 *InquiryDataLength = CommandPacket.InTransferLength;
317
318 return Status;
319 }
320
321 /**
322 Execute Inquiry SCSI command on a specific SCSI target.
323
324 Executes the Inquiry command on the SCSI target specified by ScsiIo.
325 If Timeout is zero, then this function waits indefinitely for the command to complete.
326 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
327 If ScsiIo is NULL, then ASSERT().
328 If SenseDataLength is NULL, then ASSERT().
329 If HostAdapterStatus is NULL, then ASSERT().
330 If TargetStatus is NULL, then ASSERT().
331 If InquiryDataLength is NULL, then ASSERT().
332
333 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
334 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
335 gets returned.
336
337 If InquiryDataLength is non-zero and InquiryDataBuffer is not NULL, InquiryDataBuffer
338 must meet buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
339 EFI_INVALID_PARAMETER gets returned.
340
341 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
342 for the specific SCSI target.
343 @param[in] Timeout The timeout in 100 ns units to use for the
344 execution of this SCSI Request Packet. A Timeout
345 value of zero means that this function will wait
346 indefinitely for the SCSI Request Packet to execute.
347 If Timeout is greater than zero, then this function
348 will return EFI_TIMEOUT if the time required to
349 execute the SCSI Request Packet is greater than Timeout.
350 @param[in, out] SenseData A pointer to sense data that was generated
351 by the execution of the SCSI Request Packet.
352 This buffer must be allocated by the caller.
353 If SenseDataLength is 0, then this parameter
354 is optional and may be NULL.
355 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
356 On output, the number of bytes written to the SenseData buffer.
357 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
358 produces the SCSI bus containing the SCSI
359 target specified by ScsiIo when the SCSI
360 Request Packet was executed. See the EFI
361 SCSI I/O Protocol in the UEFI Specification
362 for details on the possible return values.
363 @param[out] TargetStatus The status returned by the SCSI target specified
364 by ScsiIo when the SCSI Request Packet was
365 executed on the SCSI Host Controller.
366 See the EFI SCSI I/O Protocol in the UEFI
367 Specification for details on the possible
368 return values.
369 @param[in, out] InquiryDataBuffer A pointer to inquiry data that was generated
370 by the execution of the SCSI Request Packet.
371 This buffer must be allocated by the caller.
372 If InquiryDataLength is 0, then this parameter
373 is optional and may be NULL.
374 @param[in, out] InquiryDataLength On input, a pointer to the length in bytes
375 of the InquiryDataBuffer buffer.
376 On output, a pointer to the number of bytes
377 written to the InquiryDataBuffer buffer.
378 @param[in] EnableVitalProductData If TRUE, then the supported vital product
379 data is returned in InquiryDataBuffer.
380 If FALSE, then the standard inquiry data is
381 returned in InquiryDataBuffer.
382
383 @retval EFI_SUCCESS The command was executed successfully. See HostAdapterStatus,
384 TargetStatus, SenseDataLength, and SenseData in that order
385 for additional status information.
386 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
387 InquiryDataBuffer could not be transferred. The actual
388 number of bytes transferred is returned in InquiryDataLength.
389 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there
390 are too many SCSI Command Packets already queued.
391 The SCSI Request Packet was not sent, so no additional
392 status information is available. The caller may retry again later.
393 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI
394 Request Packet. See HostAdapterStatus, TargetStatus,
395 SenseDataLength, and SenseData in that order for additional
396 status information.
397 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not
398 supported by the SCSI initiator(i.e., SCSI Host Controller).
399 The SCSI Request Packet was not sent, so no additional
400 status information is available.
401 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request
402 Packet to execute. See HostAdapterStatus, TargetStatus,
403 SenseDataLength, and SenseData in that order for
404 additional status information.
405 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
406
407 **/
408 EFI_STATUS
409 EFIAPI
410 ScsiInquiryCommand (
411 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
412 IN UINT64 Timeout,
413 IN OUT VOID *SenseData OPTIONAL,
414 IN OUT UINT8 *SenseDataLength,
415 OUT UINT8 *HostAdapterStatus,
416 OUT UINT8 *TargetStatus,
417 IN OUT VOID *InquiryDataBuffer OPTIONAL,
418 IN OUT UINT32 *InquiryDataLength,
419 IN BOOLEAN EnableVitalProductData
420 )
421 {
422 return ScsiInquiryCommandEx (
423 ScsiIo,
424 Timeout,
425 SenseData,
426 SenseDataLength,
427 HostAdapterStatus,
428 TargetStatus,
429 InquiryDataBuffer,
430 InquiryDataLength,
431 EnableVitalProductData,
432 0
433 );
434 }
435
436 /**
437 Execute Mode Sense(10) SCSI command on a specific SCSI target.
438
439 Executes the SCSI Mode Sense(10) command on the SCSI target specified by ScsiIo.
440 If Timeout is zero, then this function waits indefinitely for the command to complete.
441 If Timeout is greater than zero, then the command is executed and will timeout
442 after Timeout 100 ns units. The DBDField, PageControl, and PageCode parameters
443 are used to construct the CDB for this SCSI command.
444 If ScsiIo is NULL, then ASSERT().
445 If SenseDataLength is NULL, then ASSERT().
446 If HostAdapterStatus is NULL, then ASSERT().
447 If TargetStatus is NULL, then ASSERT().
448 If DataLength is NULL, then ASSERT().
449
450 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
451 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
452 gets returned.
453
454 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
455 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
456 gets returned.
457
458 @param[in] ScsiIo A pointer to the SCSI I/O Protocol instance
459 for the specific SCSI target.
460 @param[in] Timeout The timeout in 100 ns units to use for the
461 execution of this SCSI Request Packet. A Timeout
462 value of zero means that this function will wait
463 indefinitely for the SCSI Request Packet to execute.
464 If Timeout is greater than zero, then this function
465 will return EFI_TIMEOUT if the time required to
466 execute the SCSI Request Packet is greater than Timeout.
467 @param[in, out] SenseData A pointer to sense data that was generated
468 by the execution of the SCSI Request Packet.
469 This buffer must be allocated by the caller.
470 If SenseDataLength is 0, then this parameter
471 is optional and may be NULL.
472 @param[in, out] SenseDataLength On input, the length in bytes of the SenseData buffer.
473 On output, the number of bytes written to the SenseData buffer.
474 @param[out] HostAdapterStatus The status of the SCSI Host Controller that
475 produces the SCSI bus containing the SCSI target
476 specified by ScsiIo when the SCSI Request Packet
477 was executed. See the EFI SCSI I/O Protocol in the
478 UEFI Specification for details on the possible
479 return values.
480 @param[out] TargetStatus The status returned by the SCSI target specified
481 by ScsiIo when the SCSI Request Packet was executed
482 on the SCSI Host Controller. See the EFI SCSI
483 I/O Protocol in the UEFI Specification for details
484 on the possible return values.
485 @param[in, out] DataBuffer A pointer to data that was generated by the
486 execution of the SCSI Request Packet. This
487 buffer must be allocated by the caller. If
488 DataLength is 0, then this parameter is optional
489 and may be NULL.
490 @param[in, out] DataLength On input, a pointer to the length in bytes of
491 the DataBuffer buffer. On output, a pointer
492 to the number of bytes written to the DataBuffer
493 buffer.
494 @param[in] DBDField Specifies the DBD field of the CDB for this SCSI Command.
495 @param[in] PageControl Specifies the PC field of the CDB for this SCSI Command.
496 @param[in] PageCode Specifies the Page Control field of the CDB for this SCSI Command.
497
498 @retval EFI_SUCCESS The command was executed successfully.
499 See HostAdapterStatus, TargetStatus, SenseDataLength,
500 and SenseData in that order for additional status information.
501 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the
502 entire DataBuffer could not be transferred.
503 The actual number of bytes transferred is returned
504 in DataLength.
505 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
506 there are too many SCSI Command Packets already queued.
507 The SCSI Request Packet was not sent, so no additional
508 status information is available. The caller may retry
509 again later.
510 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
511 SCSI Request Packet. See HostAdapterStatus, TargetStatus,
512 SenseDataLength, and SenseData in that order for
513 additional status information.
514 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
515 is not supported by the SCSI initiator(i.e., SCSI
516 Host Controller). The SCSI Request Packet was not
517 sent, so no additional status information is available.
518 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
519 Request Packet to execute. See HostAdapterStatus,
520 TargetStatus, SenseDataLength, and SenseData in that
521 order for additional status information.
522 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
523
524 **/
525 EFI_STATUS
526 EFIAPI
527 ScsiModeSense10Command (
528 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
529 IN UINT64 Timeout,
530 IN OUT VOID *SenseData OPTIONAL,
531 IN OUT UINT8 *SenseDataLength,
532 OUT UINT8 *HostAdapterStatus,
533 OUT UINT8 *TargetStatus,
534 IN OUT VOID *DataBuffer OPTIONAL,
535 IN OUT UINT32 *DataLength,
536 IN UINT8 DBDField OPTIONAL,
537 IN UINT8 PageControl,
538 IN UINT8 PageCode
539 )
540 {
541 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
542 EFI_STATUS Status;
543 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
544
545 ASSERT (SenseDataLength != NULL);
546 ASSERT (HostAdapterStatus != NULL);
547 ASSERT (TargetStatus != NULL);
548 ASSERT (DataLength != NULL);
549 ASSERT (ScsiIo != NULL);
550
551 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
552 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
553
554 CommandPacket.Timeout = Timeout;
555 CommandPacket.InDataBuffer = DataBuffer;
556 CommandPacket.SenseData = SenseData;
557 CommandPacket.InTransferLength = *DataLength;
558 CommandPacket.Cdb = Cdb;
559 //
560 // Fill Cdb for Mode Sense (10) Command
561 //
562 Cdb[0] = EFI_SCSI_OP_MODE_SEN10;
563 //
564 // DBDField is in Cdb[1] bit3 of (bit7..0)
565 //
566 Cdb[1] = (UINT8)((DBDField << 3) & 0x08);
567 //
568 // PageControl is in Cdb[2] bit7..6, PageCode is in Cdb[2] bit5..0
569 //
570 Cdb[2] = (UINT8)(((PageControl << 6) & 0xc0) | (PageCode & 0x3f));
571 Cdb[7] = (UINT8)(*DataLength >> 8);
572 Cdb[8] = (UINT8)(*DataLength);
573
574 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
575 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
576 CommandPacket.SenseDataLength = *SenseDataLength;
577
578 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
579
580 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
581 *TargetStatus = CommandPacket.TargetStatus;
582 *SenseDataLength = CommandPacket.SenseDataLength;
583 *DataLength = CommandPacket.InTransferLength;
584
585 return Status;
586 }
587
588 /**
589 Execute Request Sense SCSI command on a specific SCSI target.
590
591 Executes the Request Sense command on the SCSI target specified by ScsiIo.
592 If Timeout is zero, then this function waits indefinitely for the command to complete.
593 If Timeout is greater than zero, then the command is executed and will timeout after Timeout 100 ns units.
594 If ScsiIo is NULL, then ASSERT().
595 If SenseDataLength is NULL, then ASSERT().
596 If HostAdapterStatus is NULL, then ASSERT().
597 If TargetStatus is NULL, then ASSERT().
598
599 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
600 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
601 gets returned.
602
603 @param[in] ScsiIo A pointer to SCSI IO protocol.
604 @param[in] Timeout The length of timeout period.
605 @param[in, out] SenseData A pointer to output sense data.
606 @param[in, out] SenseDataLength The length of output sense data.
607 @param[out] HostAdapterStatus The status of Host Adapter.
608 @param[out] TargetStatus The status of the target.
609
610 @retval EFI_SUCCESS Command is executed successfully.
611 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are
612 too many SCSI Command Packets already queued.
613 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
614 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
615 the SCSI initiator(i.e., SCSI Host Controller)
616 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
617 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
618
619 **/
620 EFI_STATUS
621 EFIAPI
622 ScsiRequestSenseCommand (
623 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
624 IN UINT64 Timeout,
625 IN OUT VOID *SenseData OPTIONAL,
626 IN OUT UINT8 *SenseDataLength,
627 OUT UINT8 *HostAdapterStatus,
628 OUT UINT8 *TargetStatus
629 )
630 {
631 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
632 EFI_STATUS Status;
633 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
634
635 ASSERT (SenseDataLength != NULL);
636 ASSERT (HostAdapterStatus != NULL);
637 ASSERT (TargetStatus != NULL);
638 ASSERT (ScsiIo != NULL);
639
640 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
641 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
642
643 CommandPacket.Timeout = Timeout;
644 CommandPacket.InDataBuffer = SenseData;
645 CommandPacket.SenseData = NULL;
646 CommandPacket.InTransferLength = *SenseDataLength;
647 CommandPacket.Cdb = Cdb;
648 //
649 // Fill Cdb for Request Sense Command
650 //
651 Cdb[0] = EFI_SCSI_OP_REQUEST_SENSE;
652 Cdb[4] = (UINT8)(*SenseDataLength);
653
654 CommandPacket.CdbLength = (UINT8)EFI_SCSI_OP_LENGTH_SIX;
655 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
656 CommandPacket.SenseDataLength = 0;
657
658 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
659
660 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
661 *TargetStatus = CommandPacket.TargetStatus;
662 *SenseDataLength = (UINT8)CommandPacket.InTransferLength;
663
664 return Status;
665 }
666
667 /**
668 Execute Read Capacity SCSI command on a specific SCSI target.
669
670 Executes the SCSI Read Capacity command on the SCSI target specified by ScsiIo.
671 If Timeout is zero, then this function waits indefinitely for the command to complete.
672 If Timeout is greater than zero, then the command is executed and will timeout after
673 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
674 If ScsiIo is NULL, then ASSERT().
675 If SenseDataLength is NULL, then ASSERT().
676 If HostAdapterStatus is NULL, then ASSERT().
677 If TargetStatus is NULL, then ASSERT().
678 If DataLength is NULL, then ASSERT().
679
680 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
681 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
682 gets returned.
683
684 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
685 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
686 gets returned.
687
688 @param[in] ScsiIo A pointer to SCSI IO protocol.
689 @param[in] Timeout The length of timeout period.
690 @param[in, out] SenseData A pointer to output sense data.
691 @param[in, out] SenseDataLength The length of output sense data.
692 @param[out] HostAdapterStatus The status of Host Adapter.
693 @param[out] TargetStatus The status of the target.
694 @param[in, out] DataBuffer A pointer to a data buffer.
695 @param[in, out] DataLength The length of data buffer.
696 @param[in] Pmi Partial medium indicator.
697
698 @retval EFI_SUCCESS Command is executed successfully.
699 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
700 DataBuffer could not be transferred. The actual
701 number of bytes transferred is returned in DataLength.
702 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
703 there are too many SCSI Command Packets already queued.
704 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
705 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
706 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
707 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
708 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
709
710 **/
711 EFI_STATUS
712 EFIAPI
713 ScsiReadCapacityCommand (
714 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
715 IN UINT64 Timeout,
716 IN OUT VOID *SenseData OPTIONAL,
717 IN OUT UINT8 *SenseDataLength,
718 OUT UINT8 *HostAdapterStatus,
719 OUT UINT8 *TargetStatus,
720 IN OUT VOID *DataBuffer OPTIONAL,
721 IN OUT UINT32 *DataLength,
722 IN BOOLEAN Pmi
723 )
724 {
725 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
726 EFI_STATUS Status;
727 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
728
729 ASSERT (SenseDataLength != NULL);
730 ASSERT (HostAdapterStatus != NULL);
731 ASSERT (TargetStatus != NULL);
732 ASSERT (DataLength != NULL);
733 ASSERT (ScsiIo != NULL);
734
735 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
736 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
737
738 CommandPacket.Timeout = Timeout;
739 CommandPacket.InDataBuffer = DataBuffer;
740 CommandPacket.SenseData = SenseData;
741 CommandPacket.InTransferLength = *DataLength;
742 CommandPacket.Cdb = Cdb;
743 //
744 // Fill Cdb for Read Capacity Command
745 //
746 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
747 if (!Pmi) {
748 //
749 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.5 MUST BE ZERO.
750 //
751 ZeroMem ((Cdb + 2), 4);
752 } else {
753 Cdb[8] |= 0x01;
754 }
755
756 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
757 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
758 CommandPacket.SenseDataLength = *SenseDataLength;
759
760 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
761
762 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
763 *TargetStatus = CommandPacket.TargetStatus;
764 *SenseDataLength = CommandPacket.SenseDataLength;
765 *DataLength = CommandPacket.InTransferLength;
766
767 return Status;
768 }
769
770 /**
771 Execute Read Capacity SCSI 16 command on a specific SCSI target.
772
773 Executes the SCSI Read Capacity 16 command on the SCSI target specified by ScsiIo.
774 If Timeout is zero, then this function waits indefinitely for the command to complete.
775 If Timeout is greater than zero, then the command is executed and will timeout after
776 Timeout 100 ns units. The Pmi parameter is used to construct the CDB for this SCSI command.
777 If ScsiIo is NULL, then ASSERT().
778 If SenseDataLength is NULL, then ASSERT().
779 If HostAdapterStatus is NULL, then ASSERT().
780 If TargetStatus is NULL, then ASSERT().
781 If DataLength is NULL, then ASSERT().
782
783 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
784 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
785 gets returned.
786
787 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
788 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
789 gets returned.
790
791 @param[in] ScsiIo A pointer to SCSI IO protocol.
792 @param[in] Timeout The length of timeout period.
793 @param[in, out] SenseData A pointer to output sense data.
794 @param[in, out] SenseDataLength The length of output sense data.
795 @param[out] HostAdapterStatus The status of Host Adapter.
796 @param[out] TargetStatus The status of the target.
797 @param[in, out] DataBuffer A pointer to a data buffer.
798 @param[in, out] DataLength The length of data buffer.
799 @param[in] Pmi Partial medium indicator.
800
801 @retval EFI_SUCCESS Command is executed successfully.
802 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire
803 DataBuffer could not be transferred. The actual
804 number of bytes transferred is returned in DataLength.
805 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
806 there are too many SCSI Command Packets already queued.
807 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
808 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
809 is not supported by the SCSI initiator(i.e., SCSI Host Controller)
810 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
811 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
812
813 **/
814 EFI_STATUS
815 EFIAPI
816 ScsiReadCapacity16Command (
817 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
818 IN UINT64 Timeout,
819 IN OUT VOID *SenseData OPTIONAL,
820 IN OUT UINT8 *SenseDataLength,
821 OUT UINT8 *HostAdapterStatus,
822 OUT UINT8 *TargetStatus,
823 IN OUT VOID *DataBuffer OPTIONAL,
824 IN OUT UINT32 *DataLength,
825 IN BOOLEAN Pmi
826 )
827 {
828 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
829 EFI_STATUS Status;
830 UINT8 Cdb[16];
831
832 ASSERT (SenseDataLength != NULL);
833 ASSERT (HostAdapterStatus != NULL);
834 ASSERT (TargetStatus != NULL);
835 ASSERT (DataLength != NULL);
836 ASSERT (ScsiIo != NULL);
837
838 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
839 ZeroMem (Cdb, 16);
840
841 CommandPacket.Timeout = Timeout;
842 CommandPacket.InDataBuffer = DataBuffer;
843 CommandPacket.SenseData = SenseData;
844 CommandPacket.InTransferLength = *DataLength;
845 CommandPacket.Cdb = Cdb;
846 //
847 // Fill Cdb for Read Capacity Command
848 //
849 Cdb[0] = EFI_SCSI_OP_READ_CAPACITY16;
850 Cdb[1] = 0x10;
851 if (!Pmi) {
852 //
853 // Partial medium indicator,if Pmi is FALSE, the Cdb.2 ~ Cdb.9 MUST BE ZERO.
854 //
855 ZeroMem ((Cdb + 2), 8);
856 } else {
857 Cdb[14] |= 0x01;
858 }
859
860 Cdb[13] = 0x20;
861 CommandPacket.CdbLength = 16;
862 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
863 CommandPacket.SenseDataLength = *SenseDataLength;
864
865 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
866
867 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
868 *TargetStatus = CommandPacket.TargetStatus;
869 *SenseDataLength = CommandPacket.SenseDataLength;
870 *DataLength = CommandPacket.InTransferLength;
871
872 return Status;
873 }
874
875 /**
876 Execute Read(10) SCSI command on a specific SCSI target.
877
878 Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
879 If Timeout is zero, then this function waits indefinitely for the command to complete.
880 If Timeout is greater than zero, then the command is executed and will timeout
881 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
882 construct the CDB for this SCSI command.
883 If ScsiIo is NULL, then ASSERT().
884 If SenseDataLength is NULL, then ASSERT().
885 If HostAdapterStatus is NULL, then ASSERT().
886 If TargetStatus is NULL, then ASSERT().
887 If DataLength is NULL, then ASSERT().
888
889 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
890 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
891 gets returned.
892
893 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
894 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
895 gets returned.
896
897 @param[in] ScsiIo A pointer to SCSI IO protocol.
898 @param[in] Timeout The length of timeout period.
899 @param[in, out] SenseData A pointer to output sense data.
900 @param[in, out] SenseDataLength The length of output sense data.
901 @param[out] HostAdapterStatus The status of Host Adapter.
902 @param[out] TargetStatus The status of the target.
903 @param[in, out] DataBuffer Read 10 command data.
904 @param[in, out] DataLength The length of data buffer.
905 @param[in] StartLba The start address of LBA.
906 @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
907
908 @retval EFI_SUCCESS Command is executed successfully.
909 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
910 not be transferred. The actual number of bytes transferred is returned in DataLength.
911 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
912 SCSI Command Packets already queued.
913 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
914 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
915 the SCSI initiator(i.e., SCSI Host Controller)
916 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
917 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
918
919 **/
920 EFI_STATUS
921 EFIAPI
922 ScsiRead10Command (
923 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
924 IN UINT64 Timeout,
925 IN OUT VOID *SenseData OPTIONAL,
926 IN OUT UINT8 *SenseDataLength,
927 OUT UINT8 *HostAdapterStatus,
928 OUT UINT8 *TargetStatus,
929 IN OUT VOID *DataBuffer OPTIONAL,
930 IN OUT UINT32 *DataLength,
931 IN UINT32 StartLba,
932 IN UINT32 SectorSize
933 )
934 {
935 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
936 EFI_STATUS Status;
937 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
938
939 ASSERT (SenseDataLength != NULL);
940 ASSERT (HostAdapterStatus != NULL);
941 ASSERT (TargetStatus != NULL);
942 ASSERT (DataLength != NULL);
943 ASSERT (ScsiIo != NULL);
944
945 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
946 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
947
948 CommandPacket.Timeout = Timeout;
949 CommandPacket.InDataBuffer = DataBuffer;
950 CommandPacket.SenseData = SenseData;
951 CommandPacket.InTransferLength = *DataLength;
952 CommandPacket.Cdb = Cdb;
953 //
954 // Fill Cdb for Read (10) Command
955 //
956 Cdb[0] = EFI_SCSI_OP_READ10;
957 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
958 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16)SectorSize));
959
960 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
961 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
962 CommandPacket.SenseDataLength = *SenseDataLength;
963
964 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
965
966 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
967 *TargetStatus = CommandPacket.TargetStatus;
968 *SenseDataLength = CommandPacket.SenseDataLength;
969 *DataLength = CommandPacket.InTransferLength;
970
971 return Status;
972 }
973
974 /**
975 Execute Write(10) SCSI command on a specific SCSI target.
976
977 Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
978 If Timeout is zero, then this function waits indefinitely for the command to complete.
979 If Timeout is greater than zero, then the command is executed and will timeout after
980 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
981 the CDB for this SCSI command.
982 If ScsiIo is NULL, then ASSERT().
983 If SenseDataLength is NULL, then ASSERT().
984 If HostAdapterStatus is NULL, then ASSERT().
985 If TargetStatus is NULL, then ASSERT().
986 If DataLength is NULL, then ASSERT().
987
988 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
989 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
990 gets returned.
991
992 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
993 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
994 gets returned.
995
996 @param[in] ScsiIo SCSI IO Protocol to use
997 @param[in] Timeout The length of timeout period.
998 @param[in, out] SenseData A pointer to output sense data.
999 @param[in, out] SenseDataLength The length of output sense data.
1000 @param[out] HostAdapterStatus The status of Host Adapter.
1001 @param[out] TargetStatus The status of the target.
1002 @param[in, out] DataBuffer A pointer to a data buffer.
1003 @param[in, out] DataLength The length of data buffer.
1004 @param[in] StartLba The start address of LBA.
1005 @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
1006
1007 @retval EFI_SUCCESS Command is executed successfully.
1008 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1009 not be transferred. The actual number of bytes transferred is returned in DataLength.
1010 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1011 SCSI Command Packets already queued.
1012 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1013 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1014 the SCSI initiator(i.e., SCSI Host Controller)
1015 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1016 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
1017
1018 **/
1019 EFI_STATUS
1020 EFIAPI
1021 ScsiWrite10Command (
1022 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1023 IN UINT64 Timeout,
1024 IN OUT VOID *SenseData OPTIONAL,
1025 IN OUT UINT8 *SenseDataLength,
1026 OUT UINT8 *HostAdapterStatus,
1027 OUT UINT8 *TargetStatus,
1028 IN OUT VOID *DataBuffer OPTIONAL,
1029 IN OUT UINT32 *DataLength,
1030 IN UINT32 StartLba,
1031 IN UINT32 SectorSize
1032 )
1033 {
1034 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1035 EFI_STATUS Status;
1036 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TEN];
1037
1038 ASSERT (SenseDataLength != NULL);
1039 ASSERT (HostAdapterStatus != NULL);
1040 ASSERT (TargetStatus != NULL);
1041 ASSERT (DataLength != NULL);
1042 ASSERT (ScsiIo != NULL);
1043
1044 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1045 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TEN);
1046
1047 CommandPacket.Timeout = Timeout;
1048 CommandPacket.OutDataBuffer = DataBuffer;
1049 CommandPacket.SenseData = SenseData;
1050 CommandPacket.OutTransferLength = *DataLength;
1051 CommandPacket.Cdb = Cdb;
1052 //
1053 // Fill Cdb for Write (10) Command
1054 //
1055 Cdb[0] = EFI_SCSI_OP_WRITE10;
1056 Cdb[1] = EFI_SCSI_BLOCK_FUA;
1057 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
1058 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16)SectorSize));
1059
1060 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TEN;
1061 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
1062 CommandPacket.SenseDataLength = *SenseDataLength;
1063
1064 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1065
1066 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1067 *TargetStatus = CommandPacket.TargetStatus;
1068 *SenseDataLength = CommandPacket.SenseDataLength;
1069 *DataLength = CommandPacket.OutTransferLength;
1070
1071 return Status;
1072 }
1073
1074 /**
1075 Execute Read(16) SCSI command on a specific SCSI target.
1076
1077 Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.
1078 If Timeout is zero, then this function waits indefinitely for the command to complete.
1079 If Timeout is greater than zero, then the command is executed and will timeout
1080 after Timeout 100 ns units. The StartLba and SectorSize parameters are used to
1081 construct the CDB for this SCSI command.
1082 If ScsiIo is NULL, then ASSERT().
1083 If SenseDataLength is NULL, then ASSERT().
1084 If HostAdapterStatus is NULL, then ASSERT().
1085 If TargetStatus is NULL, then ASSERT().
1086 If DataLength is NULL, then ASSERT().
1087
1088 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
1089 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1090 gets returned.
1091
1092 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
1093 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1094 gets returned.
1095
1096 @param[in] ScsiIo A pointer to SCSI IO protocol.
1097 @param[in] Timeout The length of timeout period.
1098 @param[in, out] SenseData A pointer to output sense data.
1099 @param[in, out] SenseDataLength The length of output sense data.
1100 @param[out] HostAdapterStatus The status of Host Adapter.
1101 @param[out] TargetStatus The status of the target.
1102 @param[in, out] DataBuffer Read 16 command data.
1103 @param[in, out] DataLength The length of data buffer.
1104 @param[in] StartLba The start address of LBA.
1105 @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
1106
1107 @retval EFI_SUCCESS Command is executed successfully.
1108 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1109 not be transferred. The actual number of bytes transferred is returned in DataLength.
1110 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1111 SCSI Command Packets already queued.
1112 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1113 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1114 the SCSI initiator(i.e., SCSI Host Controller)
1115 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1116 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
1117
1118 **/
1119 EFI_STATUS
1120 EFIAPI
1121 ScsiRead16Command (
1122 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1123 IN UINT64 Timeout,
1124 IN OUT VOID *SenseData OPTIONAL,
1125 IN OUT UINT8 *SenseDataLength,
1126 OUT UINT8 *HostAdapterStatus,
1127 OUT UINT8 *TargetStatus,
1128 IN OUT VOID *DataBuffer OPTIONAL,
1129 IN OUT UINT32 *DataLength,
1130 IN UINT64 StartLba,
1131 IN UINT32 SectorSize
1132 )
1133 {
1134 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1135 EFI_STATUS Status;
1136 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
1137
1138 ASSERT (SenseDataLength != NULL);
1139 ASSERT (HostAdapterStatus != NULL);
1140 ASSERT (TargetStatus != NULL);
1141 ASSERT (DataLength != NULL);
1142 ASSERT (ScsiIo != NULL);
1143
1144 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1145 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
1146
1147 CommandPacket.Timeout = Timeout;
1148 CommandPacket.InDataBuffer = DataBuffer;
1149 CommandPacket.SenseData = SenseData;
1150 CommandPacket.InTransferLength = *DataLength;
1151 CommandPacket.Cdb = Cdb;
1152 //
1153 // Fill Cdb for Read (16) Command
1154 //
1155 Cdb[0] = EFI_SCSI_OP_READ16;
1156 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
1157 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
1158
1159 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
1160 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
1161 CommandPacket.SenseDataLength = *SenseDataLength;
1162
1163 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1164
1165 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1166 *TargetStatus = CommandPacket.TargetStatus;
1167 *SenseDataLength = CommandPacket.SenseDataLength;
1168 *DataLength = CommandPacket.InTransferLength;
1169
1170 return Status;
1171 }
1172
1173 /**
1174 Execute Write(16) SCSI command on a specific SCSI target.
1175
1176 Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.
1177 If Timeout is zero, then this function waits indefinitely for the command to complete.
1178 If Timeout is greater than zero, then the command is executed and will timeout after
1179 Timeout 100 ns units. The StartLba and SectorSize parameters are used to construct
1180 the CDB for this SCSI command.
1181 If ScsiIo is NULL, then ASSERT().
1182 If SenseDataLength is NULL, then ASSERT().
1183 If HostAdapterStatus is NULL, then ASSERT().
1184 If TargetStatus is NULL, then ASSERT().
1185 If DataLength is NULL, then ASSERT().
1186
1187 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
1188 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1189 gets returned.
1190
1191 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
1192 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1193 gets returned.
1194
1195 @param[in] ScsiIo SCSI IO Protocol to use
1196 @param[in] Timeout The length of timeout period.
1197 @param[in, out] SenseData A pointer to output sense data.
1198 @param[in, out] SenseDataLength The length of output sense data.
1199 @param[out] HostAdapterStatus The status of Host Adapter.
1200 @param[out] TargetStatus The status of the target.
1201 @param[in, out] DataBuffer A pointer to a data buffer.
1202 @param[in, out] DataLength The length of data buffer.
1203 @param[in] StartLba The start address of LBA.
1204 @param[in] SectorSize The number of contiguous logical blocks of data that shall be transferred.
1205
1206 @retval EFI_SUCCESS Command is executed successfully.
1207 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1208 not be transferred. The actual number of bytes transferred is returned in DataLength.
1209 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1210 SCSI Command Packets already queued.
1211 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1212 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1213 the SCSI initiator(i.e., SCSI Host Controller)
1214 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1215 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
1216
1217 **/
1218 EFI_STATUS
1219 EFIAPI
1220 ScsiWrite16Command (
1221 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1222 IN UINT64 Timeout,
1223 IN OUT VOID *SenseData OPTIONAL,
1224 IN OUT UINT8 *SenseDataLength,
1225 OUT UINT8 *HostAdapterStatus,
1226 OUT UINT8 *TargetStatus,
1227 IN OUT VOID *DataBuffer OPTIONAL,
1228 IN OUT UINT32 *DataLength,
1229 IN UINT64 StartLba,
1230 IN UINT32 SectorSize
1231 )
1232 {
1233 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1234 EFI_STATUS Status;
1235 UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIXTEEN];
1236
1237 ASSERT (SenseDataLength != NULL);
1238 ASSERT (HostAdapterStatus != NULL);
1239 ASSERT (TargetStatus != NULL);
1240 ASSERT (DataLength != NULL);
1241 ASSERT (ScsiIo != NULL);
1242
1243 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1244 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIXTEEN);
1245
1246 CommandPacket.Timeout = Timeout;
1247 CommandPacket.OutDataBuffer = DataBuffer;
1248 CommandPacket.SenseData = SenseData;
1249 CommandPacket.OutTransferLength = *DataLength;
1250 CommandPacket.Cdb = Cdb;
1251 //
1252 // Fill Cdb for Write (16) Command
1253 //
1254 Cdb[0] = EFI_SCSI_OP_WRITE16;
1255 Cdb[1] = EFI_SCSI_BLOCK_FUA;
1256 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
1257 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
1258
1259 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
1260 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
1261 CommandPacket.SenseDataLength = *SenseDataLength;
1262
1263 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1264
1265 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1266 *TargetStatus = CommandPacket.TargetStatus;
1267 *SenseDataLength = CommandPacket.SenseDataLength;
1268 *DataLength = CommandPacket.OutTransferLength;
1269
1270 return Status;
1271 }
1272
1273 /**
1274 Execute Security Protocol In SCSI command on a specific SCSI target.
1275
1276 Executes the SCSI Security Protocol In command on the SCSI target specified by ScsiIo.
1277 If Timeout is zero, then this function waits indefinitely for the command to complete.
1278 If Timeout is greater than zero, then the command is executed and will timeout after
1279 Timeout 100 ns units.
1280 If ScsiIo is NULL, then ASSERT().
1281 If SenseDataLength is NULL, then ASSERT().
1282 If HostAdapterStatus is NULL, then ASSERT().
1283 If TargetStatus is NULL, then ASSERT().
1284 If TransferLength is NULL, then ASSERT().
1285
1286 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
1287 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1288 gets returned.
1289
1290 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
1291 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1292 gets returned.
1293
1294 @param[in] ScsiIo SCSI IO Protocol to use.
1295 @param[in] Timeout The length of timeout period.
1296 @param[in, out] SenseData A pointer to output sense data.
1297 @param[in, out] SenseDataLength The length of output sense data.
1298 @param[out] HostAdapterStatus The status of Host Adapter.
1299 @param[out] TargetStatus The status of the target.
1300 @param[in] SecurityProtocol The Security Protocol to use.
1301 @param[in] SecurityProtocolSpecific The Security Protocol Specific data.
1302 @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the
1303 SECURITY PROTOCOL IN command.
1304 @param[in] DataLength The size in bytes of the data buffer.
1305 @param[in, out] DataBuffer A pointer to a data buffer.
1306 @param[out] TransferLength A pointer to a buffer to store the size in
1307 bytes of the data written to the data buffer.
1308
1309 @retval EFI_SUCCESS Command is executed successfully.
1310 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1311 not be transferred. The actual number of bytes transferred is returned in TransferLength.
1312 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1313 SCSI Command Packets already queued.
1314 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1315 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1316 the SCSI initiator(i.e., SCSI Host Controller)
1317 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1318 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
1319
1320 **/
1321 EFI_STATUS
1322 EFIAPI
1323 ScsiSecurityProtocolInCommand (
1324 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1325 IN UINT64 Timeout,
1326 IN OUT VOID *SenseData OPTIONAL,
1327 IN OUT UINT8 *SenseDataLength,
1328 OUT UINT8 *HostAdapterStatus,
1329 OUT UINT8 *TargetStatus,
1330 IN UINT8 SecurityProtocol,
1331 IN UINT16 SecurityProtocolSpecific,
1332 IN BOOLEAN Inc512,
1333 IN UINTN DataLength,
1334 IN OUT VOID *DataBuffer OPTIONAL,
1335 OUT UINTN *TransferLength
1336 )
1337 {
1338 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1339 EFI_STATUS Status;
1340 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE];
1341
1342 ASSERT (SenseDataLength != NULL);
1343 ASSERT (HostAdapterStatus != NULL);
1344 ASSERT (TargetStatus != NULL);
1345 ASSERT (ScsiIo != NULL);
1346 ASSERT (TransferLength != NULL);
1347 ASSERT (DataLength <= MAX_UINT32);
1348
1349 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1350 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE);
1351
1352 CommandPacket.Timeout = Timeout;
1353 CommandPacket.InDataBuffer = DataBuffer;
1354 CommandPacket.SenseData = SenseData;
1355 CommandPacket.InTransferLength = (UINT32)DataLength;
1356 CommandPacket.Cdb = Cdb;
1357 //
1358 // Fill Cdb for Security Protocol In Command
1359 //
1360 Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_IN;
1361 Cdb[1] = SecurityProtocol;
1362 WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific));
1363
1364 if (Inc512) {
1365 if (DataLength % 512 != 0) {
1366 return EFI_INVALID_PARAMETER;
1367 }
1368
1369 Cdb[4] = BIT7;
1370 WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32)DataLength / 512));
1371 } else {
1372 WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32)DataLength));
1373 }
1374
1375 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE;
1376 CommandPacket.DataDirection = EFI_SCSI_DATA_IN;
1377 CommandPacket.SenseDataLength = *SenseDataLength;
1378
1379 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1380
1381 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1382 *TargetStatus = CommandPacket.TargetStatus;
1383 *SenseDataLength = CommandPacket.SenseDataLength;
1384 *TransferLength = (UINTN)CommandPacket.InTransferLength;
1385
1386 return Status;
1387 }
1388
1389 /**
1390 Execute Security Protocol Out SCSI command on a specific SCSI target.
1391
1392 Executes the SCSI Security Protocol Out command on the SCSI target specified by ScsiIo.
1393 If Timeout is zero, then this function waits indefinitely for the command to complete.
1394 If Timeout is greater than zero, then the command is executed and will timeout after
1395 Timeout 100 ns units.
1396 If ScsiIo is NULL, then ASSERT().
1397 If SenseDataLength is NULL, then ASSERT().
1398 If HostAdapterStatus is NULL, then ASSERT().
1399 If TargetStatus is NULL, then ASSERT().
1400
1401 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet buffer
1402 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1403 gets returned.
1404
1405 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet buffer
1406 alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise EFI_INVALID_PARAMETER
1407 gets returned.
1408
1409 @param[in] ScsiIo SCSI IO Protocol to use.
1410 @param[in] Timeout The length of timeout period.
1411 @param[in, out] SenseData A pointer to output sense data.
1412 @param[in, out] SenseDataLength The length of output sense data.
1413 @param[out] HostAdapterStatus The status of Host Adapter.
1414 @param[out] TargetStatus The status of the target.
1415 @param[in] SecurityProtocol The Security Protocol to use.
1416 @param[in] SecurityProtocolSpecific The Security Protocol Specific data.
1417 @param[in] Inc512 If TRUE, 512 increment (INC_512) bit will be set for the
1418 SECURITY PROTOCOL OUT command.
1419 @param[in] DataLength The size in bytes of the transfer data.
1420 @param[in, out] DataBuffer A pointer to a data buffer.
1421
1422 @retval EFI_SUCCESS Command is executed successfully.
1423 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, but the entire DataBuffer could
1424 not be transferred. The actual number of bytes transferred is returned in DataLength.
1425 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because there are too many
1426 SCSI Command Packets already queued.
1427 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
1428 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet is not supported by
1429 the SCSI initiator(i.e., SCSI Host Controller)
1430 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1431 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet are invalid.
1432
1433 **/
1434 EFI_STATUS
1435 EFIAPI
1436 ScsiSecurityProtocolOutCommand (
1437 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1438 IN UINT64 Timeout,
1439 IN OUT VOID *SenseData OPTIONAL,
1440 IN OUT UINT8 *SenseDataLength,
1441 OUT UINT8 *HostAdapterStatus,
1442 OUT UINT8 *TargetStatus,
1443 IN UINT8 SecurityProtocol,
1444 IN UINT16 SecurityProtocolSpecific,
1445 IN BOOLEAN Inc512,
1446 IN UINTN DataLength,
1447 IN OUT VOID *DataBuffer OPTIONAL
1448 )
1449 {
1450 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
1451 EFI_STATUS Status;
1452 UINT8 Cdb[EFI_SCSI_OP_LENGTH_TWELVE];
1453
1454 ASSERT (SenseDataLength != NULL);
1455 ASSERT (HostAdapterStatus != NULL);
1456 ASSERT (TargetStatus != NULL);
1457 ASSERT (ScsiIo != NULL);
1458 ASSERT (DataLength <= MAX_UINT32);
1459
1460 ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
1461 ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_TWELVE);
1462
1463 CommandPacket.Timeout = Timeout;
1464 CommandPacket.OutDataBuffer = DataBuffer;
1465 CommandPacket.SenseData = SenseData;
1466 CommandPacket.OutTransferLength = (UINT32)DataLength;
1467 CommandPacket.Cdb = Cdb;
1468 //
1469 // Fill Cdb for Security Protocol Out Command
1470 //
1471 Cdb[0] = EFI_SCSI_OP_SECURITY_PROTOCOL_OUT;
1472 Cdb[1] = SecurityProtocol;
1473 WriteUnaligned16 ((UINT16 *)&Cdb[2], SwapBytes16 (SecurityProtocolSpecific));
1474
1475 if (Inc512) {
1476 if (DataLength % 512 != 0) {
1477 return EFI_INVALID_PARAMETER;
1478 }
1479
1480 Cdb[4] = BIT7;
1481 WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32)DataLength / 512));
1482 } else {
1483 WriteUnaligned32 ((UINT32 *)&Cdb[6], SwapBytes32 ((UINT32)DataLength));
1484 }
1485
1486 CommandPacket.CdbLength = EFI_SCSI_OP_LENGTH_TWELVE;
1487 CommandPacket.DataDirection = EFI_SCSI_DATA_OUT;
1488 CommandPacket.SenseDataLength = *SenseDataLength;
1489
1490 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
1491
1492 *HostAdapterStatus = CommandPacket.HostAdapterStatus;
1493 *TargetStatus = CommandPacket.TargetStatus;
1494 *SenseDataLength = CommandPacket.SenseDataLength;
1495
1496 return Status;
1497 }
1498
1499 /**
1500 Internal helper notify function in which update the result of the
1501 non-blocking SCSI Read/Write commands and signal caller event.
1502
1503 @param Event The instance of EFI_EVENT.
1504 @param Context The parameter passed in.
1505
1506 **/
1507 VOID
1508 EFIAPI
1509 ScsiLibNotify (
1510 IN EFI_EVENT Event,
1511 IN VOID *Context
1512 )
1513 {
1514 EFI_SCSI_LIB_ASYNC_CONTEXT *LibContext;
1515 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
1516 EFI_EVENT CallerEvent;
1517
1518 LibContext = (EFI_SCSI_LIB_ASYNC_CONTEXT *)Context;
1519 CommandPacket = &LibContext->CommandPacket;
1520 CallerEvent = LibContext->CallerEvent;
1521
1522 //
1523 // Update SCSI Read/Write operation results
1524 //
1525 *LibContext->SenseDataLength = CommandPacket->SenseDataLength;
1526 *LibContext->HostAdapterStatus = CommandPacket->HostAdapterStatus;
1527 *LibContext->TargetStatus = CommandPacket->TargetStatus;
1528 if (CommandPacket->InDataBuffer != NULL) {
1529 *LibContext->DataLength = CommandPacket->InTransferLength;
1530 } else {
1531 *LibContext->DataLength = CommandPacket->OutTransferLength;
1532 }
1533
1534 if (CommandPacket->Cdb != NULL) {
1535 FreePool (CommandPacket->Cdb);
1536 }
1537
1538 FreePool (Context);
1539
1540 gBS->CloseEvent (Event);
1541 gBS->SignalEvent (CallerEvent);
1542 }
1543
1544 /**
1545 Execute blocking/non-blocking Read(10) SCSI command on a specific SCSI
1546 target.
1547
1548 Executes the SCSI Read(10) command on the SCSI target specified by ScsiIo.
1549 When Event is NULL, blocking command will be executed. Otherwise non-blocking
1550 command will be executed.
1551 For blocking I/O, if Timeout is zero, this function will wait indefinitely
1552 for the command to complete. If Timeout is greater than zero, then the
1553 command is executed and will timeout after Timeout 100 ns units.
1554 For non-blocking I/O, if Timeout is zero, Event will be signaled only after
1555 the command to completes. If Timeout is greater than zero, Event will also be
1556 signaled after Timeout 100 ns units.
1557 The StartLba and SectorSize parameters are used to construct the CDB for this
1558 SCSI command.
1559
1560 If ScsiIo is NULL, then ASSERT().
1561 If SenseDataLength is NULL, then ASSERT().
1562 If HostAdapterStatus is NULL, then ASSERT().
1563 If TargetStatus is NULL, then ASSERT().
1564 If DataLength is NULL, then ASSERT().
1565
1566 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet
1567 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1568 EFI_INVALID_PARAMETER gets returned.
1569
1570 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet
1571 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1572 EFI_INVALID_PARAMETER gets returned.
1573
1574 @param[in] ScsiIo A pointer to SCSI IO protocol.
1575 @param[in] Timeout The length of timeout period.
1576 @param[in, out] SenseData A pointer to output sense data.
1577 @param[in, out] SenseDataLength The length of output sense data.
1578 @param[out] HostAdapterStatus The status of Host Adapter.
1579 @param[out] TargetStatus The status of the target.
1580 @param[in, out] DataBuffer Read 16 command data.
1581 @param[in, out] DataLength The length of data buffer.
1582 @param[in] StartLba The start address of LBA.
1583 @param[in] SectorSize The number of contiguous logical blocks
1584 of data that shall be transferred.
1585 @param[in] Event If the SCSI target does not support
1586 non-blocking I/O, then Event is ignored,
1587 and blocking I/O is performed. If Event
1588 is NULL, then blocking I/O is performed.
1589 If Event is not NULL and non-blocking
1590 I/O is supported, then non-blocking I/O
1591 is performed, and Event will be signaled
1592 when the SCSI Read(10) command
1593 completes.
1594
1595 @retval EFI_SUCCESS Command is executed successfully.
1596 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
1597 but the entire DataBuffer could not be
1598 transferred. The actual number of bytes
1599 transferred is returned in DataLength.
1600 @retval EFI_NOT_READY The SCSI Request Packet could not be
1601 sent because there are too many SCSI
1602 Command Packets already queued.
1603 @retval EFI_DEVICE_ERROR A device error occurred while attempting
1604 to send SCSI Request Packet.
1605 @retval EFI_UNSUPPORTED The command described by the SCSI
1606 Request Packet is not supported by the
1607 SCSI initiator(i.e., SCSI Host
1608 Controller)
1609 @retval EFI_TIMEOUT A timeout occurred while waiting for the
1610 SCSI Request Packet to execute.
1611 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet
1612 are invalid.
1613 @retval EFI_OUT_OF_RESOURCES The request could not be completed due
1614 to a lack of resources.
1615
1616 **/
1617 EFI_STATUS
1618 EFIAPI
1619 ScsiRead10CommandEx (
1620 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1621 IN UINT64 Timeout,
1622 IN OUT VOID *SenseData OPTIONAL,
1623 IN OUT UINT8 *SenseDataLength,
1624 OUT UINT8 *HostAdapterStatus,
1625 OUT UINT8 *TargetStatus,
1626 IN OUT VOID *DataBuffer OPTIONAL,
1627 IN OUT UINT32 *DataLength,
1628 IN UINT32 StartLba,
1629 IN UINT32 SectorSize,
1630 IN EFI_EVENT Event OPTIONAL
1631 )
1632 {
1633 EFI_SCSI_LIB_ASYNC_CONTEXT *Context;
1634 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
1635 EFI_STATUS Status;
1636 UINT8 *Cdb;
1637 EFI_EVENT SelfEvent;
1638
1639 if (Event == NULL) {
1640 return ScsiRead10Command (
1641 ScsiIo,
1642 Timeout,
1643 SenseData,
1644 SenseDataLength,
1645 HostAdapterStatus,
1646 TargetStatus,
1647 DataBuffer,
1648 DataLength,
1649 StartLba,
1650 SectorSize
1651 );
1652 }
1653
1654 ASSERT (SenseDataLength != NULL);
1655 ASSERT (HostAdapterStatus != NULL);
1656 ASSERT (TargetStatus != NULL);
1657 ASSERT (DataLength != NULL);
1658 ASSERT (ScsiIo != NULL);
1659
1660 Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));
1661 if (Context == NULL) {
1662 return EFI_OUT_OF_RESOURCES;
1663 }
1664
1665 Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN);
1666 if (Cdb == NULL) {
1667 Status = EFI_OUT_OF_RESOURCES;
1668 goto ErrorExit;
1669 }
1670
1671 Context->SenseDataLength = SenseDataLength;
1672 Context->HostAdapterStatus = HostAdapterStatus;
1673 Context->TargetStatus = TargetStatus;
1674 Context->CallerEvent = Event;
1675
1676 CommandPacket = &Context->CommandPacket;
1677 CommandPacket->Timeout = Timeout;
1678 CommandPacket->InDataBuffer = DataBuffer;
1679 CommandPacket->SenseData = SenseData;
1680 CommandPacket->InTransferLength = *DataLength;
1681 CommandPacket->Cdb = Cdb;
1682 //
1683 // Fill Cdb for Read (10) Command
1684 //
1685 Cdb[0] = EFI_SCSI_OP_READ10;
1686 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
1687 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16)SectorSize));
1688
1689 CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN;
1690 CommandPacket->DataDirection = EFI_SCSI_DATA_IN;
1691 CommandPacket->SenseDataLength = *SenseDataLength;
1692
1693 //
1694 // Create Event
1695 //
1696 Status = gBS->CreateEvent (
1697 EVT_NOTIFY_SIGNAL,
1698 TPL_NOTIFY,
1699 ScsiLibNotify,
1700 Context,
1701 &SelfEvent
1702 );
1703 if (EFI_ERROR (Status)) {
1704 goto ErrorExit;
1705 }
1706
1707 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);
1708 if (EFI_ERROR (Status)) {
1709 //
1710 // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()
1711 // returns with error, close the event here.
1712 //
1713 gBS->CloseEvent (SelfEvent);
1714 goto ErrorExit;
1715 } else {
1716 return EFI_SUCCESS;
1717 }
1718
1719 ErrorExit:
1720 if (Context != NULL) {
1721 FreePool (Context);
1722 }
1723
1724 return Status;
1725 }
1726
1727 /**
1728 Execute blocking/non-blocking Write(10) SCSI command on a specific SCSI
1729 target.
1730
1731 Executes the SCSI Write(10) command on the SCSI target specified by ScsiIo.
1732 When Event is NULL, blocking command will be executed. Otherwise non-blocking
1733 command will be executed.
1734 For blocking I/O, if Timeout is zero, this function will wait indefinitely
1735 for the command to complete. If Timeout is greater than zero, then the
1736 command is executed and will timeout after Timeout 100 ns units.
1737 For non-blocking I/O, if Timeout is zero, Event will be signaled only after
1738 the command to completes. If Timeout is greater than zero, Event will also be
1739 signaled after Timeout 100 ns units.
1740 The StartLba and SectorSize parameters are used to construct the CDB for this
1741 SCSI command.
1742
1743 If ScsiIo is NULL, then ASSERT().
1744 If SenseDataLength is NULL, then ASSERT().
1745 If HostAdapterStatus is NULL, then ASSERT().
1746 If TargetStatus is NULL, then ASSERT().
1747 If DataLength is NULL, then ASSERT().
1748
1749 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet
1750 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1751 EFI_INVALID_PARAMETER gets returned.
1752
1753 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet
1754 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1755 EFI_INVALID_PARAMETER gets returned.
1756
1757 @param[in] ScsiIo SCSI IO Protocol to use
1758 @param[in] Timeout The length of timeout period.
1759 @param[in, out] SenseData A pointer to output sense data.
1760 @param[in, out] SenseDataLength The length of output sense data.
1761 @param[out] HostAdapterStatus The status of Host Adapter.
1762 @param[out] TargetStatus The status of the target.
1763 @param[in, out] DataBuffer A pointer to a data buffer.
1764 @param[in, out] DataLength The length of data buffer.
1765 @param[in] StartLba The start address of LBA.
1766 @param[in] SectorSize The number of contiguous logical blocks
1767 of data that shall be transferred.
1768 @param[in] Event If the SCSI target does not support
1769 non-blocking I/O, then Event is ignored,
1770 and blocking I/O is performed. If Event
1771 is NULL, then blocking I/O is performed.
1772 If Event is not NULL and non-blocking
1773 I/O is supported, then non-blocking I/O
1774 is performed, and Event will be signaled
1775 when the SCSI Write(10) command
1776 completes.
1777
1778 @retval EFI_SUCCESS Command is executed successfully.
1779 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
1780 but the entire DataBuffer could not be
1781 transferred. The actual number of bytes
1782 transferred is returned in DataLength.
1783 @retval EFI_NOT_READY The SCSI Request Packet could not be
1784 sent because there are too many SCSI
1785 Command Packets already queued.
1786 @retval EFI_DEVICE_ERROR A device error occurred while attempting
1787 to send SCSI Request Packet.
1788 @retval EFI_UNSUPPORTED The command described by the SCSI
1789 Request Packet is not supported by the
1790 SCSI initiator(i.e., SCSI Host
1791 Controller)
1792 @retval EFI_TIMEOUT A timeout occurred while waiting for the
1793 SCSI Request Packet to execute.
1794 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet
1795 are invalid.
1796 @retval EFI_OUT_OF_RESOURCES The request could not be completed due
1797 to a lack of resources.
1798
1799 **/
1800 EFI_STATUS
1801 EFIAPI
1802 ScsiWrite10CommandEx (
1803 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1804 IN UINT64 Timeout,
1805 IN OUT VOID *SenseData OPTIONAL,
1806 IN OUT UINT8 *SenseDataLength,
1807 OUT UINT8 *HostAdapterStatus,
1808 OUT UINT8 *TargetStatus,
1809 IN OUT VOID *DataBuffer OPTIONAL,
1810 IN OUT UINT32 *DataLength,
1811 IN UINT32 StartLba,
1812 IN UINT32 SectorSize,
1813 IN EFI_EVENT Event OPTIONAL
1814 )
1815 {
1816 EFI_SCSI_LIB_ASYNC_CONTEXT *Context;
1817 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
1818 EFI_STATUS Status;
1819 UINT8 *Cdb;
1820 EFI_EVENT SelfEvent;
1821
1822 if (Event == NULL) {
1823 return ScsiWrite10Command (
1824 ScsiIo,
1825 Timeout,
1826 SenseData,
1827 SenseDataLength,
1828 HostAdapterStatus,
1829 TargetStatus,
1830 DataBuffer,
1831 DataLength,
1832 StartLba,
1833 SectorSize
1834 );
1835 }
1836
1837 ASSERT (SenseDataLength != NULL);
1838 ASSERT (HostAdapterStatus != NULL);
1839 ASSERT (TargetStatus != NULL);
1840 ASSERT (DataLength != NULL);
1841 ASSERT (ScsiIo != NULL);
1842
1843 Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));
1844 if (Context == NULL) {
1845 return EFI_OUT_OF_RESOURCES;
1846 }
1847
1848 Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_TEN);
1849 if (Cdb == NULL) {
1850 Status = EFI_OUT_OF_RESOURCES;
1851 goto ErrorExit;
1852 }
1853
1854 Context->SenseDataLength = SenseDataLength;
1855 Context->HostAdapterStatus = HostAdapterStatus;
1856 Context->TargetStatus = TargetStatus;
1857 Context->CallerEvent = Event;
1858
1859 CommandPacket = &Context->CommandPacket;
1860 CommandPacket->Timeout = Timeout;
1861 CommandPacket->OutDataBuffer = DataBuffer;
1862 CommandPacket->SenseData = SenseData;
1863 CommandPacket->OutTransferLength = *DataLength;
1864 CommandPacket->Cdb = Cdb;
1865 //
1866 // Fill Cdb for Write (10) Command
1867 //
1868 Cdb[0] = EFI_SCSI_OP_WRITE10;
1869 WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 (StartLba));
1870 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16)SectorSize));
1871
1872 CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_TEN;
1873 CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;
1874 CommandPacket->SenseDataLength = *SenseDataLength;
1875
1876 //
1877 // Create Event
1878 //
1879 Status = gBS->CreateEvent (
1880 EVT_NOTIFY_SIGNAL,
1881 TPL_NOTIFY,
1882 ScsiLibNotify,
1883 Context,
1884 &SelfEvent
1885 );
1886 if (EFI_ERROR (Status)) {
1887 goto ErrorExit;
1888 }
1889
1890 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);
1891 if (EFI_ERROR (Status)) {
1892 //
1893 // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()
1894 // returns with error, close the event here.
1895 //
1896 gBS->CloseEvent (SelfEvent);
1897 goto ErrorExit;
1898 } else {
1899 return EFI_SUCCESS;
1900 }
1901
1902 ErrorExit:
1903 if (Context != NULL) {
1904 FreePool (Context);
1905 }
1906
1907 return Status;
1908 }
1909
1910 /**
1911 Execute blocking/non-blocking Read(16) SCSI command on a specific SCSI
1912 target.
1913
1914 Executes the SCSI Read(16) command on the SCSI target specified by ScsiIo.
1915 When Event is NULL, blocking command will be executed. Otherwise non-blocking
1916 command will be executed.
1917 For blocking I/O, if Timeout is zero, this function will wait indefinitely
1918 for the command to complete. If Timeout is greater than zero, then the
1919 command is executed and will timeout after Timeout 100 ns units.
1920 For non-blocking I/O, if Timeout is zero, Event will be signaled only after
1921 the command to completes. If Timeout is greater than zero, Event will also be
1922 signaled after Timeout 100 ns units.
1923 The StartLba and SectorSize parameters are used to construct the CDB for this
1924 SCSI command.
1925
1926 If ScsiIo is NULL, then ASSERT().
1927 If SenseDataLength is NULL, then ASSERT().
1928 If HostAdapterStatus is NULL, then ASSERT().
1929 If TargetStatus is NULL, then ASSERT().
1930 If DataLength is NULL, then ASSERT().
1931
1932 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet
1933 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1934 EFI_INVALID_PARAMETER gets returned.
1935
1936 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet
1937 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
1938 EFI_INVALID_PARAMETER gets returned.
1939
1940 @param[in] ScsiIo A pointer to SCSI IO protocol.
1941 @param[in] Timeout The length of timeout period.
1942 @param[in, out] SenseData A pointer to output sense data.
1943 @param[in, out] SenseDataLength The length of output sense data.
1944 @param[out] HostAdapterStatus The status of Host Adapter.
1945 @param[out] TargetStatus The status of the target.
1946 @param[in, out] DataBuffer Read 16 command data.
1947 @param[in, out] DataLength The length of data buffer.
1948 @param[in] StartLba The start address of LBA.
1949 @param[in] SectorSize The number of contiguous logical blocks
1950 of data that shall be transferred.
1951 @param[in] Event If the SCSI target does not support
1952 non-blocking I/O, then Event is ignored,
1953 and blocking I/O is performed. If Event
1954 is NULL, then blocking I/O is performed.
1955 If Event is not NULL and non-blocking
1956 I/O is supported, then non-blocking I/O
1957 is performed, and Event will be signaled
1958 when the SCSI Read(16) command
1959 completes.
1960
1961 @retval EFI_SUCCESS Command is executed successfully.
1962 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
1963 but the entire DataBuffer could not be
1964 transferred. The actual number of bytes
1965 transferred is returned in DataLength.
1966 @retval EFI_NOT_READY The SCSI Request Packet could not be
1967 sent because there are too many SCSI
1968 Command Packets already queued.
1969 @retval EFI_DEVICE_ERROR A device error occurred while attempting
1970 to send SCSI Request Packet.
1971 @retval EFI_UNSUPPORTED The command described by the SCSI
1972 Request Packet is not supported by the
1973 SCSI initiator(i.e., SCSI Host
1974 Controller)
1975 @retval EFI_TIMEOUT A timeout occurred while waiting for the
1976 SCSI Request Packet to execute.
1977 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet
1978 are invalid.
1979 @retval EFI_OUT_OF_RESOURCES The request could not be completed due
1980 to a lack of resources.
1981
1982 **/
1983 EFI_STATUS
1984 EFIAPI
1985 ScsiRead16CommandEx (
1986 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
1987 IN UINT64 Timeout,
1988 IN OUT VOID *SenseData OPTIONAL,
1989 IN OUT UINT8 *SenseDataLength,
1990 OUT UINT8 *HostAdapterStatus,
1991 OUT UINT8 *TargetStatus,
1992 IN OUT VOID *DataBuffer OPTIONAL,
1993 IN OUT UINT32 *DataLength,
1994 IN UINT64 StartLba,
1995 IN UINT32 SectorSize,
1996 IN EFI_EVENT Event OPTIONAL
1997 )
1998 {
1999 EFI_SCSI_LIB_ASYNC_CONTEXT *Context;
2000 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
2001 EFI_STATUS Status;
2002 UINT8 *Cdb;
2003 EFI_EVENT SelfEvent;
2004
2005 if (Event == NULL) {
2006 return ScsiRead16Command (
2007 ScsiIo,
2008 Timeout,
2009 SenseData,
2010 SenseDataLength,
2011 HostAdapterStatus,
2012 TargetStatus,
2013 DataBuffer,
2014 DataLength,
2015 StartLba,
2016 SectorSize
2017 );
2018 }
2019
2020 ASSERT (SenseDataLength != NULL);
2021 ASSERT (HostAdapterStatus != NULL);
2022 ASSERT (TargetStatus != NULL);
2023 ASSERT (DataLength != NULL);
2024 ASSERT (ScsiIo != NULL);
2025
2026 Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));
2027 if (Context == NULL) {
2028 return EFI_OUT_OF_RESOURCES;
2029 }
2030
2031 Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN);
2032 if (Cdb == NULL) {
2033 Status = EFI_OUT_OF_RESOURCES;
2034 goto ErrorExit;
2035 }
2036
2037 Context->SenseDataLength = SenseDataLength;
2038 Context->HostAdapterStatus = HostAdapterStatus;
2039 Context->TargetStatus = TargetStatus;
2040 Context->CallerEvent = Event;
2041
2042 CommandPacket = &Context->CommandPacket;
2043 CommandPacket->Timeout = Timeout;
2044 CommandPacket->InDataBuffer = DataBuffer;
2045 CommandPacket->SenseData = SenseData;
2046 CommandPacket->InTransferLength = *DataLength;
2047 CommandPacket->Cdb = Cdb;
2048 //
2049 // Fill Cdb for Read (16) Command
2050 //
2051 Cdb[0] = EFI_SCSI_OP_READ16;
2052 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
2053 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
2054
2055 CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
2056 CommandPacket->DataDirection = EFI_SCSI_DATA_IN;
2057 CommandPacket->SenseDataLength = *SenseDataLength;
2058
2059 //
2060 // Create Event
2061 //
2062 Status = gBS->CreateEvent (
2063 EVT_NOTIFY_SIGNAL,
2064 TPL_NOTIFY,
2065 ScsiLibNotify,
2066 Context,
2067 &SelfEvent
2068 );
2069 if (EFI_ERROR (Status)) {
2070 goto ErrorExit;
2071 }
2072
2073 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);
2074 if (EFI_ERROR (Status)) {
2075 //
2076 // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()
2077 // returns with error, close the event here.
2078 //
2079 gBS->CloseEvent (SelfEvent);
2080 goto ErrorExit;
2081 } else {
2082 return EFI_SUCCESS;
2083 }
2084
2085 ErrorExit:
2086 if (Context != NULL) {
2087 FreePool (Context);
2088 }
2089
2090 return Status;
2091 }
2092
2093 /**
2094 Execute blocking/non-blocking Write(16) SCSI command on a specific SCSI
2095 target.
2096
2097 Executes the SCSI Write(16) command on the SCSI target specified by ScsiIo.
2098 When Event is NULL, blocking command will be executed. Otherwise non-blocking
2099 command will be executed.
2100 For blocking I/O, if Timeout is zero, this function will wait indefinitely
2101 for the command to complete. If Timeout is greater than zero, then the
2102 command is executed and will timeout after Timeout 100 ns units.
2103 For non-blocking I/O, if Timeout is zero, Event will be signaled only after
2104 the command to completes. If Timeout is greater than zero, Event will also be
2105 signaled after Timeout 100 ns units.
2106 The StartLba and SectorSize parameters are used to construct the CDB for this
2107 SCSI command.
2108
2109 If ScsiIo is NULL, then ASSERT().
2110 If SenseDataLength is NULL, then ASSERT().
2111 If HostAdapterStatus is NULL, then ASSERT().
2112 If TargetStatus is NULL, then ASSERT().
2113 If DataLength is NULL, then ASSERT().
2114
2115 If SenseDataLength is non-zero and SenseData is not NULL, SenseData must meet
2116 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
2117 EFI_INVALID_PARAMETER gets returned.
2118
2119 If DataLength is non-zero and DataBuffer is not NULL, DataBuffer must meet
2120 buffer alignment requirement defined in EFI_SCSI_IO_PROTOCOL. Otherwise
2121 EFI_INVALID_PARAMETER gets returned.
2122
2123 @param[in] ScsiIo SCSI IO Protocol to use
2124 @param[in] Timeout The length of timeout period.
2125 @param[in, out] SenseData A pointer to output sense data.
2126 @param[in, out] SenseDataLength The length of output sense data.
2127 @param[out] HostAdapterStatus The status of Host Adapter.
2128 @param[out] TargetStatus The status of the target.
2129 @param[in, out] DataBuffer A pointer to a data buffer.
2130 @param[in, out] DataLength The length of data buffer.
2131 @param[in] StartLba The start address of LBA.
2132 @param[in] SectorSize The number of contiguous logical blocks
2133 of data that shall be transferred.
2134 @param[in] Event If the SCSI target does not support
2135 non-blocking I/O, then Event is ignored,
2136 and blocking I/O is performed. If Event
2137 is NULL, then blocking I/O is performed.
2138 If Event is not NULL and non-blocking
2139 I/O is supported, then non-blocking I/O
2140 is performed, and Event will be signaled
2141 when the SCSI Write(16) command
2142 completes.
2143
2144 @retval EFI_SUCCESS Command is executed successfully.
2145 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
2146 but the entire DataBuffer could not be
2147 transferred. The actual number of bytes
2148 transferred is returned in DataLength.
2149 @retval EFI_NOT_READY The SCSI Request Packet could not be
2150 sent because there are too many SCSI
2151 Command Packets already queued.
2152 @retval EFI_DEVICE_ERROR A device error occurred while attempting
2153 to send SCSI Request Packet.
2154 @retval EFI_UNSUPPORTED The command described by the SCSI
2155 Request Packet is not supported by the
2156 SCSI initiator(i.e., SCSI Host
2157 Controller)
2158 @retval EFI_TIMEOUT A timeout occurred while waiting for the
2159 SCSI Request Packet to execute.
2160 @retval EFI_INVALID_PARAMETER The contents of the SCSI Request Packet
2161 are invalid.
2162 @retval EFI_OUT_OF_RESOURCES The request could not be completed due
2163 to a lack of resources.
2164
2165 **/
2166 EFI_STATUS
2167 EFIAPI
2168 ScsiWrite16CommandEx (
2169 IN EFI_SCSI_IO_PROTOCOL *ScsiIo,
2170 IN UINT64 Timeout,
2171 IN OUT VOID *SenseData OPTIONAL,
2172 IN OUT UINT8 *SenseDataLength,
2173 OUT UINT8 *HostAdapterStatus,
2174 OUT UINT8 *TargetStatus,
2175 IN OUT VOID *DataBuffer OPTIONAL,
2176 IN OUT UINT32 *DataLength,
2177 IN UINT64 StartLba,
2178 IN UINT32 SectorSize,
2179 IN EFI_EVENT Event OPTIONAL
2180 )
2181 {
2182 EFI_SCSI_LIB_ASYNC_CONTEXT *Context;
2183 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
2184 EFI_STATUS Status;
2185 UINT8 *Cdb;
2186 EFI_EVENT SelfEvent;
2187
2188 if (Event == NULL) {
2189 return ScsiWrite16Command (
2190 ScsiIo,
2191 Timeout,
2192 SenseData,
2193 SenseDataLength,
2194 HostAdapterStatus,
2195 TargetStatus,
2196 DataBuffer,
2197 DataLength,
2198 StartLba,
2199 SectorSize
2200 );
2201 }
2202
2203 ASSERT (SenseDataLength != NULL);
2204 ASSERT (HostAdapterStatus != NULL);
2205 ASSERT (TargetStatus != NULL);
2206 ASSERT (DataLength != NULL);
2207 ASSERT (ScsiIo != NULL);
2208
2209 Context = AllocateZeroPool (sizeof (EFI_SCSI_LIB_ASYNC_CONTEXT));
2210 if (Context == NULL) {
2211 return EFI_OUT_OF_RESOURCES;
2212 }
2213
2214 Cdb = AllocateZeroPool (EFI_SCSI_OP_LENGTH_SIXTEEN);
2215 if (Cdb == NULL) {
2216 Status = EFI_OUT_OF_RESOURCES;
2217 goto ErrorExit;
2218 }
2219
2220 Context->SenseDataLength = SenseDataLength;
2221 Context->HostAdapterStatus = HostAdapterStatus;
2222 Context->TargetStatus = TargetStatus;
2223 Context->CallerEvent = Event;
2224
2225 CommandPacket = &Context->CommandPacket;
2226 CommandPacket->Timeout = Timeout;
2227 CommandPacket->OutDataBuffer = DataBuffer;
2228 CommandPacket->SenseData = SenseData;
2229 CommandPacket->OutTransferLength = *DataLength;
2230 CommandPacket->Cdb = Cdb;
2231 //
2232 // Fill Cdb for Write (16) Command
2233 //
2234 Cdb[0] = EFI_SCSI_OP_WRITE16;
2235 WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
2236 WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorSize));
2237
2238 CommandPacket->CdbLength = EFI_SCSI_OP_LENGTH_SIXTEEN;
2239 CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;
2240 CommandPacket->SenseDataLength = *SenseDataLength;
2241
2242 //
2243 // Create Event
2244 //
2245 Status = gBS->CreateEvent (
2246 EVT_NOTIFY_SIGNAL,
2247 TPL_NOTIFY,
2248 ScsiLibNotify,
2249 Context,
2250 &SelfEvent
2251 );
2252 if (EFI_ERROR (Status)) {
2253 goto ErrorExit;
2254 }
2255
2256 Status = ScsiIo->ExecuteScsiCommand (ScsiIo, CommandPacket, SelfEvent);
2257 if (EFI_ERROR (Status)) {
2258 //
2259 // Since ScsiLibNotify() will not be signaled if ExecuteScsiCommand()
2260 // returns with error, close the event here.
2261 //
2262 gBS->CloseEvent (SelfEvent);
2263 goto ErrorExit;
2264 } else {
2265 return EFI_SUCCESS;
2266 }
2267
2268 ErrorExit:
2269 if (Context != NULL) {
2270 FreePool (Context);
2271 }
2272
2273 return Status;
2274 }