UFS FFU 实践
前文提到ufs-utils这个工具可以做UFS FFU,我们先看这个工具的使用。
ufs-util
Android自带的aarch64貌似编译有问题,换个工具编译ok,ffu怎么用了?
./ufs-utils ffu --help
FFU command usage:
ufs-utils ffu [-t] <ffu cmd idn> [-p] <path to device>?
-t FFU cmd idn
0 : FFU, flash FFU
1 : Check FFU status (check FFU status attribute and display FW version)
-s Max chunk size in KB alignment to 4KB, which FFU file will be split (optional)
-w path to FFU file
-g sg struct ver - 0: SG_IO_VER4 (default), 1: SG_IO_VER3
-p bsg device path for FFU, ufs-bsg for Check FFU status
-p
的bsg device path就是前面提到的/dev/0:0:0:0(sg v4) or /dev/block/sda(sg v3)。
usf-bsg用于Check FFU status,device是/dev/ufs-bsg。
what is ufs bsg? 看文档:
BSG Support
This transport driver supports exchanging UFS protocol information units
(UPIUs) with a UFS device. Typically, user space will allocate
struct ufs_bsg_request and struct ufs_bsg_reply (see ufs_bsg.h) as
request_upiu and reply_upiu respectively. Filling those UPIUs should
be done in accordance with JEDEC spec UFS2.1 paragraph 10.7.
Caveat emptor: The driver makes no further input validations and sends the
UPIU to the device as it is. Open the bsg device in /dev/ufs-bsg and
send SG_IO with the applicable sg_io_v4::io_hdr_v4.guard = 'Q'; io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; io_hdr_v4.response = (__u64)reply_upiu; io_hdr_v4.max_response_len = reply_len; io_hdr_v4.request_len = request_len; io_hdr_v4.request = (__u64)request_upiu; if (dir == SG_DXFER_TO_DEV) { io_hdr_v4.dout_xfer_len = (uint32_t)byte_cnt; io_hdr_v4.dout_xferp = (uintptr_t)(__u64)buff; } else { io_hdr_v4.din_xfer_len = (uint32_t)byte_cnt; io_hdr_v4.din_xferp = (uintptr_t)(__u64)buff; }
config SCSI_UFS_BSG
bool "Universal Flash Storage BSG device node"
depends on SCSI_UFSHCD
select BLK_DEV_BSGLIB
help
Universal Flash Storage (UFS) is SCSI transport specification for
accessing flash storage on digital cameras, mobile phones and
consumer electronic devices.
A UFS controller communicates with a UFS device by exchanging
UFS Protocol Information Units (UPIUs).
UPIUs can not only be used as a transport layer for the SCSI protocol
but are also used by the UFS native command set.
This transport driver supports exchanging UFS protocol information units
with a UFS device. See also the ufshcd driver, which is a SCSI driver
that supports UFS devices.
Select this if you need a bsg device node for your UFS controller.
If unsure, say N.
重点是UPIUs are also used by the UFS native command set
。
ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
code是driver\scsi\ufs\ufs_bsg.c
。
/*
* bsg endpoint that supports UPIUs
*
* Copyright (C) 2018 Western Digital Corporation
*/
#include "ufs_bsg.h"
当前QCOM低内核还不支持ufs bsg,我从5.x port过来可以用了,有些接口小冲突需要fix。
不过drv有对应属性是:
UFS_ATTRIBUTE(ffu_status, _FFU_STATUS);
sysfs在:
What: /sys/bus/platform/drivers/ufshcd/*/attributes/ffu_status
Date: February 2018
Contact: Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
Description: This file provides the ffu status UFS device attribute.The full information about the attribute could be found at UFS specifications 2.1. The file is read only.
ufs spec的定义:
The column "MDV" (Manufacturer Default Value) specifies atrribute values after device manufacturing
就是出厂值是0了,升级成功是1。
ok,QCOM平台直接使用如下命令升级(固件升级文件是xxx.bin):
./ufs-utils ffu -t 0 -w xxx.bin -p /dev/block/sda
nm,报错了,一下心哇凉哇凉的:
Start : write_buffer mode 14 , buf_id 0
Start : send_scsi_cmd cmd = 3b len 262144 sg_type 0
writing file scsi_cmd_cdb_1.bin length=10
Err: Command fail with status 1 , senseKey Miscompare
Err: SG_IO WRITE BUFFER data error ret -22
Err: Write error -22:
工具默认没开debug,打开即可:
-#CXXFLAGS = -DDEBUG
+CXXFLAGS = -DDEBUG
senseKey Miscompare
是啥意思?我们先看工具code:
/* description of the sense key values */
static const char *const snstext[] = {
"No Sense", /* 0: There is no sense information */
"Recovered Error", /* 1: The last command completed successfully
but used error correction */
"Not Ready", /* 2: The addressed target is not ready */
"Medium Error", /* 3: Data error detected on the medium */
"Hardware Error", /* 4: Controller or device failure */
"Illegal Request", /* 5: Error in request */
"Unit Attention", /* 6: Removable medium was changed, or
the target has been reset, or ... */
"Data Protect", /* 7: Access to the data is blocked */
"Blank Check", /* 8: Reached unexpected written or unwritten
region of the medium */
"Vendor Specific",
"Copy Aborted", /* A: COPY or COMPARE was aborted */
"Aborted Command", /* B: The target aborted the command */
"Equal", /* C: A SEARCH DATA command found data equal */
"Volume Overflow", /* D: Medium full with still data to be written */
"Miscompare", /* E: Source data and data on the medium
do not agree */
/**
* send_scsi_cmd - Utility function for SCSI command sending
* @fd: bsg driver file descriptor
* @cdb: pointer to SCSI cmd cdb buffer
* @buf: pointer to the SCSI cmd data buffer
* @cmd_len: SCSI command length
* @byte_cnt: SCSI data length
* @dir: The cmd direction
*
**/
static int send_scsi_cmd(int fd, const __u8 *cdb, void *buf, __u8 cmd_len,
__u32 byte_cnt, int dir, __u8 sg_type)
{
...
else {
io_hdr_v3.interface_id = 'S';
io_hdr_v3.cmd_len = cmd_len;
io_hdr_v3.mx_sb_len = SENSE_BUFF_LEN;
io_hdr_v3.dxfer_direction = dir;
io_hdr_v3.dxfer_len = byte_cnt;
io_hdr_v3.dxferp = buf;
/* pointer to command buf (rbufCmdBlk) */
io_hdr_v3.cmdp = (unsigned char *)cdb;
io_hdr_v3.sbp = sense_buffer; //tj: here
io_hdr_v3.timeout = DEF_TIMEOUT_MSEC;
sg_struct = &io_hdr_v3;
}
WRITE_LOG("Start : %s cmd = %x len %d sg_type %d\n", __func__, cdb[0],
byte_cnt, sg_type);
write_file_with_counter("scsi_cmd_cdb_%d.bin",
cdb, cmd_len);
while (((ret = ioctl(fd, SG_IO, sg_struct)) < 0) &&
((errno == EINTR) || (errno == EAGAIN)));
if (sg_type == SG4_TYPE) {
if (io_hdr_v4.info != 0) {
print_error("Command fail with status %x , senseKey %s",
io_hdr_v4.info,
sense_key_string(sense_buffer[2]));
ret = -EINVAL;
}
}
else {
if (io_hdr_v3.status) {
print_error("Command fail with status %x , senseKey %s",
io_hdr_v3.status,
sense_key_string(sense_buffer[2]));
ret = -EINVAL;
}
}
用的是v3,io_hdr_v3.status
是1,ioctl cmd是SG_IO
。
看下v3 interface:
/*
* SCSI Generic v3 struct copied from include/scsi/sg.h
*/
typedef struct sg_io_hdr {
int interface_id; /* [i] 'S' for SCSI generic (required) */
int dxfer_direction; /* [i] data transfer direction */
unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
unsigned char mx_sb_len; /* [i] max length to write to sbp */
unsigned short int iovec_count; /* [i] 0 implies no scatter gather */
unsigned int dxfer_len; /* [i] byte count of data transfer */
void *dxferp; /* [i], [*io] points to data transfer memory
or scatter gather list */
unsigned char *cmdp; /* [i], [*i] points to command to perform */
unsigned char *sbp; /* [i], [*o] points to sense_buffer memory */ //tj:here
sbp
就是响应了,看样子是写进去了,怎么会不匹配,拍了拍脑袋想了想改了改代码居然可以了,容我慢慢道来:)
FFU was written to the device, reboot and check status
本站采用CC BY-NC-SA 4.0进行许可 | 转载请注明原文链接 - UFS FFU 实践
您好,这个页面底下的付费内容二维码存在问题,不是指向付款页面
已经fix了。
你好,能否帮忙发一下ufs-utils 的源码或编译后的bin文件,感谢!
这个不难吧,搜下就是了,github上也有,现在不做这些了。。。
好的 已经在github上找到了,感谢!