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