UFS发生命令超时处理流程
1. 在UFS的上层发送命令下来,如果上层30s没有收到ufs devices的response, 就会出现超时,此时会去查询命令是否真正的发送以及是否需要Abort 超时的命令
首先 我们先看数据传输是驱动程序的本质目的,通过数据的传输,来完成作为存储介质的使命,read & write,在read流程中,ufs向应用程序提供数据,在write流程中,应用程序向ufs存放数据。
本节分三个阶段关注数据的流向,分别是:系统调用数据到bio的组成,bio到电梯队列request的组成,request到controller的数据传输。主要围绕buffer和存储地址两个数据流要素,根据读流程描述各阶段这两个数据流要素的数据结构。
sys_read->submit_bio的流程
bio生成后,就plug到进程的plug_list里面,如果失败,则进电梯merge,如果依然失败,则只能等待新的request被释放出来,两次蓄流的目的是为了尽可能的让bio请求得到merge,减少往磁盘驱动下发的频度,提升综合性能
bio层->request的流程
当plug_list达到设定阈值或进程主动发起或设定时间已到或手机将要关机等,则会进行泄流。从elevator的queue里面取出一个request请求,下发到底层UFS驱动,这个流程从request转化为scsi协议包,最后封装在UFS的协议包UPIU包里面,于是就完成了一个请求的host内存准备,最后通过置这个请求对应的UFSHCI的doorbell寄存器中的mask,实现请求往驱动层的发送。
2. 接下来我们看看超时的具体流程和操作
```c
/**
* scsi_alloc_sdev - allocate and setup a scsi_Device
* @starget: which target to allocate a &scsi_device for
* @lun: which lun
* @hostdata: usually NULL and set by ->slave_alloc instead
*
* Description:
* Allocate, initialize for io, and return a pointer to a scsi_Device.
* Stores the @shost, @channel, @id, and @lun in the scsi_Device, and
* adds scsi_Device to the appropriate list.
*
* Return value:
* scsi_Device pointer, or NULL on failure.
**/
```
```c
scsi_alloc_sdev
|
if (shost_use_blk_mq(shost))
sdev->request_queue = scsi_mq_alloc_queue(sdev);
else
sdev->request_queue = scsi_old_alloc_queue(sdev);
|
blk_queue_rq_timed_out(q, scsi_times_out);
|
scsi_abort_command
|
queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
|
scmd_eh_abort_handler
|
scsi_try_to_abort_cmd
|
return hostt->eh_abort_handler(scmd);
|
.eh_abort_handler = ufshcd_abort
|
ufshcd_abort
```
/**
* ufshcd_abort - abort a specific command
* @cmd: SCSI command pointer
*
* Abort the pending command in device by sending UFS_ABORT_TASK task management
* command, and in host controller by clearing the door-bell register. There can
* be race between controller sending the command to the device while abort is
* issued. To avoid that, first issue UFS_QUERY_TASK to check if the command is
* really issued and then try to abort it.
*
* Returns SUCCESS/FAILED
*/
static int ufshcd_abort(struct scsi_cmnd *cmd)
{
struct Scsi_Host *host;
struct ufs_hba *hba;
unsigned long flags;
unsigned int tag;
int err = 0;
int poll_cnt;
u8 resp = 0xF;
struct ufshcd_lrb *lrbp;
u32 reg;
host = cmd->device->host;
hba = shost_priv(host);
tag = cmd->request->tag;
lrbp = &hba->lrb[tag];
if (!ufshcd_valid_tag(hba, tag)) {
dev_err(hba->dev,
"%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
__func__, tag, cmd, cmd->request);
BUG();
}
/*
* Task abort to the device W-LUN is illegal. When this command
* will fail, due to spec violation, scsi err handling next step
* will be to send LU reset which, again, is a spec violation.
* To avoid these unnecessary/illegal step we skip to the last error
* handling stage: reset and restore.
*/
if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN)
return ufshcd_eh_host_reset_handler(cmd);
ufshcd_hold(hba, false);
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
/* If command is already aborted/completed, return SUCCESS */
if (!(test_bit(tag, &hba->outstanding_reqs))) {
dev_err(hba->dev,
"%s: cmd at tag %d already completed, outstanding=0x%lx, doorbell=0x%x\n",
__func__, tag, hba->outstanding_reqs, reg);
goto out;
}
if (!(reg & (1 << tag))) {
dev_err(hba->dev,
"%s: cmd was completed, but without a notifying intr, tag = %d",
__func__, tag);
}
/* Print Transfer Request of aborted task */
dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
/*
* Print detailed info about aborted request.
* As more than one request might get aborted at the same time,
* print full information only for the first aborted request in order
* to reduce repeated printouts. For other aborted requests only print
* basic details.
*/
scsi_print_command(hba->lrb[tag].cmd);
if (!hba->req_abort_count) {
ufshcd_print_host_regs(hba);
ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
} else {
ufshcd_print_trs(hba, 1 << tag, false);
}
hba->req_abort_count++;
/* Skip task abort in case previous aborts failed and report failure */
if (lrbp->req_abort_skip) {
err = -EIO;
goto out;
}
for (poll_cnt = 100; poll_cnt; poll_cnt--) {
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
UFS_QUERY_TASK, &resp);
if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) {
/* cmd pending in the device */
dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n",
__func__, tag);
break;
} else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
/*
* cmd not pending in the device, check if it is
* in transition.
*/
dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n",
__func__, tag);
reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (reg & (1 << tag)) {
/* sleep for max. 200us to stabilize */
usleep_range(100, 200);
continue;
}
/* command completed already */
dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n",
__func__, tag);
goto out;
} else {
dev_err(hba->dev,
"%s: no response from device. tag = %d, err %d\n",
__func__, tag, err);
if (!err)
err = resp; /* service response error */
goto out;
}
}
if (!poll_cnt) {
err = -EBUSY;
goto out;
}
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
UFS_ABORT_TASK, &resp);
if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
if (!err) {
err = resp; /* service response error */
dev_err(hba->dev, "%s: issued. tag = %d, err %d\n",
__func__, tag, err);
}
goto out;
}
err = ufshcd_clear_cmd(hba, tag);
if (err) {
dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n",
__func__, tag, err);
goto out;
}
scsi_dma_unmap(cmd);
spin_lock_irqsave(host->host_lock, flags);
ufshcd_outstanding_req_clear(hba, tag);
hba->lrb[tag].cmd = NULL;
spin_unlock_irqrestore(host->host_lock, flags);
clear_bit_unlock(tag, &hba->lrb_in_use);
wake_up(&hba->dev_cmd.tag_wq);
out:
if (!err) {
err = SUCCESS;
} else {
dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
err = FAILED;
}
/*
* This ufshcd_release() corresponds to the original scsi cmd that got
* aborted here (as we won't get any IRQ for it).
*/
ufshcd_release(hba);
return err;
}
UFS发生命令超时处理流程相关推荐
- Go exec 包执行命令超时失效问题分析及解决方案
来自:指月 https://www.lixueduan.com 原文:https://www.lixueduan.com/post/go/exex-cmd-timeout/ 本文主要从源码层面分析了 ...
- UBOOT添加命令的执行流程
BootLoader(引导装载程序)是嵌入式系统软件开发的第一个环节,它把操作系统和硬件平台衔接在一起,对于嵌入式系统的后续软件开发十分重要,在整个开发中也占有相当大的比例.U-BOOT是当前比较流行 ...
- 南方cassCAD快捷命令对照设置流程
一.南方cassCAD快捷命令对照设置流程 以下为自编CAD快捷命令供大家参考,第一排为快捷命令,星号后为命令全称,命令文字解释. 自设快 命令全称 快捷命令中文解释 捷命令 FIND 在整个图形查找 ...
- golang 执行外部命令 超时处理 exec.CommandContext
使用exec.CommandContext来处理外部命令的超时 func main() {timeout := 5ctx, cancel := context.WithTimeout(context. ...
- linux expect 自动交互 执行命令 超时 不完整 中断 解决方法
使用 expec t自动交互执行命令时,默认超时timeout为30s 手动添加set timeout -1设置 超时时间为无穷大 就可以执行完命令了 通过expect执行scp,传输文件不完整 写了 ...
- linux host命令超时,Linux中的PING命令。每日一个小知识。不怕学不会
PING(数据包Internet Groper)命令用于检查主机与服务器/主机之间的网络连接.该命令以IP地址或URL为输入,并通过消息" PING"将数据包发送到指定的地址,并记 ...
- Mybatis3.3.x技术内幕(十一):执行一个Sql命令的完整流程
2019独角兽企业重金招聘Python工程师标准>>> Mybatis中的Sql命令,在枚举类SqlCommandType中定义的. public enum SqlCommandTy ...
- 在郊区发生交通事故的处理流程
最近两年碰上了两起位于郊区的交通事故,最终的结果都是在警方的"善意"调解下导致自己吃了个懵亏,进行了所谓的"互碰自赔".用自己的交强险修了自己的车. 总结下来, ...
- 第一个redis应用方法导致的提示redis LRANGE命令超时问题的解决
我的第一个redis应用的方法代码如下: public List<QuestionsLibrary> GetRedisQuestionsLibraryList() { var qlist ...
最新文章
- 博客园的“随笔、文章、新闻、日记有啥区别”
- 简易嵌入式管理平台 C 实现
- 理论+实践,带你掌握动态规划法
- JAVA反射系列之Method,java.lang.reflect.Method的使用。
- VMware虚拟机XP系统安装教程
- RFID技术在图书馆中的应用
- SPSS 25.0中文版安装教程【001期】
- windows平台服务监控邮件报警批处理脚本
- 计算机处理器性能排名,2019电脑cpu处理器性能排名:AMD 32核撕裂者遥遥领先(2)...
- CTS、CLS和CLR
- 深度学习(十三) Adversarial Attack 理论部分
- 19、Jetson Xavier NX使用yolov5对比GPU模型下的pt、onnx、engine 、 DeepStream 加速性能
- 壹度同城新零售系统v4.1.23 社交电商 同城商城
- 彻底解决The last packet successfully received from the server was * milliseconds ago问题
- 雷电模拟器忘记锁屏密码
- vim替换字符串带斜杠_VI中的查找和替换
- 剑已配好,我们江湖见
- COLA 2.0架构应用
- win10开机“正在准备自动修复”,且无法修复你的电脑
- 光伏mppt扰动观察法仿真,matlab2018a