AnintroductiontoSCSIdriversAnintroductiontoSCSIdriversAnintroductiontoSCSIdriversAlanCoxalan@redhat.
com1.
CopyrightandLicensingCopyright(c)1999byAlanCox.
ThismaterialmaybedistributedonlysubjecttothetermsandconditionssetforthintheOpenPublicationLicense,v0.
4(8June1999)orlater(thelatestversionispresentlyavailableathttp://www.
opencontent.
org/openpub/).
2.
AnIntroductiontoSCSIDriversForthismonthsarticleI'mgoingtoattempttocoverwritingadriverforasimpleSCSIcontrollerunderLinux.
TheLinuxkerneldoesmostoftheworkforSCSIdevicessoa'dumb'SCSIinterfacecanactuallyberelativelypainlesstowrite.
FormoreadvanceddeviceshowevertheSCSIlayerisactuallytooclever.
Thereareplansafoottostreamlineitbecauseofthis.
ThejoboftheSCSIdriverisdifferenttothatofablockdriver.
TheupperlayersoftheSCSIcodehandletheCD-ROM,Diskandotherdevices.
RequestsareturnedintoSCSIcommandblocksbeforetheyarefedtoyourdriver.
ThismeansyourSCSIdriverneedonlyworryaboutSCSIandnotaboutotheraspectsofthekerneldevicestructure.
InordertoillustratetheSCSIdriversI'mgoingtoinventaSCSIcontrollerthathasasimpleandeasytousecommandinterface.
Theysadlydon'ttendtoexist.
Itdoeshowevermakeitaloteasiertofollowtheexample.
EvensowithinthelimitsofamagazineIcanonlycoverthebasicsandhopefullyenoughtogetpeoplestarted.
ALinuxSCSIdrivercontainssevenmainfunctionsThedetectfunctioniscalledfirstbytheSCSIlayer.
IthasthejobofscanningforthecontrollersandregisteringthoseitfindswiththeSCSIlayer.
OncetheyareregisteredtheSCSIlayerwillissuecommandstothecontrollertoprobetheSCSIdevicesonthechain.
Thecommandfunctionissuesacommandsynchronouslyandwaitsforittocomplete.
Mostdriversimplementthisbycallingtheirownqueuecommandfunction.
Thequeuecommandfunctionissuesacommandanddoesnotwaitforittofinish.
Thisisusedbyalmostalloperations.
WhenthecommandcompletesthedrivercallsbackintotheSCSIlayertoinformtheSCSIlayerofthecompletionandpassesbackanyerrorinformation.
AbortandResetareusedtohandleerrorsituationsorcaseswheretheSCSIlayerthinksacommandhasgonemissing.
TheSCSIlayerwillfirstattempttoabortthecommandthenifneedbestartusingalargerhammerontheproblemuntilitgetstothepointoftryingtoresettheentirecontroller.
Hopefullythiswillneverhappen.
Theinfofunctionreturnsadescriptionofthecontrolleritself.
Thisisgenerallyaveryshortpieceofcodeindeed.
FinallythemappingofSCSItoPCdiskgeometryhasneverbeenexactlyastandard.
Thebios_paramfunctioniscalledbytheSCSIlayertoaskthecontrollertoeitherqueryitsBIOSforthefakeddiskgeometryortocomputeageometry(hopefullyusingthesamealgorithmasthecontrollerBIOSitself).
Thefirstfunctiontolookatindetailistheprobefunction.
ThisiscalledatboottimeorwhenaSCSImoduleisloaded.
Forourexampleweassumetherecanonlybeonecardandthatitbehavessanely.
intmyscsi_detect(Scsi_Host_Template*tpnt){structScsi_Host*shpnt;intio=0x320,irq=11;/*Assumefixedforexample*/ForourexamplewewilluseafixedIOandIRQ.
ArealcontrollerwouldeitherreadPCIspaceorwouldprobealistofcommonaddresses.
Wewillalsohidetheprobelogicinafunction.
if(myscsi_probe(io,irq)==0){/*Found-createaninstanceofthiscontroller*/shpnt=scsi_register(tpnt,0);if(shpnt==NULL)return0;Thefirstthingwedoistoaskscsi_registertomakeusadevice.
Thetpntisthetemplatepassedintothisfunctionandwhosedefinitionwewilldescribelaterinthearticle.
Itbasicallydefinesthistypeofcard.
Thereturnedpointisaninstanceofthecard.
Wepass0forthesecondargumentasweneednoprivatedataareaattaching.
Passingasizearrangesforaprivateblocktobeallocatedasshpnt->hostdatashpnt->unique_id=io;shpnt->io_port=io;shpnt->n_io_port=MY_PORT_RANGE;shpnt->irq=irq;shpnt->this_id=MY_SCSI_ID;Nowwestarttofillinthestructure.
Theunique_idisfortellingcardsapart.
InourcasetheI/Oportisaconvenientchoiceforthis.
'this_id'holdstheIDofthecontrolleritself.
EachSCSIdevicehasanidentityincludingthecontroller.
TheSCSIlayerneedstoknowthecontrollersID.
Weassumeforthiscaseitisfixed.
my_hardware_init(shpnt);Initializemyhardware.
Yougettowriteallofthisbit.
if(request_irq(irq,my_irq_handler,0,"myscsi",shpnt)){scsi_unregister(shpnt);printk("my_scsi:IRQ%disbusy.
",irq);return0;}Ifwecan'tregisterourinterrupthandlerweareabitstuck.
Ifsoweunregisterourscsicontrollerandreportnocontrollersfound.
Wealsolettheuserknowsoastoavoidconfusion.
}return1;}Andifitworkedwereportthatwefound1controller.
TheSCSIlayerwillnowgooffandscanallourdevices.
Timetowritethecommandfunctions.
intmyscsi_queuecommand(Scsi_Cmnd*SCpnt,void(*done)(Scsi_Cmnd*)){intio,i;unsignedlongflags;io=SCpnt->host->io_port;/*DigoutourI/Oport*/current_command=Scpnt;Forthisexamplewewillassumethatthecontrollerhandlesonlyonecommandatatime.
TypicalforacheapISAcontroller,notfordecenthardware.
Ifwesupportedmanycommandswecouldn'tkeepaglobalcurrent_commandbutwouldneedtokeepsomekindoflistandmatchrepliesfromthecardtothelistentries.
current_command->scsi_done=done;current_command->SCp.
Status=0;Weneedtorememberwhattocallwhenthecommandcompletes.
Nextwesetupthecommand.
Ourcardishypotheticalandratherover-smartforabasicISAdevice.
Youwon'tbesolucky.
.
.
save_flags(flags);outb(SCpnt->target,io+TARGET_PORT);for(i=0;icmd_len;i++)outb(SCpnt->cmnd[i],io+BUF+i);outb(COMMAND_BEGIN,io+COMMAND);Firstlyweloadthetargetdeviceintothecard,thenthecommand.
SCSIcommandsareblocksofupto16bytesincludinglengthinformation.
Aftershovingitontothecardwecanletthecardbeginoperation,andalsowecanallowinterruptsaswearereadytohandletheresultofthecommand.
restore_flags(flags);return0;andwereturnbacktotheSCSIlayer,thecommandisqueuedandhopefullysomethingwillhappen.
IfnotthentheSCSIlayerwillbotherusafteratimeout.
WhentheSCSIlayerdoeswanttobotherusaboutcommandsthathavegonewalkiesthenitwillcallourabortfunctionthenifthatfailsourresetfunction.
Manysimplercontrollerscannotsupporttheabortfunction.
Ifsotheabortfunctionisniceandsimpleintmyscsi_abort(Scsi_Cmnd*SCpnt){returnSCSI_ABORT_SNOOZE;}Weaskthekerneltowaitabitlongerandhope.
Intheendthekernelwillgetboredofwaitingandcallourresethandler.
WecanalsoreportSCSI_ABORT_PENDINGtoindicatethecommandisbeingabortedbutthatithasnotyetaborted-forexampleifaninterruptmustoccurfromthecardconfirmingtheabort,andwecanreturnSCSI_ABORT_SUCCESSifweabortedthecommand.
FinallywecanreportSCSI_ABORT_BUSYifwearebusyorthereissomeotherreasonwewouldliketoabortbutcannotdosorightnow.
AftertryingtoabortandreissuefailingcommandstheSCSIlayerwilltrytoresetthings.
Ittriestoresetfirstthedeviceincasethathasbecomeconfused,thentoresettheSCSIbusincasethebusitselfhaslockedup.
Finallyittriestoresetthecontrollerincasethehardwarehaschoked.
Howyouhandlethisdependsontheabilityofthecontrolleritself.
intmyscsi_reset(Scsi_Cmnd*SCpnt,unsignedintflags){myhardware_reset(SCpnt->host);returnSCSI_RESET_PENDING;}Forourexampleweassumethatthecontrollerisfairlydumb.
Weignoretheflaghintsandweresetthedevice.
TheSCSI_RESET_PENDINGreturnindicatesthatthebushasbeenresetbutthatcommandswillbereturnedwithafailurestatuslater.
IfthecontrollerresetreturnedthecommandsimmediatelywecouldreissuethecommandsandreturnSCSI_RESET_SUCCESS.
IfwedonotthinkthistypeofresetisappropriatewecanreturnSCSI_RESET_PUNT.
Youshouldatleastsupportresettingthebus.
Theflagsfieldisasetoffourflagsdesignedtoprovidehintsastowhattoresetandhow.
TheimportantflagsareSCSI_RESET_SUGGEST_BUS_RESETwhentheSCSIlayerthinkstheentirebusshouldberesetandSCSI_RESET_SUGGEST_HOST_RESETwhichisthelastresorthinttothedriverthatthingsarebadandthatitmightbeappropriatetocompletelyrestarttheboarditself.
We'veissuedcommandsandwecanstartanabort.
Atthispointwecan'tgetanyfurtherwithoutconsideringtheinterrupthandler.
Theneedsoftheinterrupthandlercanvaryalotbetweencards.
ForourexampledriverI'mgoingtoassumethatitwillinterruptusoncewhenitwantsthedatatosend/receiveandonceoncommandcompletion.
intmy_irq_handler(intirq,void*dev_id,structpt_regs*regs){structScsi_Host*shpnt=dev_id;intio=shpnt->io_port;u16data;Whenwerequestedtheinterruptweusedthehostpointerasthe'dev_id'-adevicespecificfieldthatispassedtothehandlerbythekernel.
Thismakesitveryeasyforustofindwhichcardwearehandlinginadriverthatissupportingmultipleinterfacecards.
WethendigoutourI/Oportaswewillprobablyneedthisalotinamoment.
data=inw(io+READ_STATUS);if(data&RESET_DONE){current_command->result=DID_RESETscsi_done(current_command);return;}Firstlywecheckifthebushasbeenreset(eitherbyusorotherdevices).
Ifsowereportthecommandwasreset.
ThiswillalsotelltheSCSIlayerthattheresetwereportedaspendinginourresethandlerhasnowcompleted.
if(data&PARITY_ERROR){current_command->result=DID_PARITYscsi_done(current_command);return;}Wecheckforparityerrors.
Wewouldcheckforasmanyerrorsaswecanidentifycleanlyonarealcard.
Foranerrorwithnoexactdetailweif(data&GENERAL_ERROR){current_command->result=DID_ERRORscsi_done(current_command);return;}TheSCSImidlayerwillhandledoingtherightthingstorecoverfromanerrorsituation.
NextwelooktoseeifthisisaSCSIphasechange(SCSIcommandspassthroughasetofphases.
Asmartcontrollerhandlesallofthisadumboneless.
Inourcasewewillassumethattheonlyphasesthatneedhelpare'datain'and'dataout'-wherewecopybytestoorfromtheSCSIdeviceweissuedacommand.
if(data&DATA_OUT){outsw(port+DATA_FIFO,current_command->request_buffer,current_command->request_bufflen);}Tosenddataweblastthebuffertothecontroller.
ThismaywellbedonebyDMAinarealcontroller.
Ourexamplewekeepsimple.
Oninputwecheckhowmanybyteswerereceivedandcopythemtotherequestbuffer-whichisprobablyapageofdiskcachemostofthetime.
Wedon'thavetoworrywhereitgoeshowever,justthatitfits.
if(data&DATA_IN){intlen=inw(port+DATA_LEN);if(len>current_command->request_bufflen)len=current_command->request_bufflen;insw(port+DATA_FIFO,current_command->request_buffer,current_command->request_bufflen);}Finallycheckifacommandfinished.
IfsoputthedeviceSCSIstatusinthelowbyteoftheresponseandtelltheSCSIlayerthecommandhascompleted.
Thetop16bitsholdthekernelinfo,thebottomtheSCSIinfo.
Thetop16bitsfornoerrorare0preciselytomakethissimple.
if(data&COMMAND_DONE){current_command->status=inb(port+CMD_STATUS);current_command->scsi_done(current_command);}}andweexitourinterrupt.
SCSIcommandscanbeissuedsynchronouslyalthoughthisisnowbasicallydeadandwedothingsproperly.
Supportingthesynchronouscommandsisbestdoneintermsofthequeuecommandfunctionandthecodebelowisbasicallyboilerplateusedbyalmosteverydriver.
staticvoidit_finished(Scsi_Cmnd*SCpnt){SCpnt->SCp.
Status++;}intmyscsi_command(Scsi_Cmnd*SCpnt){myscsi_queuecommand(SCpnt,it_finished);while(!
SCpnt->SCp.
Status)barrier();returnSCpnt->result;}Wequeueacommandandtellthequeuefunctionthatthe'completion'handler(scsi_done)istoincrementthestatus.
Havingissuedthecommandwespininaloopuntilthecommandfinishes.
Thebarrier()statementisimportanthere.
Gccmightotherwiseoptimizewhile(variable)toif(variable)while(1);Barriertellsitthatitcannotcachevaluesfromvariablesacrossthebarrier()functioncall.
Thisensuresthatthestatus,whichischangedbyaninterruptwillbeseenbytheloopingcode.
ThiscompletestheSCSIcommandhandlersforoursimplecard.
Theyarenotoptimizedandourcardisalittlesimplistic.
Westillneedtofillinthegeometryfunctionandtheinfofunction.
Theinfofunctionreturnsatextdescriptionforourcontroller.
constchar*myscsi_info(structScsi_Host*SChost){return("MySCSIdevice");}itcould(perhapsshouldinfact)returntheI/OandIRQinformation,driverversionandothervaluableinformationtoo.
Thebios_paramfunctionmapsourSCSIdisktoaPCBIOSfakedgeometry.
Realdisksdon'thavethesimplegeometrythePChas,buteveryonehascarriedonfakingitratherthanfixingalltheoperatingsystems.
Thuswehavetocontinuethisfiction.
WeneedtousethesamealgorithmastheBIOSorlifewillbemessy.
ThisexampleistakenfromtheSymbios53c416driverandisquitetypicalintsym53c416_bios_param(Disk*disk,kdev_tdev,int*ip){intsize;size=disk->capacity;ip[0]=64;/*heads*/ip[1]=32;/*sectors*/if((ip[2]=size>>11)>1024)/*cylinders,testforbigdisk*/{ip[0]=255;/*heads*/ip[1]=63;/*sectors*/ip[2]=size/(255*63);/*cylinders*/}return0;}Giventhedisksizewefillinanarrayofintegersfortheheads,sectorsandcylindersofourdisk.
Weactuallywanttobesurethattheseareright.
GettingthemappingwrongwillgivepeoplewhousemixedLinux/DOSdiskscorruptedfilesystemsandgenerateunhappymail.
Allisnowfineexceptthattounloadthemoduleweneedtocleanupourresources.
Weprovideareleasefunctionforthis.
intmyscsi_release(structScsi_Host*SChost){free_irq(SChost->irq,SChost);return0;}ArealdrivershouldofcoursehaveallocatedandfreedtheI/Oportsitusedtoo.
TomakeourdriveraSCSImodulewehavetoincludesomemagicattheendofthefile#ifdefMODULEScsi_Host_Templatedriver_template=MYSCSI;#include"scsi_module.
c"#endifThisgeneratestheinit_moduleandcleanup_modulecodeneededforaSCSIdevice,ratherthantheauthorhavingtoreplicateiteachtime.
TheMYSCSIobjectisadefineweneedtocreateinaheaderfilewealsoinclude.
Itisadefineinaseparatefileasforacompiledindriverwewillneeditagain.
Ourmyscsi.
hfilelookslikeexternintmyscsi_detect(Scsi_Host_Template*);externconstchar*myscsi_info(structScsi_Host*).
.
.
todeclaretheroutinesweprovide.
ThenwedefinedtheMYSCSItemplate#defineMYSCSI{name:"MySCSIDemo",detect:myscsi_detect,info:myscsi_info,command:myscsi_command,queuecommand:myscsi_queuecommand,abort:myscsi_abort,reset:myscsi_reset,bios_param:myscsi_bios_param,ThispartdefinestheSCSIfunctionsweuse.
The"field:value"formatisagccextensionwhichsetsagivenfieldinastructureratherthanlistingallthefieldsinorder.
can_queue:1,Totellthekernelwecanqueuecommandsandreturnthis_id:MY_SCSI_ID,OurhostSCSIidsg_tablesize:SG_NONE,Scattergatherisaveryusefulextensionforperformance.
Forthissimpledriverwedon'tsupportit.
cmd_per_lun:1,WecanhaveatmostonecommandoutstandingperLUN(logicalunit).
unchecked_isa_dma:1,IfyousetthistozerothekernelwilldothehardworkofensuringallthediskbuffersarecopiedintoISAbusaccessiblememorywhenneeded.
ThisonlymatterstoISAbuscontrollersthatdoDMA.
use_clustering:ENABLE_CLUSTERING,Weturnonclustering.
ClusteringtellstheSCSIlayerthatitisworthtryingtomergemultiplediskreadorwriterequestsintoasingleSCSIcommand.
Averyintelligentcontrollermaywellnotsetthis.
proc_dir:&myscsi_proc}Lastlywedefineourdirectoryfor/proc/scsi.
Wehaven'tputthisintothedriveryetsoweaddstructproc_dirmyscsi_proc={PROC_SCSI_MYSCSI,"myscsi",6,/*Lengthofname*/S_IFDIR|S_IRUGO|S_IXUGO,2};whichwillbeusedtoinstallourdirectoryin/proc/scsi.
ThePROC_SCSI_MYSCSIneedstobeaddedtoinclude/linux//proc_fs.
htogetauniqueinodenumberforthisdirectoryin/proc/scsi.
Thescsi_directory_inosenumerationissimplyalistofallthepossibledevices.
WedropourentryinbeforethedebuggingdriverPROC_SCSI_FCAL,PROC_SCSI_I2O,PROC_SCSI_MYSCSI,/*here*/PROC_SCSI_SCSI_DEBUG,HopefullythisarticlehasprovidedenoughgroundingthatthoseinterestedinwritingSCSIdriverscannowfollowthroughexistingdrivers-especiallysimpleoneslikethesymbios53c416driverandseehowtoimplementanewone.
天上云服务器怎么样?天上云是国人商家,成都天上云网络科技有限公司,专注于香港、美国海外云服务器的产品,有多年的运维维护经验。世界这么大 靠谱最重,我们7*24H为您提供服务,贴心售后服务,安心、省事儿、稳定、靠谱。目前,天上云香港大带宽物理机服务器572元;20Mbps带宽!三网CN2线路,香港沙田数据中心!点击进入:天上云官方网站地址香港沙田数据中心!线路说明 :去程中国电信CN2 +中国联通+...
特网云官網特网云服务器在硬件级别上实现云主机之间的完全隔离;采用高端服务器进行部署,同时采用集中的管理与监控,确保业务稳定可靠,搭建纯SSD架构的高性能企业级云服务器,同时采用Intel Haswell CPU、高频DDR4内存、高速Sas3 SSD闪存作为底层硬件配置,分钟级响应速度,特网云采用自带硬防节点,部分节点享免费20G防御,可实现300G防御峰值,有效防御DDoS、CC等恶意攻击,保障...
RackNerd 商家给的感觉就是一直蹭节日热点,然后时不时通过修改配置结构不断的提供低价年付的VPS主机,不过他们家还是在做事的,这么两年多的发展,居然已经有新增至十几个数据中心,而且产品线发展也是比较丰富。比如也有独立服务器业务,不过在他们轮番的低价年付VPS主机活动下,他们的服务器估摸着销路不是太好的。这里,今天有看到RackNerd商家的独立服务器业务有促销。这次提供美国多个机房的高配独立...
ignore_user_abort为你推荐
云计算什么叫做“云计算”?西部妈妈网烟台分类妈妈网 分类妈妈网的前2个字什么?同ip网站查询服务器禁PING 是不是就可以解决同IP网站查询问题地陷裂口山崩地裂的意思罗伦佐娜米开朗琪罗简介haole018.com为什么www.haole008.com在我这里打不开啊,是不是haole008换新的地址了?haokandianyingwang有什么好看的电影网站javbibinobibi的中文意思是?lcoc.top服装英语中double topstitches什么意思www.ca800.comPLC好学吗
二级域名 备案域名 cn域名注册 国外免费vps 免费动态域名解析 荷兰服务器 精品网 42u机柜尺寸 阿里云代金券 丹弗 php空间申请 linux空间 河南移动邮件系统 刀片服务器的优势 183是联通还是移动 cdn加速是什么 hkt 支持外链的相册 卡巴斯基是免费的吗 西安服务器托管 更多