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