scsi命令的第一次转变

1.6.5 scsi命令的第一次转变

前面介绍了读写文件时,是通过sd_init_command设置的scsi_cmnd命令结构,其实我们也可以通过scsi_execute_req函数直接发送scsi命令,不过需要两次转变。

 

仍然以scsi磁盘举例,最初scsi这边发送的是scsi命令,可是从block走就得变成request,然而走到磁盘那边又得变回scsi命令,换言之,这整个过程scsi命令要变两次身。

 

比如,我们想获得磁盘的容量,就可以直接调用:

cmd[0] = READ_CAPACITY;

res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,

              SD_TIMEOUT, SD_MAX_RETRIES);

 

首先让我们从scsi磁盘那边很常用的一个函数开始(比如sd_ioctl),我们来看scsi命令是如何在光天化日之下被偷梁换柱的变成了request,这个函数就是scsi_execute_req()。来自位于SCSI中间层的drivers/scsi/scsi_lib.c

 

    216 int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,

    217                      int data_direction, void *buffer, unsigned bufflen,

    218                      struct scsi_sense_hdr *sshdr, int timeout, int retries)

    219 {

    220         char *sense = NULL;

    221         int result;

    222

    223         if (sshdr) {

    224                 sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);

    225                 if (!sense)

    226                         return DRIVER_ERROR << 24;

    227         }

    228         result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,

    229                               sense, timeout, retries, 0);

    230         if (sshdr)

    231                 scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);

    232

    233         kfree(sense);

    234         return result;

    235 }

 

这里面最需要关注的就是一个函数,scsi_execute(),来自同一个文件:

 

    179 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,

    180                  int data_direction, void *buffer, unsigned bufflen,

    181                  unsigned char *sense, int timeout, int retries, int flags)

    182 {

    183         struct request *req;

    184         int write = (data_direction == DMA_TO_DEVICE);

    185         int ret = DRIVER_ERROR << 24;

    186

    187         req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);

    188

    189         if (bufflen &&  blk_rq_map_kern(sdev->request_queue, req,

    190                                         buffer, bufflen, __GFP_WAIT))

    191                 goto out;

    192

    193         req->cmd_len = COMMAND_SIZE(cmd[0]);

    194         memcpy(req->cmd, cmd, req->cmd_len);

    195         req->sense = sense;

    196         req->sense_len = 0;

    197         req->retries = retries;

    198         req->timeout = timeout;

    199         req->cmd_type = REQ_BLOCK_PC;

    200         req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT;

    201

    202         /*

    203          * head injection *required* here otherwise quiesce won't work

    204          */

    205         blk_execute_rq(req->q, NULL, req, 1);

    206

    207         ret = req->errors;

    208  out:

    209         blk_put_request(req);

    210

    211         return ret;

    212 }

 

首先被调用的是blk_get_request.来自block/ll_rw_blk.c:

 

   2215 struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask)

   2216 {

   2217         struct request *rq;

   2218

   2219         BUG_ON(rw != READ && rw != WRITE);

   2220

   2221         spin_lock_irq(q->queue_lock);

   2222         if (gfp_mask & __GFP_WAIT) {

   2223                 rq = get_request_wait(q, rw, NULL);

   2224         } else {

   2225                 rq = get_request(q, rw, NULL, gfp_mask);

   2226                 if (!rq)

   2227                         spin_unlock_irq(q->queue_lock);

   2228         }

   2229         /* q->queue_lock is unlocked at this point */

   2230

   2231         return rq;

   2232 }

 

注意到我们调用这个函数的时候,第二个参数确实是__GFP_WAIT。所以2223行会被执行。get_request_wait()来自同一个文件:

 

   2173 static struct request *get_request_wait(request_queue_t *q, int rw_flags,

   2174                                         struct bio *bio)

   2175 {

   2176         const int rw = rw_flags & 0x01;

   2177         struct request *rq;

   2178

   2179         rq = get_request(q, rw_flags, bio, GFP_NOIO);

   2180         while (!rq) {

   2181                 DEFINE_WAIT(wait);

   2182                 struct request_list *rl = &q->rq;

   2183

   2184                 prepare_to_wait_exclusive(&rl->wait[rw], &wait,

   2185                                 TASK_UNINTERRUPTIBLE);

   2186

   2187                 rq = get_request(q, rw_flags, bio, GFP_NOIO);

   2188

   2189                 if (!rq) {

   2190                         struct io_context *ioc;

   2191

   2192                         blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);

   2193

   2194                         __generic_unplug_device(q);

   2195                         spin_unlock_irq(q->queue_lock);

   2196                         io_schedule();

   2197

   2198                         /*

   2199                          * After sleeping, we become a "batching" process and

   2200                          * will be able to allocate at least one request, and

   2201                          * up to a big batch of them for a small period time.

   2202                          * See ioc_batching, ioc_set_batching

   2203                          */

   2204                         ioc = current_io_context(GFP_NOIO, q->node);

   2205                         ioc_set_batching(q, ioc);

   2206

   2207                         spin_lock_irq(q->queue_lock);

   2208                 }

   2209                 finish_wait(&rl->wait[rw], &wait);

   2210         }

   2211

   2212         return rq;

   2213 }

 

