1bc4e68d3SJeuk Kim /* 2bc4e68d3SJeuk Kim * QEMU UFS 3bc4e68d3SJeuk Kim * 4bc4e68d3SJeuk Kim * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. 5bc4e68d3SJeuk Kim * 6bc4e68d3SJeuk Kim * Written by Jeuk Kim <jeuk20.kim@samsung.com> 7bc4e68d3SJeuk Kim * 8bc4e68d3SJeuk Kim * SPDX-License-Identifier: GPL-2.0-or-later 9bc4e68d3SJeuk Kim */ 10bc4e68d3SJeuk Kim 11bc4e68d3SJeuk Kim #ifndef HW_UFS_UFS_H 12bc4e68d3SJeuk Kim #define HW_UFS_UFS_H 13bc4e68d3SJeuk Kim 14bc4e68d3SJeuk Kim #include "hw/pci/pci_device.h" 15bc4e68d3SJeuk Kim #include "hw/scsi/scsi.h" 16bc4e68d3SJeuk Kim #include "block/ufs.h" 17bc4e68d3SJeuk Kim 18bc4e68d3SJeuk Kim #define UFS_MAX_LUS 32 19*096434feSJeuk Kim #define UFS_BLOCK_SIZE_SHIFT 12 20*096434feSJeuk Kim #define UFS_BLOCK_SIZE (1 << UFS_BLOCK_SIZE_SHIFT) 21bc4e68d3SJeuk Kim 222a8b36a4SJeuk Kim typedef struct UfsBusClass { 232a8b36a4SJeuk Kim BusClass parent_class; 242a8b36a4SJeuk Kim bool (*parent_check_address)(BusState *bus, DeviceState *dev, Error **errp); 252a8b36a4SJeuk Kim } UfsBusClass; 262a8b36a4SJeuk Kim 272a8b36a4SJeuk Kim typedef struct UfsBus { 28*096434feSJeuk Kim BusState parent_bus; 292a8b36a4SJeuk Kim } UfsBus; 302a8b36a4SJeuk Kim 312a8b36a4SJeuk Kim #define TYPE_UFS_BUS "ufs-bus" 322a8b36a4SJeuk Kim DECLARE_OBJ_CHECKERS(UfsBus, UfsBusClass, UFS_BUS, TYPE_UFS_BUS) 332a8b36a4SJeuk Kim 34329f1662SJeuk Kim typedef enum UfsRequestState { 35329f1662SJeuk Kim UFS_REQUEST_IDLE = 0, 36329f1662SJeuk Kim UFS_REQUEST_READY = 1, 37329f1662SJeuk Kim UFS_REQUEST_RUNNING = 2, 38329f1662SJeuk Kim UFS_REQUEST_COMPLETE = 3, 39329f1662SJeuk Kim UFS_REQUEST_ERROR = 4, 40329f1662SJeuk Kim } UfsRequestState; 41329f1662SJeuk Kim 42329f1662SJeuk Kim typedef enum UfsReqResult { 43329f1662SJeuk Kim UFS_REQUEST_SUCCESS = 0, 44329f1662SJeuk Kim UFS_REQUEST_FAIL = 1, 452a8b36a4SJeuk Kim UFS_REQUEST_NO_COMPLETE = 2, 46329f1662SJeuk Kim } UfsReqResult; 47329f1662SJeuk Kim 48329f1662SJeuk Kim typedef struct UfsRequest { 49329f1662SJeuk Kim struct UfsHc *hc; 50329f1662SJeuk Kim UfsRequestState state; 51329f1662SJeuk Kim int slot; 52329f1662SJeuk Kim 53329f1662SJeuk Kim UtpTransferReqDesc utrd; 54329f1662SJeuk Kim UtpUpiuReq req_upiu; 55329f1662SJeuk Kim UtpUpiuRsp rsp_upiu; 56329f1662SJeuk Kim 57329f1662SJeuk Kim /* for scsi command */ 58329f1662SJeuk Kim QEMUSGList *sg; 59*096434feSJeuk Kim uint32_t data_len; 60329f1662SJeuk Kim } UfsRequest; 61329f1662SJeuk Kim 62*096434feSJeuk Kim struct UfsLu; 63*096434feSJeuk Kim typedef UfsReqResult (*UfsScsiOp)(struct UfsLu *, UfsRequest *); 64*096434feSJeuk Kim 652a8b36a4SJeuk Kim typedef struct UfsLu { 66*096434feSJeuk Kim DeviceState qdev; 672a8b36a4SJeuk Kim uint8_t lun; 682a8b36a4SJeuk Kim UnitDescriptor unit_desc; 69*096434feSJeuk Kim SCSIBus bus; 70*096434feSJeuk Kim SCSIDevice *scsi_dev; 71*096434feSJeuk Kim BlockConf conf; 72*096434feSJeuk Kim UfsScsiOp scsi_op; 732a8b36a4SJeuk Kim } UfsLu; 742a8b36a4SJeuk Kim 75bc4e68d3SJeuk Kim typedef struct UfsParams { 76bc4e68d3SJeuk Kim char *serial; 77bc4e68d3SJeuk Kim uint8_t nutrs; /* Number of UTP Transfer Request Slots */ 78bc4e68d3SJeuk Kim uint8_t nutmrs; /* Number of UTP Task Management Request Slots */ 79bc4e68d3SJeuk Kim } UfsParams; 80bc4e68d3SJeuk Kim 81bc4e68d3SJeuk Kim typedef struct UfsHc { 82bc4e68d3SJeuk Kim PCIDevice parent_obj; 832a8b36a4SJeuk Kim UfsBus bus; 84bc4e68d3SJeuk Kim MemoryRegion iomem; 85bc4e68d3SJeuk Kim UfsReg reg; 86bc4e68d3SJeuk Kim UfsParams params; 87bc4e68d3SJeuk Kim uint32_t reg_size; 88329f1662SJeuk Kim UfsRequest *req_list; 89329f1662SJeuk Kim 902a8b36a4SJeuk Kim UfsLu *lus[UFS_MAX_LUS]; 91*096434feSJeuk Kim UfsLu report_wlu; 92*096434feSJeuk Kim UfsLu dev_wlu; 93*096434feSJeuk Kim UfsLu boot_wlu; 94*096434feSJeuk Kim UfsLu rpmb_wlu; 95329f1662SJeuk Kim DeviceDescriptor device_desc; 96329f1662SJeuk Kim GeometryDescriptor geometry_desc; 97329f1662SJeuk Kim Attributes attributes; 98329f1662SJeuk Kim Flags flags; 99bc4e68d3SJeuk Kim 100bc4e68d3SJeuk Kim qemu_irq irq; 101bc4e68d3SJeuk Kim QEMUBH *doorbell_bh; 102bc4e68d3SJeuk Kim QEMUBH *complete_bh; 103bc4e68d3SJeuk Kim } UfsHc; 104bc4e68d3SJeuk Kim 105bc4e68d3SJeuk Kim #define TYPE_UFS "ufs" 106bc4e68d3SJeuk Kim #define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS) 107bc4e68d3SJeuk Kim 1082a8b36a4SJeuk Kim #define TYPE_UFS_LU "ufs-lu" 1092a8b36a4SJeuk Kim #define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU) 1102a8b36a4SJeuk Kim 111329f1662SJeuk Kim typedef enum UfsQueryFlagPerm { 112329f1662SJeuk Kim UFS_QUERY_FLAG_NONE = 0x0, 113329f1662SJeuk Kim UFS_QUERY_FLAG_READ = 0x1, 114329f1662SJeuk Kim UFS_QUERY_FLAG_SET = 0x2, 115329f1662SJeuk Kim UFS_QUERY_FLAG_CLEAR = 0x4, 116329f1662SJeuk Kim UFS_QUERY_FLAG_TOGGLE = 0x8, 117329f1662SJeuk Kim } UfsQueryFlagPerm; 118329f1662SJeuk Kim 119329f1662SJeuk Kim typedef enum UfsQueryAttrPerm { 120329f1662SJeuk Kim UFS_QUERY_ATTR_NONE = 0x0, 121329f1662SJeuk Kim UFS_QUERY_ATTR_READ = 0x1, 122329f1662SJeuk Kim UFS_QUERY_ATTR_WRITE = 0x2, 123329f1662SJeuk Kim } UfsQueryAttrPerm; 124329f1662SJeuk Kim 1252a8b36a4SJeuk Kim static inline bool is_wlun(uint8_t lun) 1262a8b36a4SJeuk Kim { 1272a8b36a4SJeuk Kim return (lun == UFS_UPIU_REPORT_LUNS_WLUN || 1282a8b36a4SJeuk Kim lun == UFS_UPIU_UFS_DEVICE_WLUN || lun == UFS_UPIU_BOOT_WLUN || 1292a8b36a4SJeuk Kim lun == UFS_UPIU_RPMB_WLUN); 1302a8b36a4SJeuk Kim } 1312a8b36a4SJeuk Kim 132*096434feSJeuk Kim void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags, 133*096434feSJeuk Kim uint8_t response, uint8_t scsi_status, 134*096434feSJeuk Kim uint16_t data_segment_length); 135*096434feSJeuk Kim void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); 136*096434feSJeuk Kim void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); 137bc4e68d3SJeuk Kim #endif /* HW_UFS_UFS_H */ 138