Chinaunix首页 | 论坛 | 博客
  • 博客访问: 169101
  • 博文数量: 22
  • 博客积分: 1632
  • 博客等级: 上尉
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-01 14:28
文章分类

全部博文(22)

文章存档

2010年(10)

2009年(3)

2008年(9)

分类: LINUX

2010-04-07 15:25:01

前一段时间在Linux平台上做了一个virtual SCSI host driver,该virtual scsi host driver主要实现将scsi command转换成块设备的请求,即将块设备伪装成一个标准scsi设备。在此对scsi host driver的编写做一下总结。

Scsi host driver的位置:

Scsi host driver位于SCSI中间层之下,属于SCSI总线控制器的驱动。如果有人做了一个SCSI适配器(host bus adapter),那么需要为该适配器写一个驱动,这个驱动就是scsi host driver。如果SCSI适配器是一个真实的硬件设备,绝大多数情况是采用PCI接口,那么scsi host driver也是一个PCI设备驱动。假设给一个真实的SCSI适配器写了一个驱动,那么内核驱动的体系结构如下图所示:

SCSI device driverSCSI设备驱动,也可以称之为功能驱动(Function driver)。SCSI middle level driverSCSI中间层驱动,抽象了SCSI的总线逻辑。Scsi host driver控制SCSI总线控制器,实现SCSI数据的物理层传输。

 

Scsi host模版:

Scsi host driver需要与scsi middle level进行数据交互,在scsi middle level定了标准的scsi host模版,所有接口函数和属性参数都定义在标准模版中。模版的类型为struct scsi_host_template

 

Virtual scsi host driver的模版定义如下:

struct scsi_host_template scsi_host_template = {

       .module                 = THIS_MODULE,

       .name                    = SCSI_HOST_IDENT,

       .info                      = scsi_info,

       .slave_configure     = scsi_slave_configure,

       .queuecommand     = scsi_queuecommand, 

       .can_queue            = SCSI_HOST_CAN_QUEUE,     /* host cmd queue depth */

       .cmd_per_lun         = SCSI_CMD_PER_LUN,     /* lun cmd queue depth */

       .sg_tablesize          = SG_ALL,

       .use_clustering       = SCSI_CLUSTERING,

       .this_id                  = SCSI_HOST_ID,

       .emulated              = 1,

};

 

       .queuecommand:通过该接口函数,scsi middle level将请求提交给scsi host driver。所以该函数是上下层之间的数据通道。

       .can_queue:描述了scsi host命令队列的长度。通常scsi host具有一个命令队列,scsi middle level通过queuecommand接口将命令直接挂入host的命令队列中,然后一步返回。

       .cmd_per_lun:该参数描述了每个lun通路所能缓存命令的数量。

       .sg_tablesizescatter-gather表的长度。

      

Scsi host的初始化:

       scsi host driver中首先需要定义一个描述host的结构。这个结构实际上是Scsi_Host的派生类,继承和扩展了Scsi_Host的功能。vscsi_host_svirtual scsi host driver中定义的结构。

 

typedef struct vscsi_host_s {

       __u32                   host_no;         /* host number, Major no */

       struct Scsi_Host     *scsi_host;     /* scsi host object */

      

       /* vscsi device array */

       struct vscsi_device_s    devices[MAX_CHANNEL][CHANNEL_DEV_NUM];

       atomic_t         dev_cnt;                /* vscsi device counters */

       struct semaphore    host_lock;      /* vscsi device access lock */

      

       /* vscsi command queue */

       struct bscsi_cmd_arr_s        vscsi_cmd_queue;

}vscsi_host_t;

 

ü         scsi_hostscsi middle level分配的scsi host对象指针。

ü         devicesvscsi_host控制器管理的设备,其中MAX_CHANNELvscsi_host最大的通道数,CHANNEL_DEV_NUMvscsi_host最大的lun数。

ü         dev_cnt描述了当前vscsi_host管理的设备数量。

ü         host_lock为设备访问锁。

ü         Vscsi_cmd_queuevscsi_host的命令队列。scsi middle level可以直接将scsi命令挂在该命令队列上。

 

Scsi host的初始化过程如下:

1、  理所当然,第一步需要初始化scsi host结构中的所有成员,例如vscsi_cmd_queue等。

2、  通过scsi_host_alloc函数让内核分配一个scsi host,调用方式为:shost = scsi_host_alloc(&scsi_host_template, sizeof(struct bscsi_host_s))。其中scsi_host_template为模版对象,即scsi host的属性以及接口方法。

3、  通过scsi_add_host函数将新分配的scsi host添加到系统中。调用如下:scsi_add_host(shost, NULL)

4、  调用scsi_scan_host(shost)扫描scsi host

 

Scsi device的初始化:

       scsi host驱动中,Scsi host控制的每个scsi设备都有一个对象。Virtual scsi driver中采用struct vscsi_device_s结构来描述。

      

       scsi host scan的过程中,驱动程序会扫描scsi host的每个channellun,然后回自动probe每个scsi device。在virtual scsi host driver中,用户可以手动的将一个设备添加到scsi host中,并且为其分配channleidlun

 

       添加scsi device的接口函数为__scsi_add_device,实现如下:

sdev = __scsi_add_device(vscsi_host->scsi_host, channel, id, lun, &vscsi_host);

bscsi_host->scsi_host为已经存在的scsi host对象。

channel, id, lun为新添加的scsi device标识。

vscsi_hostvscsi host的对象,将该scsi host对象告诉新创建的scsi device

 

通过__scsi_add_device函数,能够在scsi middle level创建一个scsi device,并且建立起scsi devicescsi host之间的关系。

 

Scsi数据传输方式:

       scsi middle level通过queuecommand函数将请求提交给scsi hostScsi middle level将获取的上层请求封装成scsi command,然后将scsi command递交给scsi host,也就是说scsi host层只能处理scsi command

 

       scsi command中存在两种数据传输方式:

1、  buffer的方式(Block-PC),这应该是SCSI驱动中较早的一种方式,其将数据存储在一个buffer中提交给scsi host

2、  scatter-gather方式。这种方式为聚散DMA方式,对于磁盘的读写基本都采用这种方式,scsi middle level可以很方便的将scsi disk driver提交的bio转换成scatter-gather table,而无须任何的数据拷贝。

 

为了达到软件兼容的目的,所以在处理scsi数据传输时,需要注意这两种传输方式。

Virtual scsi host原理:


阅读(1980) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~