而真正被调用的又是get_request(),仍然是来自同一个文件。

 

   2068 static struct request *get_request(request_queue_t *q, int rw_flags,

   2069                                    struct bio *bio, gfp_t gfp_mask)

   2070 {

   2071         struct request *rq = NULL;

   2072         struct request_list *rl = &q->rq;

   2073         struct io_context *ioc = NULL;

   2074         const int rw = rw_flags & 0x01;

   2075         int may_queue, priv;

   2076

   2077         may_queue = elv_may_queue(q, rw_flags);

   2078         if (may_queue == ELV_MQUEUE_NO)

   2079                 goto rq_starved;

   2080

   2081         if (rl->count[rw]+1 >= queue_congestion_on_threshold(q)) {

   2082                 if (rl->count[rw]+1 >= q->nr_requests) {

   2083                         ioc = current_io_context(GFP_ATOMIC, q->node);

   2084                         /*

   2085                          * The queue will fill after this allocation, so set

   2086                          * it as full, and mark this process as "batching".

   2087                          * This process will be allowed to complete a batch of

   2088                          * requests, others will be blocked.

   2089                          */

   2090                         if (!blk_queue_full(q, rw)) {

   2091                                 ioc_set_batching(q, ioc);

   2092                                 blk_set_queue_full(q, rw);

   2093                         } else {

   2094                                 if (may_queue != ELV_MQUEUE_MUST

   2095                                                 && !ioc_batching(q, ioc)) {

   2096                                         /*

   2097                                          * The queue is full and the allocating

   2098                                          * process is not a "batcher", and not

   2099                                          * exempted by the IO scheduler

   2100                                          */

   2101                                         goto out;

   2102                                 }

   2103                         }

   2104                 }

   2105                 blk_set_queue_congested(q, rw);

   2106         }

   2107

   2108         /*

   2109          * Only allow batching queuers to allocate up to 50% over the defined

   2110          * limit of requests, otherwise we could have thousands of requests

   2111          * allocated with any setting of ->nr_requests

   2112          */

   2113         if (rl->count[rw] >= (3 * q->nr_requests / 2))

   2114                 goto out;

   2115

   2116         rl->count[rw]++;

   2117         rl->starved[rw] = 0;

   2118

   2119         priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);

   2120         if (priv)

   2121                 rl->elvpriv++;

   2122

   2123         spin_unlock_irq(q->queue_lock);

   2124

   2125         rq = blk_alloc_request(q, rw_flags, priv, gfp_mask);

   2126         if (unlikely(!rq)) {

   2127                 /*

   2128                  * Allocation failed presumably due to memory. Undo anything

   2129                  * we might have messed up.

   2130                  *

   2131                  * Allocating task should really be put onto the front of the

   2132                  * wait queue, but this is pretty rare.

   2133                  */

   2134                 spin_lock_irq(q->queue_lock);

   2135                 freed_request(q, rw, priv);

   2136

   2137                 /*

   2138                  * in the very unlikely event that allocation failed and no

   2139                  * requests for this direction was pending, mark us starved

   2140                  * so that freeing of a request in the other direction will

   2141                  * notice us. another possible fix would be to split the

   2142                  * rq mempool into READ and WRITE

   2143                  */

   2144 rq_starved:

   2145                 if (unlikely(rl->count[rw] == 0))

   2146                         rl->starved[rw] = 1;

   2147

   2148                 goto out;

   2149         }

   2150

   2151         /*

   2152          * ioc may be NULL here, and ioc_batching will be false. That's

   2153          * OK, if the queue is under the request limit then requests need

   2154          * not count toward the nr_batch_requests limit. There will always

   2155          * be some limit enforced by BLK_BATCH_TIME.

   2156          */

   2157         if (ioc_batching(q, ioc))

   2158                 ioc->nr_batch_requests--;

   2159

   2160         rq_init(q, rq);

   2161

   2162         blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);

   2163 out:

   2164         return rq;

   2165 }

 

