1 /** @file
2   UEFI SCSI Library implementation
3 
4   Copyright (c) 2006 - 2015, 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
ScsiTestUnitReadyCommand(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus)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
ScsiInquiryCommandEx(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * InquiryDataBuffer,OPTIONAL IN OUT UINT32 * InquiryDataLength,IN BOOLEAN EnableVitalProductData,IN UINT8 PageCode)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
ScsiInquiryCommand(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * InquiryDataBuffer,OPTIONAL IN OUT UINT32 * InquiryDataLength,IN BOOLEAN EnableVitalProductData)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
ScsiModeSense10Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT8 DBDField,OPTIONAL IN UINT8 PageControl,IN UINT8 PageCode)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
ScsiRequestSenseCommand(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus)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
ScsiReadCapacityCommand(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN BOOLEAN Pmi)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
ScsiReadCapacity16Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN BOOLEAN Pmi)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
ScsiRead10Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorSize)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
ScsiWrite10Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorSize)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
ScsiRead16Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorSize)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
ScsiWrite16Command(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorSize)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
ScsiLibNotify(IN EFI_EVENT Event,IN VOID * Context)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
ScsiRead10CommandEx(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorSize,IN EFI_EVENT Event OPTIONAL)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
ScsiWrite10CommandEx(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT32 StartLba,IN UINT32 SectorSize,IN EFI_EVENT Event OPTIONAL)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
ScsiRead16CommandEx(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorSize,IN EFI_EVENT Event OPTIONAL)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
ScsiWrite16CommandEx(IN EFI_SCSI_IO_PROTOCOL * ScsiIo,IN UINT64 Timeout,IN OUT VOID * SenseData,OPTIONAL IN OUT UINT8 * SenseDataLength,OUT UINT8 * HostAdapterStatus,OUT UINT8 * TargetStatus,IN OUT VOID * DataBuffer,OPTIONAL IN OUT UINT32 * DataLength,IN UINT64 StartLba,IN UINT32 SectorSize,IN EFI_EVENT Event OPTIONAL)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 }
2068