Linux内核SCSI子系统驱动架构.docx
《Linux内核SCSI子系统驱动架构.docx》由会员分享,可在线阅读,更多相关《Linux内核SCSI子系统驱动架构.docx(21页珍藏版)》请在冰豆网上搜索。
Linux内核SCSI子系统驱动架构
SCSI子系统驱动架构
2013-2-2
代码布局:
一、读写数据流:
drivers/scsi/scsi_lib.c
scsi_execute_req===>scsi_execute===>blk_execute_rq===>blk_execute_rq_nowait
错误恢复:
drivers/scsi/scsi_error.c
内核线程scsi_error_handler===>
二、初始化:
(本文!
)
--------------------------------------------------------------------------------------------------------------------
scsi高层(scsi磁盘)驱动:
1代码分布
2核心调用:
drivers/scsi/sd.c(这里以scsidisk设备为例)
同步执行部分:
sd_probe
异步执行部分:
sd_probe_async===>sd_revalidate_disk===>sd_spinup_disk
--------------------------------------------------------------------------------------------------------------------
scsi子系统核心初始化:
1代码分布
2核心调用:
scsi_init_queue();
scsi_init_procfs();
scsi_init_devinfo();
scsi_init_hosts();
scsi_init_sysctl();
scsi_sysfs_register();
scsi_netlink_init();
--------------------------------------------------------------------------------------------------------------------
scsi适配器驱动:
1代码分布
2核心调用:
drivers/scsi/hosts.c
1)、structScsi_Host*scsi_host_alloc(structscsi_host_template*sht,intprivsize)
2)、scsi_add_host(structScsi_Host*host,structdevice*dev)
===>scsi_add_host_with_dma(host,dev,dev)
intscsi_add_host_with_dma(structScsi_Host*shost,structdevice*dev,structdevice*dma_dev)
3)、scsi_scan_host===>do_scsi_scan_host===>scsi_scan_host_selected===>scsi_scan_channel
===>__scsi_scan_target===>scsi_probe_and_add_lun===>scsi_probe_lun
scsi_add_lun
代码骨架:
----------------------------------------------------------------------------------------------------------------------
scsi子系统核心初始化:
drivers/scsi/scsi.c:
staticstructclassshost_class={
.name="scsi_host",
.dev_release=scsi_host_cls_release,
};
staticstructclasssdev_class={
.name="scsi_device",
.dev_release=scsi_device_cls_release,
};
structbus_typescsi_bus_type={
.name="scsi",
.match=scsi_bus_match,
.uevent=scsi_bus_uevent,
};
subsys_initcall(init_scsi)===>
staticint__initinit_scsi(void)
{
scsi_init_queue();
scsi_init_procfs();
scsi_init_devinfo();//
scsi_init_hosts();//
scsi_init_sysctl();
scsi_sysfs_register();//
scsi_netlink_init();
}
intscsi_init_hosts(void)
{
returnclass_register(&shost_class);
}
intscsi_sysfs_register(void)
{
interror;
error=bus_register(&scsi_bus_type);
if(!
error){
class_register(&sdev_class);
}
}
----------------------------------------------------------------------------------------------------------------------
scsiHBA驱动:
(前端以dmx3191d为例)
staticstructscsi_host_templatedmx3191d_driver_template={
.name="DomexDMX3191D",
.queuecommand=NCR5380_queue_command,
......,
};
staticstructpci_device_iddmx3191d_pci_tbl[]={
{PCI_VENDOR_ID_DOMEX,PCI_DEVICE_ID_DOMEX_DMX3191D,
PCI_ANY_ID,PCI_ANY_ID,0,0,4},
{}
};
staticstructpci_driverdmx3191d_pci_driver={
.name=DMX3191D_DRIVER_NAME,
.id_table=dmx3191d_pci_tbl,
.probe=dmx3191d_probe_one,
.remove=__devexit_p(dmx3191d_remove_one),
};
module_init(dmx3191d_init);
staticint__initdmx3191d_init(void)
{
returnpci_register_driver(&dmx3191d_pci_driver);//调dmx3191d_probe_one
}
staticint__devinitdmx3191d_probe_one(structpci_dev*pdev,conststructpci_device_id*id)
{
structScsi_Host*shost;
......;
scsi_host_alloc(&dmx3191d_driver_template,sizeof(structNCR5380_hostdata));//------
shost->irq=pdev->irq;
request_irq(pdev->irq,NCR5380_intr,IRQF_SHARED,NAME,shost);
......;
scsi_add_host(shost,&pdev->dev);
scsi_scan_host(shost);
}
----------------------------------------------------------------------------------------------------------
drivers/scsi/hosts.c
staticatomic_tscsi_host_next_hn;
structScsi_Host*scsi_host_alloc(structscsi_host_template*sht,intprivsize)
{
structScsi_Host*shost;
gfp_tgfp_mask=GFP_KERNEL;
shost=kzalloc(sizeof(structScsi_Host)+privsize,gfp_mask);
shost->host_no=atomic_inc_return(&scsi_host_next_hn)-1;
device_initialize(&shost->shost_gendev);
shost->shost_gendev.bus=&scsi_bus_type;
shost->shost_gendev.type=&scsi_host_type;
......;
device_initialize(&shost->shost_dev);
shost->shost_dev.parent=&shost->shost_gendev;
shost->shost_dev.class=&shost_class;
returnshost;
}
include/scsi/scsi_host.h
staticinlineint__must_checkscsi_add_host(structScsi_Host*host,structdevice*dev)
{
returnscsi_add_host_with_dma(host,dev,dev);
}
drivers/scsi/hosts.c
intscsi_add_host_with_dma(structScsi_Host*shost,structdevice*dev,structdevice*dma_dev)
{
structscsi_host_template*sht=shost->hostt;
......;
device_add(&shost->shost_gendev);//------
device_add(&shost->shost_dev);
......;
scsi_sysfs_add_host(shost);
......;
}
----------------------------------------------------------------------------------------------------------------------
drivers/scsi/scsi_scan.c
#ifdefCONFIG_SCSI_SCAN_ASYNC//0
#defineSCSI_SCAN_TYPE_DEFAULT"async"
#else
#defineSCSI_SCAN_TYPE_DEFAULT"sync"
#endif
staticcharscsi_scan_type[6]=SCSI_SCAN_TYPE_DEFAULT;
//变量的值可以在加载scsi中间层模块时通过模块参数设定,未设定则用上面的默认值
module_param_string(scan,scsi_scan_type,sizeof(scsi_scan_type),S_IRUGO);
#definejiffiesraid6_jiffies()
//specifyscanningorrescanningofallpossiblechannels,(target)ids,orluns,onagivenshost.
#defineSCAN_WILD_CARD~0
#defineMAX_COMMAND_SIZE16
voidscsi_scan_host(structScsi_Host*shost)
{
structtask_struct*p;
structasync_scan_data*data;
if(strncmp(scsi_scan_type,"none",4)==0)
return;
data=scsi_prep_async_scan(shost);//异步扫描准备与判断shost->async_scan=1
if(!
data){//如果data=null,shost->async_scan仍为0
do_scsi_scan_host(shost);
return;//同步扫描逻辑,不需要任何准备工作
}
p=kthread_run(do_scan_async,data,"scsi_scan_%d",shost->host_no);//异步扫描逻辑
if(IS_ERR(p))//有错误时
do_scan_async(data);//shost->async_scan=0
}
staticvoiddo_scsi_scan_host(structScsi_Host*shost)
{
if(shost->hostt->scan_finished){
......;//自定义的扫描逻辑
}else{
//通配符SCAN_WILD_CARD~0,表示需要尝试所有可能的值
//rescan=0,表示第一次扫描,为1,表示重新扫描,即这个接口还有其他地方调用!
scsi_scan_host_selected(shost,SCAN_WILD_CARD,SCAN_WILD_CARD,SCAN_WILD_CARD,0);
}
}
intscsi_scan_host_selected(structScsi_Host*shost,unsignedintchannel,
unsignedintid,unsignedintlun,intrescan)
{
......;
//shost->async_scan:
是异步扫描标志,为1--异步扫描,0--同步扫描
if(!
shost->async_scan)
scsi_complete_async_scans();
if(scsi_host_scan_allowed(shost)){
if(channel==SCAN_WILD_CARD)
for(channel=0;channel<=shost->max_channel;channel++)
scsi_scan_channel(shost,channel,id,lun,rescan);
else
scsi_scan_channel(shost,channel,id,lun,rescan);
}
}
staticvoidscsi_scan_channel(structScsi_Host*shost,unsignedintchannel,
unsignedintid,unsignedintlun,intrescan)
{
uintorder_id;
if(id==SCAN_WILD_CARD)
for(id=0;idmax_id;++id){
if(shost->reverse_ordering)
order_id=shost->max_id-id-1;
else
order_id=id;
__scsi_scan_target(&shost->shost_gendev,channel,order_id,lun,rescan);
}
else
__scsi_scan_target(&shost->shost_gendev,channel,id,lun,rescan);//----
}
staticvoid__scsi_scan_target(structdevice*parent,unsignedintchannel,
unsignedintid,unsignedintlun,intrescan)
{
structScsi_Host*shost=dev_to_shost(parent);
intbflags=0;
intres;
structscsi_target*starget;
if(shost->this_id==id)
return;
starget=scsi_alloc_target(parent,channel,id);
if(lun!
=SCAN_WILD_CARD){
scsi_probe_and_add_lun(starget,lun,NULL,NULL,rescan,NULL);//---------
gotoout_reap;
}
res=scsi_probe_and_add_lun(starget,0,&bflags,NULL,rescan,NULL);//--------
if(res==SCSI_SCAN_LUN_PRESENT||res==SCSI_SCAN_TARGET_PRESENT){
//会调用scsi_probe_and_add_lun
if(scsi_report_lun_scan(starget,bflags,rescan)!
=0)
//会调用scsi_probe_and_add_lun
scsi_sequential_lun_scan(starget,bflags,starget->scsi_level,rescan);
}
out_reap:
scsi_target_reap(starget);
put_device(&starget->dev);
}
staticintscsi_probe_and_add_lun(structscsi_target*starget,uintlun,int*bflagsp,
structscsi_device**sdevp,intrescan,void*hostdata)
{
structscsi_device*sdev;
unsignedchar*result;
intbflags,result_len=256;
structScsi_Host*shost=dev_to_shost(starget->dev.parent);
sdev=scsi_device_lookup_by_target(starget,lun);
if(sdev){
if(rescan||!
scsi_device_created(sdev)){
if(sdevp)
*sdevp=sdev;
else
scsi_device_put(sdev);
if(bflagsp)
*bflagsp=scsi_get_device_flags(sdev,sdev->vendor,sdev->model);
returnSCSI_SCAN_LUN_PRESENT;
}
......;
}else
sdev=scsi_alloc_sdev(starget,lun,hostdata);//-----------
result=kmalloc(result_len,GFP_ATOMIC|((shost->unchecked_isa_dma)?
__GFP_DMA:
0));
scsi_probe_lun(sdev,result,result_len,&bflags);//----------
if(bflagsp)
*bflagsp=bflags;
......;
res=scsi_add_lun(sdev,result,&bflags,shost->async_scan);//---------
returnres;
}
staticstructscsi_device*scsi_alloc_sdev(structscsi_target*starget,unsignedintlun,void*hostdata)
{
structscsi_device*sdev;
structScsi_Host*shost=dev_to_shost(starget->dev.parent);
......;
sdev=kzalloc(sizeof(*sdev)+shost->transportt->device_size,GFP_ATOMIC);
......;
sdev->request_queue=scsi_alloc_queue(sdev);
......;
scsi_sysfs_device_initialize(sdev);//---------
......;
returnsdev;
}
voidscsi_sysfs_device_initialize(structscsi_device*sdev)
{
structScsi_Host*shost=sdev->host;
structscsi_target*starget=sdev->sdev_target;
device_initialize(&sdev->sdev_gendev);//
sdev->sdev_gendev.bus=&scsi_bus_type;
sdev->sdev_gendev.type=&scsi_dev_type;
......;
device_initialize(&sdev->sdev_dev);//
......;
sdev->scsi_level=starget->scsi_level;
list_add_tail(&sdev->same_target_siblings,&starget->device