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.
HostMem近日发布了最新的优惠消息,全场云服务器产品一律75折优惠,美国洛杉矶QuadraNet机房,基于KVM虚拟架构,2核心2G内存240G SSD固态硬盘100Mbps带宽4TB流量,27美元/年,线路方面电信CN2 GT,联通CU移动CM,有需要美国大硬盘VPS云服务器的朋友可以关注一下。HostMem怎么样?HostMem服务器好不好?HostMem值不值得购买?HostMem是一家...
VoLLcloud LLC是一家成立于2020年12月互联网服务提供商企业,于2021年1月份投入云计算应用服务,为广大用户群体提供云服务平台,已经多个数据中心部署云计算中心,其中包括亚洲、美国、欧洲等地区,拥有自己的研发和技术服务团队。现七夕将至,VoLLcloud LLC 推出亚洲地区(香港)所有产品7折优惠,该产品为CMI线路,去程三网163,回程三网CMI线路,默认赠送 2G DDoS/C...
BuyVM 商家算是有一些年头,从早年提供低价便宜VPS主机深受广大网友抢购且也遭到吐槽的是因为审核账户太过于严格。毕竟我们国内的个人注册账户喜欢账户资料乱写,毕竟我们看英文信息有些还是比较难以识别的,于是就注册信息的时候随便打一些字符,这些是不能通过的。前几天,我们可以看到BUYVM商家有新增加迈阿密机房,而且商家有提供大硬盘且不限制流量的VPS主机,深受有一些网友的喜欢。目前,BUYVM商家有...
ignore_user_abort为你推荐
哈利波特罗恩升级当爸哈利波特中的赫敏为什么要喜欢罗恩,不喜欢哈利公司网络被攻击最近公司频繁的受到网络攻击,导致网络瘫痪,又碰到arp攻击,有病毒的,有点崩溃。。。美国互联网瘫痪美国是否有能力关闭全球互联网以及中国互联网,还有美国有没能力关闭某个网站,比如淘宝,天涯,网易等h连锁酒店全国比较有名的连锁酒店?对对塔对对塔和魔方格那个是正宗的?lunwenjiancewritecheck论文检测准吗?javbibitreebibi是什么牌子的partnersonline国内有哪些知名的ACCA培训机构ww.66bobo.com谁知道11qqq com被换成哪个网站www.toutoulu.comSEO行业外链怎么做?
ip查域名 Hello图床 私有云存储 web服务器架设软件 日本bb瘦 稳定免费空间 台湾google 监控服务器 华为云建站 hdchina 删除域名 性能测试工具 赵 ddos攻击软件 ddos攻击器下载 云主机 堡垒主机 主机托管 免费免备案cdn 灵动:鬼影实录2 更多