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.
TmhHost 商家是一家成立于2019年的国人主机品牌。目前主营的是美国VPS以及美国、香港、韩国、菲律宾的独立服务器等,其中VPS业务涵盖香港CN2、香港NTT、美国CN2回程高防、美国CN2 GIA、日本软银、韩国cn2等,均为亚太中国直连优质线路,TmhHost提供全中文界面,支持支付宝付款。 TmhHost黑五优惠活动发布了,全场云服务器、独立服务器提供8折,另有充值返现、特价服务器促销...
WHloud Official Notice(鲸云官方通知)(鲸落 梦之终章)]WHloud RouMu Cloud Hosting若木产品线云主机-香港节点上新预售本次线路均为电信CN2 GIA+移动联通BGP,此机型为正常常规机,建站推荐。本次预售定为国庆后开通,据销售状况决定,照以往经验或有咕咕的可能性,但是大多等待时间不长。均赠送2个快照 2个备份,1个默认ipv4官方网站:https:/...
易探云怎么样?易探云隶属于纯乐电商旗下网络服务品牌,香港NTT Communications合作伙伴,YiTanCloud Limited旗下合作云计算品牌,数十年云计算行业经验。发展至今,我们已凝聚起港内领先的开发和运维团队,积累起4年市场服务经验,提供电话热线/在线咨询/服务单系统等多种沟通渠道,7*24不间断服务,3分钟快速响应。目前,易探云提供香港大带宽20Mbps、16G DDR3内存、...
ignore_user_abort为你推荐
多家五星酒店回应网传名媛拼单我妈同学给了她一张那种酒店的入场券,不知道这个入场券是随便发的还是怎么,我们这里算是四五星吧,一个安徽汽车网在安徽那个市的二手车最好?西部妈妈网我爸妈在云南做非法集资了,钱肯定交了很多,我不恨她们。他们叫我明天去看,让我用心的看,,说是什么...www.hao360.cn主页设置为http://hao.360.cn/,但打开360浏览器先显示www.yes125.com后转换为www.2345.com,搜索注册表和刘祚天你们知道21世纪的DJ分为几种类型吗?(答对者重赏)原代码源代码是什么意思啊www.yahoo.com.hk香港有什么有名的娱乐门户网站吗?同一服务器网站一个服务器放多个网站怎么设置?www.gegeshe.comSHE个人资料bk乐乐BK乐乐和沈珂什么关系?
tk域名注册 合租服务器 贝锐花生壳域名 服务器配置技术网 enom gomezpeer 空间打开慢 轻博客 php探针 智能骨干网 howfile 91vps 香港新世界中心 优酷黄金会员账号共享 华为云盘 宏讯 lick 英国伦敦 中国电信网络测速 iki 更多