1. 前言
本专题我们开始学习SCSI子系统的相关内容。本专题主要参考了《存储技术原理分析》、ULA、ULK的相关内容。本专题主要以硬件UFS为例,记录SCSI子系统的框架流程。
前面主要讲述了UFS的初始化过程,通过ufshcd_pltfrm_init负责获取IO资源,中断号,通过scsi_host_alloc为Scsi_host及私有数据空间hba分配空间,同时通过解析DTS中的属性值初始化hba相关成员,最后通过ufshcd_init对ufs controller进行初始化,并ufshcd_async_scan对链接的ufs device进行扫描。主要通过探测ufs device是否链接,如果探测到ufs device则检测是否ufs device已经ready,获取host和device都能支持的传输速率,最后扫描well known lun和normal lun。
在如上的初始化完毕之后,就可以对ufs设备进行io操作了,上层的的IO操作将最终转换为对底层UFS的命令处理,本节将介绍UFS命令处理的相关流程。
kernel版本:5.10
平台:arm64
注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“
2. scsi_queue_rq
参考 block多队列分析 - 3. 读文件过程 的分析,我们知道通过文件系统读取块设备上的文件时,经历了如下的流程(以ext4, nullb为例):
vfs_read -> new_sync_read -> ext4_file_read_iter -> generic_file_read_iter -> generic_file_buffered_read -> page_cache_async_readahead -> page_cache_async_ra -> ondemand_readahead -> do_page_cache_ra -> page_cache_ra_unbounded -> read_pages -> blk_finish_plug -> blk_flush_plug_list -> blk_mq_flush_plug_list -> blk_mq_sched_insert_requests -> blk_mq_run_hw_queue -> __blk_mq_delay_run_hw_queue -> blk_mq_run_work_fn -> __blk_mq_run_hw_queue -> blk_mq_dispatch_rq_list -> q->mq_ops->queue_rq
对于此处的q->mq_ops->queue_rq,通过ufs_qcom_probe -> ufshcd_init -> scsi_add_host -> scsi_mq_setup_tags可知:
tag_set->ops = &scsi_mq_ops;
而在ufs_qcom_probe -> ufshcd_init -> blk_mq_init_queue -> blk_mq_init_allocated_queue中:
q->mq_ops = set->ops;
由此可知,q->mq_ops就是scsi_mq_ops,q->mq_ops->queue_rq就是scsi_queue_rq
static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,const struct blk_mq_queue_data *bd)
|--struct request *req = bd->rq;
| struct request_queue *q = req->q;
| struct scsi_device *sdev = q->queuedata;
| struct Scsi_Host *shost = sdev->host;
| struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req)
|--scsi_set_resid(cmd, 0);
|--memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
|--cmd->scsi_done = scsi_mq_done;
|--blk_mq_start_request(req);
| |--blk_add_timer(rq);
| //Dispatch a command to the low-level driver
|--reason = scsi_dispatch_cmd(cmd)
|--struct Scsi_Host *host = cmd->device->host;
|--if (cmd->device->lun_in_cdb)
| cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | (cmd->device->lun << 5 & 0xe0);
|--host->hostt->queuecommand(host, cmd);
当scsi_dispatch_cmd进行命令分发的时候,最终会调用到host->hostt->queuecommand(host, cmd)回调函数。这个回调函数的参数host为scsi_host,cmd为scsi_cmd,他将传递给更下层的ufs层去执行,UFS层对应的queuecommand回调函数为ufshcd_queuecommand,它定义了tatic struct scsi_host_template ufshcd_driver_template模板中,通过ufshcd_alloc_host->scsi_host_alloc赋值给shost->hostt
|- -ufshcd_queuecommand
static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
|--struct ufshcd_lrb *lrbp;
| hba = shost_priv(host);
| tag = cmd->request->tag;
|--err = ufshcd_hold(hba, true);
|--lrbp = &hba->lrb[tag];
| lrbp->cmd = cmd

 - 3. UFS命令处理&spm=1001.2101.3001.5002&articleId=116749869&d=1&t=3&u=aa0ae031c4ac45969d7a482f318d1851)
4285

被折叠的 条评论
为什么被折叠?