这个elv_may_queue来自block/elevator.c

 

    848 int elv_may_queue(request_queue_t *q, int rw)

    849 {

    850         elevator_t *e = q->elevator;

    851

    852         if (e->ops->elevator_may_queue_fn)

    853                 return e->ops->elevator_may_queue_fn(q, rw);

    854

    855         return ELV_MQUEUE_MAY;

    856 }

 

属于我们的那个elevator_t结构体变量是当初我们在elevator_init()中调用elevator_alloc()申请的。它的ops显然是和具体我们采用了哪种电梯有关系的。这里我们为了简便起见,选择“noop”,这种最简单最原始的机制。再一次贴出它的elevator_type

 

     87 static struct elevator_type elevator_noop = {

     88         .ops = {

     89              .elevator_merge_req_fn          = noop_merged_requests,

     90                 .elevator_dispatch_fn           = noop_dispatch,

     91                 .elevator_add_req_fn            = noop_add_request,

     92                 .elevator_queue_empty_fn        = noop_queue_empty,

     93                 .elevator_former_req_fn         = noop_former_request,

     94                 .elevator_latter_req_fn         = noop_latter_request,

     95                 .elevator_init_fn               = noop_init_queue,

     96                 .elevator_exit_fn               = noop_exit_queue,

     97         },

     98         .elevator_name = "noop",

     99         .elevator_owner = THIS_MODULE,

    100 };

 

我们看到,对于我们选择的这种noop的电梯,elevator_may_queue_fn根本就没有定义。所以带着一个返回值ELV_MQUEUE_MAY,我们返回到get_request()中来。rl又是什么呢?2072行我们让它指向了q->rq,它就是request_queue

 

这里我们看到了rq其实是struct request_list结构体变量,在前面输入/输出调度程序中见过了。不过这些我们现在都不想看,我们想看的只有其中的几个函数,第一个是2125blk_alloc_request(),来自ll_rw_blk.c

 

   1970 static struct request *

   1971 blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask)

   1972 {

   1973         struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);

   1974

   1975         if (!rq)

   1976                 return NULL;

   1977

   1978         /*

   1979          * first three bits are identical in rq->cmd_flags and bio->bi_rw,

   1980          * see bio.h and blkdev.h

   1981          */

   1982         rq->cmd_flags = rw | REQ_ALLOCED;

   1983

   1984         if (priv) {

   1985                 if (unlikely(elv_set_request(q, rq, gfp_mask))) {

   1986                         mempool_free(rq, q->rq.rq_pool);

   1987                         return NULL;

   1988                 }

   1989                 rq->cmd_flags |= REQ_ELVPRIV;

   1990         }

   1991

   1992         return rq;

   1993 }

 

其它我们不懂没有关系,至少我们从1972行可以看出这里申请了一个struct request的结构体指针,换句话说,此前,我们已经有了请求队列,但是没有实质性的元素,从这一刻起,我们有了一个真正的request。虽然现在还没有进入到队伍中去,但这只是早晚的事儿了。请看下面:

 

下一个,get_request()2160行的rq_init()

 

    238 static void rq_init(request_queue_t *q, struct request *rq)

    239 {

    240         INIT_LIST_HEAD(&rq->queuelist);

    241         INIT_LIST_HEAD(&rq->donelist);

    242

    243         rq->errors = 0;

    244         rq->bio = rq->biotail = NULL;

    245         INIT_HLIST_NODE(&rq->hash);

    246         RB_CLEAR_NODE(&rq->rb_node);

    247         rq->ioprio = 0;

    248         rq->buffer = NULL;

    249         rq->ref_count = 1;

    250         rq->q = q;

    251         rq->special = NULL;

    252         rq->data_len = 0;

    253         rq->data = NULL;

    254         rq->nr_phys_segments = 0;

    255         rq->sense = NULL;

    256         rq->end_io = NULL;

    257         rq->end_io_data = NULL;

    258         rq->completion_data = NULL;

    259 }

 

这个函数在干什么?很简单,就是对刚申请的rq进行初始化。

 

