int ucs_scsi_send_inquiry(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(cdb_param, SCSI_CDB_PARAM_LEN); STACKBUF_DMA_ALIGN(param, SCSI_INQUIRY_LEN); struct scsi_req_build_type req_upiu; memset(cdb_param, 0, SCSI_CDB_PARAM_LEN); cdb_param[0] = SCSI_CMD_INQUIRY; cdb_param[3] = sizeof(param)>> 8; cdb_param[4] = sizeof(param); /* Flush cdb to memory. */ dsb(); arch_invalidate_cache_range((addr_t) cdb_param, SCSI_CDB_PARAM_LEN); memset(&req_upiu, 0 , sizeof(struct scsi_req_build_type)); req_upiu.cdb = (addr_t) cdb_param; req_upiu.data_buffer_addr = (addr_t) param; req_upiu.data_len = SCSI_INQUIRY_LEN; req_upiu.flags = UPIU_FLAGS_READ; req_upiu.lun = 0; req_upiu.dd = UTRD_TARGET_TO_SYSTEM; if (ucs_do_scsi_cmd(dev, &req_upiu)) { dprintf(CRITICAL, "Failed to send SCSI inquiry\n"); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) param, SCSI_INQUIRY_LEN); return UFS_SUCCESS; }
int ucs_do_scsi_unmap(struct ufs_dev *dev, struct scsi_unmap_req *req) { STACKBUF_DMA_ALIGN(cdb_param, SCSI_CDB_PARAM_LEN); STACKBUF_DMA_ALIGN(param, sizeof(struct unmap_param_list)); struct scsi_req_build_type req_upiu; struct unmap_param_list *param_list; struct unmap_blk_desc *blk_desc; param_list = (struct unmap_param_list *)param; param_list->data_len = (sizeof(struct unmap_param_list) - 1) << 0x8; /* n-1 */ param_list->blk_desc_data_len = sizeof(struct unmap_blk_desc) << 0x8; blk_desc = &(param_list->blk_desc); blk_desc->lba = BE64(req->start_lba); blk_desc->num_blks = BE32(req->num_blocks); memset((void*)cdb_param, 0, SCSI_CDB_PARAM_LEN); cdb_param[0] = SCSI_CMD_UNMAP; cdb_param[1] = 0; /*ANCHOR = 0 for UFS*/ cdb_param[6] = 0; /*Group No = 0*/ cdb_param[7] = 0; /* Param list length is 1, we erase 1 contiguous blk*/ cdb_param[8] = sizeof(struct unmap_param_list); cdb_param[9] = 0; /* Flush cdb to memory. */ dsb(); arch_invalidate_cache_range((addr_t) cdb_param, SCSI_CDB_PARAM_LEN); memset((void*)&req_upiu, 0 , sizeof(struct scsi_req_build_type)); req_upiu.cdb = (addr_t) cdb_param; req_upiu.data_buffer_addr = (addr_t) param; req_upiu.data_len = sizeof(struct unmap_param_list); req_upiu.flags = UPIU_FLAGS_WRITE; req_upiu.lun = req->lun; req_upiu.dd = UTRD_SYSTEM_TO_TARGET; if (ucs_do_scsi_cmd(dev, &req_upiu)) { dprintf(CRITICAL, "Failed to send SCSI unmap command \n"); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) param, SCSI_INQUIRY_LEN); return UFS_SUCCESS; }
int dme_read_unit_desc(struct ufs_dev *dev, uint8_t index) { STACKBUF_DMA_ALIGN(unit_desc, sizeof(struct ufs_unit_desc)); struct ufs_unit_desc *desc = (struct ufs_unit_desc *) unit_desc; struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR, UFS_DESC_IDN_UNIT, index, 0, (addr_t) unit_desc, sizeof(struct ufs_unit_desc)}; if (dme_send_query_upiu(dev, &query)) { dprintf(CRITICAL, "%s:%d DME Read Unit Descriptor request failed\n", __func__, __LINE__); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_unit_desc)); dev->lun_cfg[index].logical_blk_cnt = BE64(desc->logical_blk_cnt); dev->lun_cfg[index].erase_blk_size = BE32(desc->erase_blk_size); // use only the lower 32 bits for rpmb partition size if (index == UFS_WLUN_RPMB) dev->rpmb_num_blocks = BE32(desc->logical_blk_cnt >> 32); return UFS_SUCCESS; }
int dme_set_fpoweronwpen(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(result, sizeof(uint32_t)); uint32_t try_again = DME_FPOWERONWPEN_RETRIES; struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_FLAG, UFS_IDX_fPowerOnWPEn, 0, 0, (addr_t) result, sizeof(uint32_t)}; struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG, UFS_IDX_fPowerOnWPEn, 0, 0, (addr_t) result, sizeof(uint32_t)}; if (dme_send_query_upiu(dev, &read_query)) { dprintf(CRITICAL, "%s:%d DME Power On Write Read Request failed\n", __func__, __LINE__); return -UFS_FAILURE; } arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t)); if (*result == 1) goto utp_set_fpoweronwpen_done; do { try_again--; dprintf(CRITICAL, "Power on Write Protect request failed. Retrying again.\n"); if (dme_send_query_upiu(dev, &set_query)) { dprintf(CRITICAL, "%s:%d DME Power On Write Set Request failed\n", __func__, __LINE__); return -UFS_FAILURE; } if (dme_send_query_upiu(dev, &read_query)) { dprintf(CRITICAL, "%s:%d DME Power On Write Read Request failed\n", __func__, __LINE__); return -UFS_FAILURE; } if (*result == 1) break; } while (try_again); utp_set_fpoweronwpen_done: dprintf(INFO,"Power on Write Protect status: %u\n", *result); return UFS_SUCCESS; }
int dme_set_fdeviceinit(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(result, sizeof(uint32_t)); uint32_t try_again = DME_FDEVICEINIT_RETRIES; struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_FLAG, UFS_IDX_fDeviceInit, 0, 0, (addr_t) result, sizeof(uint32_t)}; struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG, UFS_IDX_fDeviceInit, 0, 0, (addr_t) result, sizeof(uint32_t)}; if (dme_send_query_upiu(dev, &read_query)) { dprintf(CRITICAL, "%s:%d DME Device Init Read request failed\n", __func__, __LINE__); return -UFS_FAILURE; } arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t)); if (*result == 1) goto utp_set_fdeviceinit_done; do { try_again--; if (dme_send_query_upiu(dev, &set_query)) { dprintf(CRITICAL, "%s:%d DME Device Init Set request failed\n", __func__, __LINE__); return -UFS_FAILURE; } if (dme_send_query_upiu(dev, &read_query)) { dprintf(CRITICAL, "%s:%d DME Device Init Read request failed\n", __func__, __LINE__); return -UFS_FAILURE; } if (*result == 1) break; } while (try_again); utp_set_fdeviceinit_done: return UFS_SUCCESS; }
void fastboot_info(const char *reason) { STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE); if (fastboot_state != STATE_COMMAND) return; if (reason == 0) return; snprintf(response, MAX_RSP_SIZE, "INFO%s", reason); usb_write(response, strlen(response)); }
int dme_read_device_desc(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(dev_desc, sizeof(struct ufs_dev_desc)); STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_string_desc)); struct ufs_dev_desc *device_desc = (struct ufs_dev_desc *) dev_desc; struct ufs_string_desc *str_desc = (struct ufs_string_desc *) desc; struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR, UFS_DESC_IDN_DEVICE, 0, 0, (addr_t) dev_desc, sizeof(struct ufs_dev_desc)}; if (dme_send_query_upiu(dev, &query)) { dprintf(CRITICAL, "%s:%d DME Read Device Descriptor request failed\n", __func__, __LINE__); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) device_desc, sizeof(struct ufs_dev_desc)); /* Store all relevant data */ dev->num_lus = device_desc->num_lu; /* Get serial number for the device based on the string index. */ if (dme_read_string_desc(dev, device_desc->serial_num, (struct ufs_string_desc *) desc)) return -UFS_FAILURE; /* Flush buffer. */ arch_invalidate_cache_range((addr_t) str_desc, sizeof(struct ufs_string_desc)); dev->serial_num = dme_parse_serial_no(str_desc); return UFS_SUCCESS; }
void fastboot_ack(const char *code, const char *reason) { STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE); if (fastboot_state != STATE_COMMAND) return; if (reason == 0) reason = ""; snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason); fastboot_state = STATE_COMPLETE; usb_write(response, strlen(response)); }
static int ucs_do_request_sense(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sense_cdb)); struct scsi_req_build_type req_upiu; struct scsi_sense_cdb *cdb_param; uint8_t buf[SCSI_SENSE_BUF_LEN]; cdb_param = cdb; memset(cdb, 0, sizeof(struct scsi_sense_cdb)); cdb_param->opcode = SCSI_CMD_SENSE_REQ; cdb_param->alloc_len = SCSI_SENSE_BUF_LEN; /* Flush cdb to memory. */ dsb(); arch_invalidate_cache_range((addr_t) cdb_param, SCSI_CDB_PARAM_LEN); memset(&req_upiu, 0 , sizeof(struct scsi_req_build_type)); req_upiu.cdb = (addr_t) cdb_param; req_upiu.data_buffer_addr = (addr_t) buf; req_upiu.data_len = SCSI_SENSE_BUF_LEN; req_upiu.flags = UPIU_FLAGS_READ; req_upiu.lun = 0; req_upiu.dd = UTRD_TARGET_TO_SYSTEM; if (ucs_do_scsi_cmd(dev, &req_upiu)) { dprintf(CRITICAL, "ucs_do_request_sense: failed\n"); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) buf, SCSI_INQUIRY_LEN); dump_sense_buffer(buf, SCSI_SENSE_BUF_LEN); return UFS_SUCCESS; }
int dme_read_config_desc(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_config_desc)); struct ufs_config_desc *config_desc = (struct ufs_config_desc *)desc; struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR, UFS_DESC_IDN_CONFIGURATION, 0, 0, (addr_t) config_desc, sizeof(struct ufs_config_desc)}; if (dme_send_query_upiu(dev, &query)) { dprintf(CRITICAL, "%s:%d DME Read Config Descriptor request failed\n", __func__, __LINE__); return -UFS_FAILURE; } /* Flush buffer. */ arch_invalidate_cache_range((addr_t) config_desc, sizeof(struct ufs_config_desc)); return UFS_SUCCESS; }
int dme_read_geo_desc(struct ufs_dev *dev) { struct ufs_geometry_desc *desc; STACKBUF_DMA_ALIGN(geometry_desc, sizeof(struct ufs_geometry_desc)); desc = (struct ufs_geometry_desc *) geometry_desc; struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR, UFS_DESC_IDN_GEOMETRY, 0, 0, (addr_t) geometry_desc, sizeof(struct ufs_geometry_desc)}; if (dme_send_query_upiu(dev, &query)) { dprintf(CRITICAL, "%s:%d DME Read Geometry Descriptor request failed\n", __func__, __LINE__); return -UFS_FAILURE; } // Flush buffer. arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_geometry_desc)); dev->rpmb_rw_size = desc->rpmb_read_write_size; return UFS_SUCCESS; }
static void cmd_download(const char *arg, void *data, unsigned sz) { STACKBUF_DMA_ALIGN(response, MAX_RSP_SIZE); unsigned len = hex2unsigned(arg); int r; download_size = 0; if (len > download_max) { fastboot_fail("data too large"); return; } snprintf(response, MAX_RSP_SIZE, "DATA%08x", len); if (usb_write(response, strlen(response)) < 0) return; r = usb_read(download_base, len); if ((r < 0) || ((unsigned) r != len)) { fastboot_state = STATE_ERROR; return; } download_size = len; fastboot_okay(""); }
int dme_set_fpurgeenable(struct ufs_dev *dev) { STACKBUF_DMA_ALIGN(result, sizeof(uint32_t)); STACKBUF_DMA_ALIGN(status, sizeof(uint32_t)); uint32_t try_again = DME_BPURGESTATUS_RETRIES; struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG, UFS_IDX_fPurgeEn, 0, 0, (addr_t) result, sizeof(uint32_t)}; struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_ATTRIBUTE, UFS_IDX_bPurgeStatus, 0, 0, (addr_t)status, sizeof(uint32_t)}; if (dme_send_query_upiu(dev, &set_query)) { dprintf(CRITICAL, "%s:%d DME Purge Enable failed\n", __func__, __LINE__); return -UFS_FAILURE; } arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t)); dprintf(INFO, "%s:%d Purge enable status: %u\n", __func__,__LINE__, *result); do { *status = 0; arch_invalidate_cache_range((addr_t) status, sizeof(uint32_t)); if (dme_send_query_upiu(dev, &read_query)) { dprintf(CRITICAL, "%s:%d DME Purge Status Read failed\n", __func__, __LINE__); return -UFS_FAILURE; } switch (*status) { case 0x0: #ifdef DEBUG_UFS dprintf(INFO, "%s:%d Purge operation returning to ufs_erase. Purge Status 0x0\n", __func__, __LINE__); #endif return UFS_SUCCESS; case 0x3: #ifdef DEBUG_UFS dprintf(INFO, "%s:%d Purge operation has completed. Purge Status:0x3\n", __func__, __LINE__); #endif // next read of status will move to 0 continue; case 0x1: #ifdef DEBUG_UFS dprintf(INFO, "%s:%d Purge operation is still in progress.. Retrying\n", __func__, __LINE__); #endif try_again--; continue; case 0x2: dprintf(CRITICAL, "%s:%d Purge operation stopped prematurely\n", __func__, __LINE__); return -UFS_FAILURE; case 0x4: dprintf(CRITICAL, "%s:%d Purge operation failed due to logical unit queue not empty\n", __func__, __LINE__); return -UFS_FAILURE; case 0x5: dprintf(CRITICAL, "%s:%d Purge operation general failure\n", __func__, __LINE__); return -UFS_FAILURE; } } while((*status == 0x1 || *status == 0x3) && try_again); // should not come here dprintf(CRITICAL, "%s:%d Purge operation timed out after checking status %d times\n", __func__, __LINE__, DME_BPURGESTATUS_RETRIES); return -UFS_FAILURE; }
int ucs_do_scsi_read(struct ufs_dev *dev, struct scsi_rdwr_req *req) { STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_rdwr_cdb)); struct scsi_req_build_type req_upiu; struct scsi_rdwr_cdb *cdb_param; uint32_t blks_remaining; uint16_t blks_to_transfer; uint64_t bytes_to_transfer; uint32_t start_blk; uint32_t buf; blks_remaining = req->num_blocks; buf = req->data_buffer_base; start_blk = req->start_lba; cdb_param = (struct scsi_rdwr_cdb*) cdb; while (blks_remaining) { if (blks_remaining <= SCSI_MAX_DATA_TRANS_BLK_LEN) { blks_to_transfer = blks_remaining; blks_remaining = 0; } else { blks_to_transfer = SCSI_MAX_DATA_TRANS_BLK_LEN; blks_remaining -= SCSI_MAX_DATA_TRANS_BLK_LEN; } bytes_to_transfer = blks_to_transfer * UFS_DEFAULT_SECTORE_SIZE; memset(cdb_param, 0, sizeof(struct scsi_rdwr_cdb)); cdb_param->opcode = SCSI_CMD_READ10; cdb_param->cdb1 = SCSI_READ_WRITE_10_CDB1(0, 0, 1, 0); cdb_param->lba = BE32(start_blk); cdb_param->trans_len = BE16(blks_to_transfer); dsb(); arch_clean_invalidate_cache_range((addr_t) cdb_param, sizeof(struct scsi_rdwr_cdb)); memset(&req_upiu, 0 , sizeof(struct scsi_req_build_type)); req_upiu.cdb = (addr_t) cdb_param; req_upiu.data_buffer_addr = buf; req_upiu.data_len = bytes_to_transfer; req_upiu.flags = UPIU_FLAGS_READ; req_upiu.lun = req->lun; req_upiu.dd = UTRD_TARGET_TO_SYSTEM; if (ucs_do_scsi_cmd(dev, &req_upiu)) { dprintf(CRITICAL, "ucs_do_scsi_read: failed\n"); return -UFS_FAILURE; } buf += bytes_to_transfer; start_blk += SCSI_MAX_DATA_TRANS_BLK_LEN; } return UFS_SUCCESS; }