4 * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
6 * Written by Jeuk Kim <jeuk20.kim@samsung.com>
8 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "hw/pci/pci_device.h"
15 #include "hw/scsi/scsi.h"
16 #include "block/ufs.h"
18 #define UFS_MAX_LUS 32
19 #define UFS_MAX_MCQ_QNUM 32
20 #define UFS_BLOCK_SIZE_SHIFT 12
21 #define UFS_BLOCK_SIZE (1 << UFS_BLOCK_SIZE_SHIFT)
23 typedef struct UfsBusClass
{
24 BusClass parent_class
;
25 bool (*parent_check_address
)(BusState
*bus
, DeviceState
*dev
, Error
**errp
);
28 typedef struct UfsBus
{
32 #define TYPE_UFS_BUS "ufs-bus"
33 DECLARE_OBJ_CHECKERS(UfsBus
, UfsBusClass
, UFS_BUS
, TYPE_UFS_BUS
)
35 typedef enum UfsRequestState
{
37 UFS_REQUEST_READY
= 1,
38 UFS_REQUEST_RUNNING
= 2,
39 UFS_REQUEST_COMPLETE
= 3,
40 UFS_REQUEST_ERROR
= 4,
43 typedef enum UfsReqResult
{
44 UFS_REQUEST_SUCCESS
= 0,
46 UFS_REQUEST_NO_COMPLETE
= 2,
49 #define UFS_INVALID_SLOT (-1)
50 typedef struct UfsRequest
{
52 UfsRequestState state
;
53 int slot
; /* -1 when it's a MCQ request */
55 UtpTransferReqDesc utrd
;
59 /* for scsi command */
65 struct UfsCqEntry cqe
;
66 QTAILQ_ENTRY(UfsRequest
) entry
;
69 static inline bool ufs_mcq_req(UfsRequest
*req
)
71 return req
->sq
!= NULL
;
75 typedef UfsReqResult (*UfsScsiOp
)(struct UfsLu
*, UfsRequest
*);
77 typedef struct UfsLu
{
80 UnitDescriptor unit_desc
;
87 typedef struct UfsParams
{
89 uint8_t nutrs
; /* Number of UTP Transfer Request Slots */
90 uint8_t nutmrs
; /* Number of UTP Task Management Request Slots */
91 bool mcq
; /* Multiple Command Queue support */
92 uint8_t mcq_qcfgptr
; /* MCQ Queue Configuration Pointer in MCQCAP */
93 uint8_t mcq_maxq
; /* MCQ Maximum number of Queues */
99 typedef struct UfsSq
{
104 uint16_t size
; /* A number of entries (qdepth) */
106 QEMUBH
*bh
; /* Bottom half to process requests in async */
108 QTAILQ_HEAD(, UfsRequest
) req_list
; /* Free request list */
111 typedef struct UfsCq
{
115 uint16_t size
; /* A number of entries (qdepth) */
118 QTAILQ_HEAD(, UfsRequest
) req_list
;
121 typedef struct UfsHc
{
122 PCIDevice parent_obj
;
126 UfsMcqReg mcq_reg
[UFS_MAX_MCQ_QNUM
];
127 UfsMcqOpReg mcq_op_reg
[UFS_MAX_MCQ_QNUM
];
130 UfsRequest
*req_list
;
132 UfsLu
*lus
[UFS_MAX_LUS
];
137 DeviceDescriptor device_desc
;
138 GeometryDescriptor geometry_desc
;
139 Attributes attributes
;
147 UfsSq
*sq
[UFS_MAX_MCQ_QNUM
];
148 UfsCq
*cq
[UFS_MAX_MCQ_QNUM
];
151 static inline uint32_t ufs_mcq_sq_tail(UfsHc
*u
, uint32_t qid
)
153 return u
->mcq_op_reg
[qid
].sq
.tp
;
156 static inline void ufs_mcq_update_sq_tail(UfsHc
*u
, uint32_t qid
, uint32_t db
)
158 u
->mcq_op_reg
[qid
].sq
.tp
= db
;
161 static inline uint32_t ufs_mcq_sq_head(UfsHc
*u
, uint32_t qid
)
163 return u
->mcq_op_reg
[qid
].sq
.hp
;
166 static inline void ufs_mcq_update_sq_head(UfsHc
*u
, uint32_t qid
, uint32_t db
)
168 u
->mcq_op_reg
[qid
].sq
.hp
= db
;
171 static inline bool ufs_mcq_sq_empty(UfsHc
*u
, uint32_t qid
)
173 return ufs_mcq_sq_tail(u
, qid
) == ufs_mcq_sq_head(u
, qid
);
176 static inline uint32_t ufs_mcq_cq_tail(UfsHc
*u
, uint32_t qid
)
178 return u
->mcq_op_reg
[qid
].cq
.tp
;
181 static inline void ufs_mcq_update_cq_tail(UfsHc
*u
, uint32_t qid
, uint32_t db
)
183 u
->mcq_op_reg
[qid
].cq
.tp
= db
;
186 static inline uint32_t ufs_mcq_cq_head(UfsHc
*u
, uint32_t qid
)
188 return u
->mcq_op_reg
[qid
].cq
.hp
;
191 static inline void ufs_mcq_update_cq_head(UfsHc
*u
, uint32_t qid
, uint32_t db
)
193 u
->mcq_op_reg
[qid
].cq
.hp
= db
;
196 static inline bool ufs_mcq_cq_empty(UfsHc
*u
, uint32_t qid
)
198 return ufs_mcq_cq_tail(u
, qid
) == ufs_mcq_cq_head(u
, qid
);
201 #define TYPE_UFS "ufs"
202 #define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
204 #define TYPE_UFS_LU "ufs-lu"
205 #define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU)
207 typedef enum UfsQueryFlagPerm
{
208 UFS_QUERY_FLAG_NONE
= 0x0,
209 UFS_QUERY_FLAG_READ
= 0x1,
210 UFS_QUERY_FLAG_SET
= 0x2,
211 UFS_QUERY_FLAG_CLEAR
= 0x4,
212 UFS_QUERY_FLAG_TOGGLE
= 0x8,
215 typedef enum UfsQueryAttrPerm
{
216 UFS_QUERY_ATTR_NONE
= 0x0,
217 UFS_QUERY_ATTR_READ
= 0x1,
218 UFS_QUERY_ATTR_WRITE
= 0x2,
221 static inline bool is_wlun(uint8_t lun
)
223 return (lun
== UFS_UPIU_REPORT_LUNS_WLUN
||
224 lun
== UFS_UPIU_UFS_DEVICE_WLUN
|| lun
== UFS_UPIU_BOOT_WLUN
||
225 lun
== UFS_UPIU_RPMB_WLUN
);
228 void ufs_build_upiu_header(UfsRequest
*req
, uint8_t trans_type
, uint8_t flags
,
229 uint8_t response
, uint8_t scsi_status
,
230 uint16_t data_segment_length
);
231 void ufs_build_query_response(UfsRequest
*req
);
232 void ufs_complete_req(UfsRequest
*req
, UfsReqResult req_result
);
233 void ufs_init_wlu(UfsLu
*wlu
, uint8_t wlun
);
234 #endif /* HW_UFS_UFS_H */