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发生命令超时处理流程相关推荐

  1. Go exec 包执行命令超时失效问题分析及解决方案

    来自:指月 https://www.lixueduan.com 原文:https://www.lixueduan.com/post/go/exex-cmd-timeout/ 本文主要从源码层面分析了 ...

  2. UBOOT添加命令的执行流程

    BootLoader(引导装载程序)是嵌入式系统软件开发的第一个环节,它把操作系统和硬件平台衔接在一起,对于嵌入式系统的后续软件开发十分重要,在整个开发中也占有相当大的比例.U-BOOT是当前比较流行 ...

  3. 南方cassCAD快捷命令对照设置流程

    一.南方cassCAD快捷命令对照设置流程 以下为自编CAD快捷命令供大家参考,第一排为快捷命令,星号后为命令全称,命令文字解释. 自设快 命令全称 快捷命令中文解释 捷命令 FIND 在整个图形查找 ...

  4. golang 执行外部命令 超时处理 exec.CommandContext

    使用exec.CommandContext来处理外部命令的超时 func main() {timeout := 5ctx, cancel := context.WithTimeout(context. ...

  5. linux expect 自动交互 执行命令 超时 不完整 中断 解决方法

    使用 expec t自动交互执行命令时,默认超时timeout为30s 手动添加set timeout -1设置 超时时间为无穷大 就可以执行完命令了 通过expect执行scp,传输文件不完整 写了 ...

  6. linux host命令超时,Linux中的PING命令。每日一个小知识。不怕学不会

    PING(数据包Internet Groper)命令用于检查主机与服务器/主机之间的网络连接.该命令以IP地址或URL为输入,并通过消息" PING"将数据包发送到指定的地址,并记 ...

  7. Mybatis3.3.x技术内幕(十一):执行一个Sql命令的完整流程

    2019独角兽企业重金招聘Python工程师标准>>> Mybatis中的Sql命令,在枚举类SqlCommandType中定义的. public enum SqlCommandTy ...

  8. 在郊区发生交通事故的处理流程

    最近两年碰上了两起位于郊区的交通事故,最终的结果都是在警方的"善意"调解下导致自己吃了个懵亏,进行了所谓的"互碰自赔".用自己的交强险修了自己的车. 总结下来, ...

  9. 第一个redis应用方法导致的提示redis LRANGE命令超时问题的解决

    我的第一个redis应用的方法代码如下: public List<QuestionsLibrary> GetRedisQuestionsLibraryList() { var qlist ...

最新文章

  1. 博客园的“随笔、文章、新闻、日记有啥区别”
  2. 简易嵌入式管理平台 C 实现
  3. 理论+实践,带你掌握动态规划法
  4. JAVA反射系列之Method,java.lang.reflect.Method的使用。
  5. VMware虚拟机XP系统安装教程
  6. RFID技术在图书馆中的应用
  7. SPSS 25.0中文版安装教程【001期】
  8. windows平台服务监控邮件报警批处理脚本
  9. 计算机处理器性能排名,2019电脑cpu处理器性能排名:AMD 32核撕裂者遥遥领先(2)...
  10. CTS、CLS和CLR
  11. 深度学习(十三) Adversarial Attack 理论部分
  12. 19、Jetson Xavier NX使用yolov5对比GPU模型下的pt、onnx、engine 、 DeepStream 加速性能
  13. 壹度同城新零售系统v4.1.23 社交电商 同城商城
  14. 彻底解决The last packet successfully received from the server was * milliseconds ago问题
  15. 雷电模拟器忘记锁屏密码
  16. vim替换字符串带斜杠_VI中的查找和替换
  17. 剑已配好,我们江湖见
  18. COLA 2.0架构应用
  19. win10开机“正在准备自动修复”,且无法修复你的电脑
  20. 光伏mppt扰动观察法仿真,matlab2018a

热门文章

  1. 软考 第十一章 软件知识产权基础知识
  2. iOS开发:获取WiFi名称(解决iOS12.0以上系统不能正常获取WiFi名称的方法)
  3. 微信公众号运营数据分析
  4. resulful规范_ResultFul API
  5. aliyun的产品都是有哪些,主要是做什么的呢?
  6. 数据库:常用数据库的创建
  7. 交换机远程连接(eNsp)
  8. U盘和电脑USB都是好的,可是插上u盘没任何反应!
  9. 【最终省二】全国大学生数学建模大赛-参赛经历
  10. 李宏毅《机器学习》误差