然后,get_request()就开开心心的返回了,正常情况下,get_request_wait()也会跟着返回,再接着,blk_get_request()也就返回了。我们也带着申请好初始化好的req回到scsi_execute()中去,而接下来一段代码就是我们最关心的,对req的真正的赋值,比如req->cmd_lenreq->cmd等等,就是这样被赋上的。换言之,我们的scsi命令就是这样被request拖下水的,从此它们之间不再是以前那种“水留不住落花的漂泊,落花走不进水的世界”的关系,而是沦落到了一荣俱荣一损俱损狼狈为奸的关系。

 

至此,完成了第一次变身,从scsi命令到request的变身。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SCSI命令参考手册是一份重要的文档,用于指导和参考在SCSI(Small Computer System Interface)技术中使用的各种命令。该手册以PDF格式提供,可以提供快速和方便的访问。 SCSI是一种用于计算机系统中连接外部设备的接口标准,是一种高速、可靠的数据传输方式。SCSI命令参考手册的主要目的是为了帮助用户了解SCSI接口的标准命令集合,以及这些命令与外部设备之间的交互方式。 在SCSI命令参考手册中,用户可以找到关于每个命令的详细说明和使用指南。手册中列举了SCSI命令的各种参数、选项和标志,以及它们对应的功能和操作示例。此外,手册还提供了一些常见问题的解答和调试技巧,以帮助用户更好地理解和应用SCSI命令。 通过阅读SCSI命令参考手册,用户可以更好地理解SCSI接口和命令的工作原理,能够学习如何使用这些命令来管理和操作外部设备,如硬盘驱动器、光驱等。手册还可以作为开发人员编写SCSI驱动程序或应用程序时的参考工具。 总之,SCSI命令参考手册PDF是一份非常重要的文档,对于使用SCSI接口的计算机系统来说,它是必备的参考资料。通过阅读手册,用户可以更好地了解和应用SCSI命令,从而提高对外部设备的管理和控制能力。 ### 回答2: SCSI命令参考手册PDF是一本关于SCSI(小型计算机系统接口)命令的参考手册,通常以PDF格式提供。SCSI是一种用于计算机和外部设备之间通信的协议和接口标准。这个手册提供了有关SCSI命令的详细信息,可以帮助用户了解和使用SCSI命令来管理和控制连接到计算机的SCSI设备。 在这个手册中,用户可以找到所有标准SCSI命令的详细描述,包括命令的结构、参数和用途。这些命令可以用于各种操作,例如读取和写入数据、控制设备、进行错误处理等。此外,手册还提供了有关如何使用这些命令的示例和建议,以帮助用户更好地理解和使用SCSI命令SCSI命令参考手册PDF还可能包含其他有用的信息,例如SCSI标准规范、命令示意图、错误代码和解释等。用户可以通过查阅这些附加信息来深入了解SCSI协议和命令的工作原理和特性。 总之,SCSI命令参考手册PDF是一本为用户提供关于SCSI命令的详细信息和指导的参考手册。通过学习和熟悉这些命令,用户可以更有效地管理和控制与计算机连接的SCSI设备,提高其使用效率和性能。 ### 回答3: scsi命令参考手册pdf是一份关于SCSI(小型计算机系统接口)命令的参考文档,可以帮助用户了解SCSI协议及其命令的使用。 首先,SCSI是一种用于计算机系统的接口标准,用于连接计算机与外部设备,如硬盘驱动器、光驱等。SCSI命令参考手册pdf详细介绍了各种SCSI命令的功能、使用方法和参数,方便用户在使用SCSI设备时进行指令的发送和数据的传输。 该参考手册包含了大量的SCSI命令,例如数据读取、数据写入、设备查询、错误检测与纠正等。用户可以通过该手册了解如何通过SCSI命令来管理和控制外部设备,进行数据的读取和写入操作,并获取设备状态和错误信息。 此外,SCSI命令参考手册pdf还提供了命令的示例和实际应用场景,方便用户更好地理解和应用SCSI命令。手册中还包含了SCSI协议的相关知识和概念解释,有助于用户对SCSI技术有更全面的了解。 总之,SCSI命令参考手册pdf是一份非常有价值的参考资料,对于需要使用SCSI设备的用户来说,它是一个必备的工具。无论是初学者还是有经验的用户,都可以通过该手册快速学习和掌握SCSI命令的使用,提升设备管理和数据传输的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值