1 /** @file
2 
3   Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #ifndef _UFS_BLOCK_IO_PEI_H_
15 #define _UFS_BLOCK_IO_PEI_H_
16 
17 #include <PiPei.h>
18 
19 #include <Ppi/UfsHostController.h>
20 #include <Ppi/BlockIo.h>
21 #include <Ppi/BlockIo2.h>
22 
23 #include <Library/DebugLib.h>
24 #include <Library/BaseLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/MemoryAllocationLib.h>
27 #include <Library/IoLib.h>
28 #include <Library/TimerLib.h>
29 #include <Library/PeiServicesLib.h>
30 
31 #include <IndustryStandard/Scsi.h>
32 
33 #include "UfsHci.h"
34 #include "UfsHcMem.h"
35 
36 #define UFS_PEIM_HC_SIG             SIGNATURE_32 ('U', 'F', 'S', 'H')
37 
38 #define UFS_PEIM_MAX_LUNS           8
39 
40 typedef struct {
41   UINT8    Lun[UFS_PEIM_MAX_LUNS];
42   UINT16   BitMask:12;              // Bit 0~7 is for common luns. Bit 8~11 is reserved for those well known luns
43   UINT16   Rsvd:4;
44 } UFS_PEIM_EXPOSED_LUNS;
45 
46 typedef struct {
47   ///
48   /// The timeout, in 100 ns units, to use for the execution of this SCSI
49   /// Request Packet. A Timeout value of 0 means that this function
50   /// will wait indefinitely for the SCSI Request Packet to execute. If
51   /// Timeout is greater than zero, then this function will return
52   /// EFI_TIMEOUT if the time required to execute the SCSI
53   /// Request Packet is greater than Timeout.
54   ///
55   UINT64 Timeout;
56   ///
57   /// A pointer to the data buffer to transfer between the SCSI
58   /// controller and the SCSI device for read and bidirectional commands.
59   ///
60   VOID   *InDataBuffer;
61   ///
62   /// A pointer to the data buffer to transfer between the SCSI
63   /// controller and the SCSI device for write or bidirectional commands.
64   ///
65   VOID   *OutDataBuffer;
66   ///
67   /// A pointer to the sense data that was generated by the execution of
68   /// the SCSI Request Packet.
69   ///
70   VOID   *SenseData;
71   ///
72   /// A pointer to buffer that contains the Command Data Block to
73   /// send to the SCSI device specified by Target and Lun.
74   ///
75   VOID   *Cdb;
76   ///
77   /// On Input, the size, in bytes, of InDataBuffer. On output, the
78   /// number of bytes transferred between the SCSI controller and the SCSI device.
79   ///
80   UINT32 InTransferLength;
81   ///
82   /// On Input, the size, in bytes of OutDataBuffer. On Output, the
83   /// Number of bytes transferred between SCSI Controller and the SCSI device.
84   ///
85   UINT32 OutTransferLength;
86   ///
87   /// The length, in bytes, of the buffer Cdb. The standard values are 6,
88   /// 10, 12, and 16, but other values are possible if a variable length CDB is used.
89   ///
90   UINT8  CdbLength;
91   ///
92   /// The direction of the data transfer. 0 for reads, 1 for writes. A
93   /// value of 2 is Reserved for Bi-Directional SCSI commands.
94   ///
95   UINT8  DataDirection;
96   ///
97   /// On input, the length in bytes of the SenseData buffer. On
98   /// output, the number of bytes written to the SenseData buffer.
99   ///
100   UINT8  SenseDataLength;
101 } UFS_SCSI_REQUEST_PACKET;
102 
103 typedef struct _UFS_PEIM_HC_PRIVATE_DATA {
104   UINT32                            Signature;
105   EFI_HANDLE                        Controller;
106 
107   UFS_PEIM_MEM_POOL                 *Pool;
108 
109   EFI_PEI_RECOVERY_BLOCK_IO_PPI     BlkIoPpi;
110   EFI_PEI_RECOVERY_BLOCK_IO2_PPI    BlkIo2Ppi;
111   EFI_PEI_PPI_DESCRIPTOR            BlkIoPpiList;
112   EFI_PEI_PPI_DESCRIPTOR            BlkIo2PpiList;
113   EFI_PEI_BLOCK_IO2_MEDIA           Media[UFS_PEIM_MAX_LUNS];
114 
115   UINTN                             UfsHcBase;
116   UINT32                            Capabilities;
117 
118   UINT8                             TaskTag;
119 
120   VOID                              *UtpTrlBase;
121   UINT8                             Nutrs;
122   VOID                              *UtpTmrlBase;
123   UINT8                             Nutmrs;
124 
125   UFS_PEIM_EXPOSED_LUNS             Luns;
126 } UFS_PEIM_HC_PRIVATE_DATA;
127 
128 #define UFS_TIMEOUT                 MultU64x32((UINT64)(3), 10000000)
129 
130 #define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)
131 
132 #define IS_ALIGNED(addr, size)      (((UINTN) (addr) & (size - 1)) == 0)
133 
134 #define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIoPpi, UFS_PEIM_HC_SIG)
135 #define GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, UFS_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, UFS_PEIM_HC_SIG)
136 
137 #define UFS_SCSI_OP_LENGTH_SIX      0x6
138 #define UFS_SCSI_OP_LENGTH_TEN      0xa
139 #define UFS_SCSI_OP_LENGTH_SIXTEEN  0x10
140 
141 typedef struct _UFS_DEVICE_MANAGEMENT_REQUEST_PACKET {
142   UINT64                            Timeout;
143   VOID                              *InDataBuffer;
144   VOID                              *OutDataBuffer;
145   UINT8                             Opcode;
146   UINT8                             DescId;
147   UINT8                             Index;
148   UINT8                             Selector;
149   UINT32                            InTransferLength;
150   UINT32                            OutTransferLength;
151   UINT8                             DataDirection;
152   UINT8                             Ocs;
153 } UFS_DEVICE_MANAGEMENT_REQUEST_PACKET;
154 
155 /**
156   Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
157 
158   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
159   @param[in]      Lun           The LUN of the UFS device to send the SCSI Request Packet.
160   @param[in, out] Packet        A pointer to the SCSI Request Packet to send to a specified Lun of the
161                                 UFS device.
162 
163   @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional
164                                 commands, InTransferLength bytes were transferred from
165                                 InDataBuffer. For write and bi-directional commands,
166                                 OutTransferLength bytes were transferred by
167                                 OutDataBuffer.
168   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request
169                                 Packet.
170   @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
171   @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.
172 
173 **/
174 EFI_STATUS
175 UfsExecScsiCmds (
176   IN     UFS_PEIM_HC_PRIVATE_DATA      *Private,
177   IN     UINT8                         Lun,
178   IN OUT UFS_SCSI_REQUEST_PACKET       *Packet
179   );
180 
181 /**
182   Initialize the UFS host controller.
183 
184   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
185 
186   @retval EFI_SUCCESS                The Ufs Host Controller is initialized successfully.
187   @retval Others                     A device error occurred while initializing the controller.
188 
189 **/
190 EFI_STATUS
191 UfsControllerInit (
192   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
193   );
194 
195 /**
196   Stop the UFS host controller.
197 
198   @param[in] Private                 The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
199 
200   @retval EFI_SUCCESS                The Ufs Host Controller is stopped successfully.
201   @retval Others                     A device error occurred while stopping the controller.
202 
203 **/
204 EFI_STATUS
205 UfsControllerStop (
206   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
207   );
208 
209 /**
210   Set specified flag to 1 on a UFS device.
211 
212   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
213   @param[in]  FlagId            The ID of flag to be set.
214 
215   @retval EFI_SUCCESS           The flag was set successfully.
216   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to set the flag.
217   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of setting the flag.
218 
219 **/
220 EFI_STATUS
221 UfsSetFlag (
222   IN  UFS_PEIM_HC_PRIVATE_DATA     *Private,
223   IN  UINT8                        FlagId
224   );
225 
226 /**
227   Read or write specified device descriptor of a UFS device.
228 
229   @param[in]      Private       The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
230   @param[in]      Read          The boolean variable to show r/w direction.
231   @param[in]      DescId        The ID of device descriptor.
232   @param[in]      Index         The Index of device descriptor.
233   @param[in]      Selector      The Selector of device descriptor.
234   @param[in, out] Descriptor    The buffer of device descriptor to be read or written.
235   @param[in]      DescSize      The size of device descriptor buffer.
236 
237   @retval EFI_SUCCESS           The device descriptor was read/written successfully.
238   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to r/w the device descriptor.
239   @retval EFI_TIMEOUT           A timeout occurred while waiting for the completion of r/w the device descriptor.
240 
241 **/
242 EFI_STATUS
243 UfsRwDeviceDesc (
244   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
245   IN     BOOLEAN                      Read,
246   IN     UINT8                        DescId,
247   IN     UINT8                        Index,
248   IN     UINT8                        Selector,
249   IN OUT VOID                         *Descriptor,
250   IN     UINT32                       DescSize
251   );
252 
253 /**
254   Sends NOP IN cmd to a UFS device for initialization process request.
255   For more details, please refer to UFS 2.0 spec Figure 13.3.
256 
257   @param[in]  Private           The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.
258 
259   @retval EFI_SUCCESS           The NOP IN command was sent by the host. The NOP OUT response was
260                                 received successfully.
261   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to execute NOP IN command.
262   @retval EFI_OUT_OF_RESOURCES  The resource for transfer is not available.
263   @retval EFI_TIMEOUT           A timeout occurred while waiting for the NOP IN command to execute.
264 
265 **/
266 EFI_STATUS
267 UfsExecNopCmds (
268   IN  UFS_PEIM_HC_PRIVATE_DATA       *Private
269   );
270 
271 /**
272   Gets the count of block I/O devices that one specific block driver detects.
273 
274   This function is used for getting the count of block I/O devices that one
275   specific block driver detects.  To the PEI ATAPI driver, it returns the number
276   of all the detected ATAPI devices it detects during the enumeration process.
277   To the PEI legacy floppy driver, it returns the number of all the legacy
278   devices it finds during its enumeration process. If no device is detected,
279   then the function will return zero.
280 
281   @param[in]  PeiServices          General-purpose services that are available
282                                    to every PEIM.
283   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
284                                    instance.
285   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
286 
287   @retval     EFI_SUCCESS          The operation performed successfully.
288 
289 **/
290 EFI_STATUS
291 EFIAPI
292 UfsBlockIoPeimGetDeviceNo (
293   IN  EFI_PEI_SERVICES               **PeiServices,
294   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
295   OUT UINTN                          *NumberBlockDevices
296   );
297 
298 /**
299   Gets a block device's media information.
300 
301   This function will provide the caller with the specified block device's media
302   information. If the media changes, calling this function will update the media
303   information accordingly.
304 
305   @param[in]  PeiServices   General-purpose services that are available to every
306                             PEIM
307   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
308   @param[in]  DeviceIndex   Specifies the block device to which the function wants
309                             to talk. Because the driver that implements Block I/O
310                             PPIs will manage multiple block devices, the PPIs that
311                             want to talk to a single device must specify the
312                             device index that was assigned during the enumeration
313                             process. This index is a number from one to
314                             NumberBlockDevices.
315   @param[out] MediaInfo     The media information of the specified block media.
316                             The caller is responsible for the ownership of this
317                             data structure.
318 
319   @par Note:
320       The MediaInfo structure describes an enumeration of possible block device
321       types.  This enumeration exists because no device paths are actually passed
322       across interfaces that describe the type or class of hardware that is publishing
323       the block I/O interface. This enumeration will allow for policy decisions
324       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
325       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
326       by a given device type, they should be reported in ascending order; this
327       order also applies to nested partitions, such as legacy MBR, where the
328       outermost partitions would have precedence in the reporting order. The
329       same logic applies to systems such as IDE that have precedence relationships
330       like "Master/Slave" or "Primary/Secondary". The master device should be
331       reported first, the slave second.
332 
333   @retval EFI_SUCCESS        Media information about the specified block device
334                              was obtained successfully.
335   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
336                              error.
337 
338 **/
339 EFI_STATUS
340 EFIAPI
341 UfsBlockIoPeimGetMediaInfo (
342   IN  EFI_PEI_SERVICES               **PeiServices,
343   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
344   IN  UINTN                          DeviceIndex,
345   OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo
346   );
347 
348 /**
349   Reads the requested number of blocks from the specified block device.
350 
351   The function reads the requested number of blocks from the device. All the
352   blocks are read, or an error is returned. If there is no media in the device,
353   the function returns EFI_NO_MEDIA.
354 
355   @param[in]  PeiServices   General-purpose services that are available to
356                             every PEIM.
357   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
358   @param[in]  DeviceIndex   Specifies the block device to which the function wants
359                             to talk. Because the driver that implements Block I/O
360                             PPIs will manage multiple block devices, PPIs that
361                             want to talk to a single device must specify the device
362                             index that was assigned during the enumeration process.
363                             This index is a number from one to NumberBlockDevices.
364   @param[in]  StartLBA      The starting logical block address (LBA) to read from
365                             on the device
366   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
367                             a multiple of the intrinsic block size of the device.
368   @param[out] Buffer        A pointer to the destination buffer for the data.
369                             The caller is responsible for the ownership of the
370                             buffer.
371 
372   @retval EFI_SUCCESS             The data was read correctly from the device.
373   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
374                                   to perform the read operation.
375   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
376                                   valid, or the buffer is not properly aligned.
377   @retval EFI_NO_MEDIA            There is no media in the device.
378   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
379                                   the intrinsic block size of the device.
380 
381 **/
382 EFI_STATUS
383 EFIAPI
384 UfsBlockIoPeimReadBlocks (
385   IN  EFI_PEI_SERVICES               **PeiServices,
386   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
387   IN  UINTN                          DeviceIndex,
388   IN  EFI_PEI_LBA                    StartLBA,
389   IN  UINTN                          BufferSize,
390   OUT VOID                           *Buffer
391   );
392 
393 /**
394   Gets the count of block I/O devices that one specific block driver detects.
395 
396   This function is used for getting the count of block I/O devices that one
397   specific block driver detects.  To the PEI ATAPI driver, it returns the number
398   of all the detected ATAPI devices it detects during the enumeration process.
399   To the PEI legacy floppy driver, it returns the number of all the legacy
400   devices it finds during its enumeration process. If no device is detected,
401   then the function will return zero.
402 
403   @param[in]  PeiServices          General-purpose services that are available
404                                    to every PEIM.
405   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
406                                    instance.
407   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
408 
409   @retval     EFI_SUCCESS          The operation performed successfully.
410 
411 **/
412 EFI_STATUS
413 EFIAPI
414 UfsBlockIoPeimGetDeviceNo2 (
415   IN  EFI_PEI_SERVICES               **PeiServices,
416   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
417   OUT UINTN                          *NumberBlockDevices
418   );
419 
420 /**
421   Gets a block device's media information.
422 
423   This function will provide the caller with the specified block device's media
424   information. If the media changes, calling this function will update the media
425   information accordingly.
426 
427   @param[in]  PeiServices   General-purpose services that are available to every
428                             PEIM
429   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
430   @param[in]  DeviceIndex   Specifies the block device to which the function wants
431                             to talk. Because the driver that implements Block I/O
432                             PPIs will manage multiple block devices, the PPIs that
433                             want to talk to a single device must specify the
434                             device index that was assigned during the enumeration
435                             process. This index is a number from one to
436                             NumberBlockDevices.
437   @param[out] MediaInfo     The media information of the specified block media.
438                             The caller is responsible for the ownership of this
439                             data structure.
440 
441   @par Note:
442       The MediaInfo structure describes an enumeration of possible block device
443       types.  This enumeration exists because no device paths are actually passed
444       across interfaces that describe the type or class of hardware that is publishing
445       the block I/O interface. This enumeration will allow for policy decisions
446       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
447       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
448       by a given device type, they should be reported in ascending order; this
449       order also applies to nested partitions, such as legacy MBR, where the
450       outermost partitions would have precedence in the reporting order. The
451       same logic applies to systems such as IDE that have precedence relationships
452       like "Master/Slave" or "Primary/Secondary". The master device should be
453       reported first, the slave second.
454 
455   @retval EFI_SUCCESS        Media information about the specified block device
456                              was obtained successfully.
457   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
458                              error.
459 
460 **/
461 EFI_STATUS
462 EFIAPI
463 UfsBlockIoPeimGetMediaInfo2 (
464   IN  EFI_PEI_SERVICES               **PeiServices,
465   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
466   IN  UINTN                          DeviceIndex,
467   OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo
468   );
469 
470 /**
471   Reads the requested number of blocks from the specified block device.
472 
473   The function reads the requested number of blocks from the device. All the
474   blocks are read, or an error is returned. If there is no media in the device,
475   the function returns EFI_NO_MEDIA.
476 
477   @param[in]  PeiServices   General-purpose services that are available to
478                             every PEIM.
479   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
480   @param[in]  DeviceIndex   Specifies the block device to which the function wants
481                             to talk. Because the driver that implements Block I/O
482                             PPIs will manage multiple block devices, PPIs that
483                             want to talk to a single device must specify the device
484                             index that was assigned during the enumeration process.
485                             This index is a number from one to NumberBlockDevices.
486   @param[in]  StartLBA      The starting logical block address (LBA) to read from
487                             on the device
488   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
489                             a multiple of the intrinsic block size of the device.
490   @param[out] Buffer        A pointer to the destination buffer for the data.
491                             The caller is responsible for the ownership of the
492                             buffer.
493 
494   @retval EFI_SUCCESS             The data was read correctly from the device.
495   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
496                                   to perform the read operation.
497   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
498                                   valid, or the buffer is not properly aligned.
499   @retval EFI_NO_MEDIA            There is no media in the device.
500   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
501                                   the intrinsic block size of the device.
502 
503 **/
504 EFI_STATUS
505 EFIAPI
506 UfsBlockIoPeimReadBlocks2 (
507   IN  EFI_PEI_SERVICES               **PeiServices,
508   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
509   IN  UINTN                          DeviceIndex,
510   IN  EFI_PEI_LBA                    StartLBA,
511   IN  UINTN                          BufferSize,
512   OUT VOID                           *Buffer
513   );
514 
515 /**
516   Initialize the memory management pool for the host controller.
517 
518   @param  Private               The Ufs Peim driver private data.
519 
520   @retval EFI_SUCCESS           The memory pool is initialized.
521   @retval Others                Fail to init the memory pool.
522 
523 **/
524 EFI_STATUS
525 UfsPeimInitMemPool (
526   IN  UFS_PEIM_HC_PRIVATE_DATA      *Private
527   );
528 
529 /**
530   Allocate some memory from the host controller's memory pool
531   which can be used to communicate with host controller.
532 
533   @param  Pool      The host controller's memory pool.
534   @param  Size      Size of the memory to allocate.
535 
536   @return The allocated memory or NULL.
537 
538 **/
539 VOID *
540 UfsPeimAllocateMem (
541   IN  UFS_PEIM_MEM_POOL        *Pool,
542   IN  UINTN                    Size
543   );
544 
545 /**
546   Free the allocated memory back to the memory pool.
547 
548   @param  Pool           The memory pool of the host controller.
549   @param  Mem            The memory to free.
550   @param  Size           The size of the memory to free.
551 
552 **/
553 VOID
554 UfsPeimFreeMem (
555   IN UFS_PEIM_MEM_POOL    *Pool,
556   IN VOID                 *Mem,
557   IN UINTN                Size
558   );
559 
560 #endif
561