12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419 |
- /** @file
- SCSI disk driver that layers on every SCSI IO protocol in the system.
- Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 1985 - 2022, American Megatrends International LLC.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "ScsiDisk.h"
- EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
- ScsiDiskDriverBindingSupported,
- ScsiDiskDriverBindingStart,
- ScsiDiskDriverBindingStop,
- 0xa,
- NULL,
- NULL
- };
- EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
- EFI_DISK_INFO_SCSI_INTERFACE_GUID,
- ScsiDiskInfoInquiry,
- ScsiDiskInfoIdentify,
- ScsiDiskInfoSenseData,
- ScsiDiskInfoWhichIde
- };
- /**
- Allocates an aligned buffer for SCSI disk.
- This function allocates an aligned buffer for the SCSI disk to perform
- SCSI IO operations. The alignment requirement is from SCSI IO interface.
- @param ScsiDiskDevice The SCSI disk involved for the operation.
- @param BufferSize The request buffer size.
- @return A pointer to the aligned buffer or NULL if the allocation fails.
- **/
- VOID *
- AllocateAlignedBuffer (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINTN BufferSize
- )
- {
- return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
- }
- /**
- Frees an aligned buffer for SCSI disk.
- This function frees an aligned buffer for the SCSI disk to perform
- SCSI IO operations.
- @param Buffer The aligned buffer to be freed.
- @param BufferSize The request buffer size.
- **/
- VOID
- FreeAlignedBuffer (
- IN VOID *Buffer,
- IN UINTN BufferSize
- )
- {
- if (Buffer != NULL) {
- FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
- }
- }
- /**
- Remove trailing spaces from the string.
- @param String The ASCII string to remove the trailing spaces.
- @retval the new length of the string.
- **/
- UINTN
- RemoveTrailingSpaces (
- IN OUT CHAR8 *String
- )
- {
- UINTN Length;
- Length = AsciiStrLen (String);
- if (Length == 0) {
- return 0;
- }
- while ((Length > 0) && (String[Length-1] == ' ')) {
- Length--;
- }
- String[Length] = '\0';
- return Length;
- }
- /**
- The user Entry Point for module ScsiDisk.
- The user code starts with this function.
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
- @retval EFI_SUCCESS The entry point is executed successfully.
- @retval other Some error occurs when executing this entry point.
- **/
- EFI_STATUS
- EFIAPI
- InitializeScsiDisk (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gScsiDiskDriverBinding,
- ImageHandle,
- &gScsiDiskComponentName,
- &gScsiDiskComponentName2
- );
- ASSERT_EFI_ERROR (Status);
- return Status;
- }
- /**
- Test to see if this driver supports ControllerHandle.
- This service is called by the EFI boot service ConnectController(). In order
- to make drivers as small as possible, there are a few calling restrictions for
- this service. ConnectController() must follow these calling restrictions.
- If any other agent wishes to call Supported() it must also follow these
- calling restrictions.
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to test
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
- @retval EFI_SUCCESS This driver supports this device
- @retval EFI_ALREADY_STARTED This driver is already running on this device
- @retval other This driver does not support this device
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskDriverBindingSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- EFI_SCSI_IO_PROTOCOL *ScsiIo;
- UINT8 DeviceType;
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- (VOID **)&ScsiIo,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
- if (!EFI_ERROR (Status)) {
- if ((DeviceType == EFI_SCSI_TYPE_DISK) ||
- (DeviceType == EFI_SCSI_TYPE_CDROM) ||
- (DeviceType == EFI_SCSI_TYPE_WLUN))
- {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_UNSUPPORTED;
- }
- }
- gBS->CloseProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- return Status;
- }
- /**
- Start this driver on ControllerHandle.
- This service is called by the EFI boot service ConnectController(). In order
- to make drivers as small as possible, there are a few calling restrictions for
- this service. ConnectController() must follow these calling restrictions. If
- any other agent wishes to call Start() it must also follow these calling
- restrictions.
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to bind driver to
- @param RemainingDevicePath Optional parameter use to pick a specific child
- device to start.
- @retval EFI_SUCCESS This driver is added to ControllerHandle
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
- @retval other This driver does not support this device
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskDriverBindingStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- EFI_SCSI_IO_PROTOCOL *ScsiIo;
- SCSI_DISK_DEV *ScsiDiskDevice;
- BOOLEAN Temp;
- UINT8 Index;
- UINT8 MaxRetry;
- BOOLEAN NeedRetry;
- BOOLEAN MustReadCapacity;
- CHAR8 VendorStr[VENDOR_IDENTIFICATION_LENGTH + 1];
- CHAR8 ProductStr[PRODUCT_IDENTIFICATION_LENGTH + 1];
- CHAR16 DeviceStr[VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2];
- MustReadCapacity = TRUE;
- ScsiDiskDevice = (SCSI_DISK_DEV *)AllocateZeroPool (sizeof (SCSI_DISK_DEV));
- if (ScsiDiskDevice == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- (VOID **)&ScsiIo,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- FreePool (ScsiDiskDevice);
- return Status;
- }
- ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;
- ScsiDiskDevice->ScsiIo = ScsiIo;
- ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
- ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;
- ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign;
- ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;
- ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;
- ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;
- ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;
- ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;
- ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;
- ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;
- ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
- ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
- ScsiDiskDevice->StorageSecurity.ReceiveData = ScsiDiskReceiveData;
- ScsiDiskDevice->StorageSecurity.SendData = ScsiDiskSendData;
- ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
- ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
- ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks;
- ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt = 1;
- ScsiDiskDevice->BlockLimitsVpdSupported = FALSE;
- ScsiDiskDevice->Handle = Controller;
- InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);
- ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
- switch (ScsiDiskDevice->DeviceType) {
- case EFI_SCSI_TYPE_DISK:
- ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
- MustReadCapacity = TRUE;
- break;
- case EFI_SCSI_TYPE_CDROM:
- ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
- ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;
- MustReadCapacity = FALSE;
- break;
- case EFI_SCSI_TYPE_WLUN:
- MustReadCapacity = FALSE;
- break;
- }
- //
- // The Sense Data Array's initial size is 6
- //
- ScsiDiskDevice->SenseDataNumber = 6;
- ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *)AllocateZeroPool (
- sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
- );
- if (ScsiDiskDevice->SenseData == NULL) {
- gBS->CloseProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- FreePool (ScsiDiskDevice);
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Retrieve device information
- //
- MaxRetry = 2;
- for (Index = 0; Index < MaxRetry; Index++) {
- Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
- if (!EFI_ERROR (Status)) {
- break;
- }
- if (!NeedRetry) {
- FreePool (ScsiDiskDevice->SenseData);
- gBS->CloseProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- FreePool (ScsiDiskDevice);
- return EFI_DEVICE_ERROR;
- }
- }
- //
- // The second parameter "TRUE" means must
- // retrieve media capacity
- //
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
- if (!EFI_ERROR (Status)) {
- //
- // Determine if Block IO & Block IO2 should be produced on this controller
- // handle
- //
- if (DetermineInstallBlockIo (Controller)) {
- InitializeInstallDiskInfo (ScsiDiskDevice, Controller);
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Controller,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &gEfiDiskInfoProtocolGuid,
- &ScsiDiskDevice->DiskInfo,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {
- Status = gBS->InstallProtocolInterface (
- &Controller,
- &gEfiEraseBlockProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &ScsiDiskDevice->EraseBlock
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));
- }
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) {
- Status = gBS->InstallProtocolInterface (
- &Controller,
- &gEfiStorageSecurityCommandProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &ScsiDiskDevice->StorageSecurity
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status));
- }
- }
- CopyMem (
- VendorStr,
- &ScsiDiskDevice->InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET],
- VENDOR_IDENTIFICATION_LENGTH
- );
- VendorStr[VENDOR_IDENTIFICATION_LENGTH] = 0;
- RemoveTrailingSpaces (VendorStr);
- CopyMem (
- ProductStr,
- &ScsiDiskDevice->InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET],
- PRODUCT_IDENTIFICATION_LENGTH
- );
- ProductStr[PRODUCT_IDENTIFICATION_LENGTH] = 0;
- RemoveTrailingSpaces (ProductStr);
- UnicodeSPrint (DeviceStr, sizeof (DeviceStr), L"%a %a", VendorStr, ProductStr);
- ScsiDiskDevice->ControllerNameTable = NULL;
- AddUnicodeString2 (
- "eng",
- gScsiDiskComponentName.SupportedLanguages,
- &ScsiDiskDevice->ControllerNameTable,
- DeviceStr,
- TRUE
- );
- AddUnicodeString2 (
- "en",
- gScsiDiskComponentName2.SupportedLanguages,
- &ScsiDiskDevice->ControllerNameTable,
- DeviceStr,
- FALSE
- );
- return EFI_SUCCESS;
- }
- }
- }
- gBS->FreePool (ScsiDiskDevice->SenseData);
- gBS->FreePool (ScsiDiskDevice);
- gBS->CloseProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- return Status;
- }
- /**
- Stop this driver on ControllerHandle.
- This service is called by the EFI boot service DisconnectController().
- In order to make drivers as small as possible, there are a few calling
- restrictions for this service. DisconnectController() must follow these
- calling restrictions. If any other agent wishes to call Stop() it must
- also follow these calling restrictions.
- @param This Protocol instance pointer.
- @param ControllerHandle Handle of device to stop driver on
- @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
- children is zero stop the entire bus driver.
- @param ChildHandleBuffer List of Child Handles to Stop.
- @retval EFI_SUCCESS This driver is removed ControllerHandle
- @retval other This driver was not removed from this device
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
- )
- {
- EFI_BLOCK_IO_PROTOCOL *BlkIo;
- EFI_ERASE_BLOCK_PROTOCOL *EraseBlock;
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_STATUS Status;
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiBlockIoProtocolGuid,
- (VOID **)&BlkIo,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
- //
- // Wait for the BlockIo2 requests queue to become empty
- //
- while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {
- }
- //
- // If Erase Block Protocol is installed, then uninstall this protocol.
- //
- Status = gBS->OpenProtocol (
- Controller,
- &gEfiEraseBlockProtocolGuid,
- (VOID **)&EraseBlock,
- This->DriverBindingHandle,
- Controller,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- Status = gBS->UninstallProtocolInterface (
- Controller,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- Status = gBS->UninstallMultipleProtocolInterfaces (
- Controller,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &gEfiDiskInfoProtocolGuid,
- &ScsiDiskDevice->DiskInfo,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- gBS->CloseProtocol (
- Controller,
- &gEfiScsiIoProtocolGuid,
- This->DriverBindingHandle,
- Controller
- );
- ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
- return EFI_SUCCESS;
- }
- //
- // errors met
- //
- return Status;
- }
- /**
- Reset SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL
- @param ExtendedVerification The flag about if extend verificate
- @retval EFI_SUCCESS The device was reset.
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could
- not be reset.
- @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskReset (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- EFI_TPL OldTpl;
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_STATUS Status;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
- Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- if (EFI_ERROR (Status)) {
- if (Status == EFI_UNSUPPORTED) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- }
- if (!ExtendedVerification) {
- goto Done;
- }
- Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- The function is to Read Block from SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
- @param MediaId The Id of Media detected
- @param Lba The logic block address
- @param BufferSize The size of Buffer
- @param Buffer The buffer to fill the read out data
- @retval EFI_SUCCESS Successfully to read out block.
- @retval EFI_DEVICE_ERROR Fail to detect media.
- @retval EFI_NO_MEDIA Media is not present.
- @retval EFI_MEDIA_CHANGED Media has changed.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskReadBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Get the intrinsic block size
- //
- BlockSize = Media->BlockSize;
- if (BlockSize == 0) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- NumberOfBlocks = BufferSize / BlockSize;
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (MediaId != Media->MediaId) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if (BufferSize == 0) {
- Status = EFI_SUCCESS;
- goto Done;
- }
- if (BufferSize % BlockSize != 0) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Done;
- }
- if (Lba > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- //
- // If all the parameters are valid, then perform read sectors command
- // to transfer data from device to host.
- //
- Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- The function is to Write Block to SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL
- @param MediaId The Id of Media detected
- @param Lba The logic block address
- @param BufferSize The size of Buffer
- @param Buffer The buffer to fill the read out data
- @retval EFI_SUCCESS Successfully to read out block.
- @retval EFI_WRITE_PROTECTED The device can not be written to.
- @retval EFI_DEVICE_ERROR Fail to detect media.
- @retval EFI_NO_MEDIA Media is not present.
- @retval EFI_MEDIA_CHANGED Media has changed.
- @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
- @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Get the intrinsic block size
- //
- BlockSize = Media->BlockSize;
- if (BlockSize == 0) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- NumberOfBlocks = BufferSize / BlockSize;
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (MediaId != Media->MediaId) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Media->ReadOnly) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
- if (BufferSize == 0) {
- Status = EFI_SUCCESS;
- goto Done;
- }
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if (BufferSize % BlockSize != 0) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Done;
- }
- if (Lba > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- //
- // if all the parameters are valid, then perform read sectors command
- // to transfer data from device to host.
- //
- Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Flush Block to Disk.
- EFI_SUCCESS is returned directly.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL
- @retval EFI_SUCCESS All outstanding data was written to the device
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskFlushBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This
- )
- {
- //
- // return directly
- //
- return EFI_SUCCESS;
- }
- /**
- Reset SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
- @param ExtendedVerification The flag about if extend verificate.
- @retval EFI_SUCCESS The device was reset.
- @retval EFI_DEVICE_ERROR The device is not functioning properly and could
- not be reset.
- @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskResetEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
- {
- EFI_TPL OldTpl;
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_STATUS Status;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
- Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- if (EFI_ERROR (Status)) {
- if (Status == EFI_UNSUPPORTED) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- }
- if (!ExtendedVerification) {
- goto Done;
- }
- Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- The function is to Read Block from SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
- @param MediaId The Id of Media detected.
- @param Lba The logic block address.
- @param Token A pointer to the token associated with the transaction.
- @param BufferSize The size of Buffer.
- @param Buffer The buffer to fill the read out data.
- @retval EFI_SUCCESS The read request was queued if Token-> Event is
- not NULL. The data was read correctly from the
- device if theToken-> Event is NULL.
- @retval EFI_DEVICE_ERROR The device reported an error while attempting
- to perform the read operation.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not on proper
- alignment.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskReadBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Get the intrinsic block size
- //
- BlockSize = Media->BlockSize;
- if (BlockSize == 0) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- NumberOfBlocks = BufferSize / BlockSize;
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (MediaId != Media->MediaId) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if (BufferSize == 0) {
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- gBS->SignalEvent (Token->Event);
- }
- Status = EFI_SUCCESS;
- goto Done;
- }
- if (BufferSize % BlockSize != 0) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Done;
- }
- if (Lba > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- //
- // If all the parameters are valid, then perform read sectors command
- // to transfer data from device to host.
- //
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- Status = ScsiDiskAsyncReadSectors (
- ScsiDiskDevice,
- Buffer,
- Lba,
- NumberOfBlocks,
- Token
- );
- } else {
- Status = ScsiDiskReadSectors (
- ScsiDiskDevice,
- Buffer,
- Lba,
- NumberOfBlocks
- );
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- The function is to Write Block to SCSI Disk.
- @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
- @param MediaId The Id of Media detected.
- @param Lba The logic block address.
- @param Token A pointer to the token associated with the transaction.
- @param BufferSize The size of Buffer.
- @param Buffer The buffer to fill the read out data.
- @retval EFI_SUCCESS The data were written correctly to the device.
- @retval EFI_WRITE_PROTECTED The device cannot be written to.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_DEVICE_ERROR The device reported an error while attempting
- to perform the write operation.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
- @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
- valid, or the buffer is not on proper
- alignment.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskWriteBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Get the intrinsic block size
- //
- BlockSize = Media->BlockSize;
- if (BlockSize == 0) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- NumberOfBlocks = BufferSize / BlockSize;
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (MediaId != Media->MediaId) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Media->ReadOnly) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
- if (BufferSize == 0) {
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- gBS->SignalEvent (Token->Event);
- }
- Status = EFI_SUCCESS;
- goto Done;
- }
- if (Buffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if (BufferSize % BlockSize != 0) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Done;
- }
- if (Lba > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- //
- // if all the parameters are valid, then perform write sectors command
- // to transfer data from device to host.
- //
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- Status = ScsiDiskAsyncWriteSectors (
- ScsiDiskDevice,
- Buffer,
- Lba,
- NumberOfBlocks,
- Token
- );
- } else {
- Status = ScsiDiskWriteSectors (
- ScsiDiskDevice,
- Buffer,
- Lba,
- NumberOfBlocks
- );
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Flush the Block Device.
- @param This Indicates a pointer to the calling context.
- @param Token A pointer to the token associated with the transaction.
- @retval EFI_SUCCESS All outstanding data was written to the device.
- @retval EFI_DEVICE_ERROR The device reported an error while attempting to
- write data.
- @retval EFI_WRITE_PROTECTED The device cannot be written to.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskFlushBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (Media->ReadOnly) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
- //
- // Wait for the BlockIo2 requests queue to become empty
- //
- while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {
- }
- Status = EFI_SUCCESS;
- //
- // Signal caller event
- //
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- gBS->SignalEvent (Token->Event);
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Internal helper notify function which process the result of an asynchronous
- SCSI UNMAP Command and signal the event passed from EraseBlocks.
- @param Event The instance of EFI_EVENT.
- @param Context The parameter passed in.
- **/
- VOID
- EFIAPI
- ScsiDiskAsyncUnmapNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- SCSI_ERASEBLK_REQUEST *EraseBlkReq;
- EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
- EFI_ERASE_BLOCK_TOKEN *Token;
- EFI_STATUS Status;
- gBS->CloseEvent (Event);
- EraseBlkReq = (SCSI_ERASEBLK_REQUEST *)Context;
- CommandPacket = &EraseBlkReq->CommandPacket;
- Token = EraseBlkReq->Token;
- Token->TransactionStatus = EFI_SUCCESS;
- Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
- CommandPacket->HostAdapterStatus
- ));
- Token->TransactionStatus = Status;
- goto Done;
- }
- Status = CheckTargetStatus (CommandPacket->TargetStatus);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
- CommandPacket->HostAdapterStatus
- ));
- Token->TransactionStatus = Status;
- goto Done;
- }
- Done:
- RemoveEntryList (&EraseBlkReq->Link);
- FreePool (CommandPacket->OutDataBuffer);
- FreePool (EraseBlkReq->CommandPacket.Cdb);
- FreePool (EraseBlkReq);
- gBS->SignalEvent (Token->Event);
- }
- /**
- Require the device server to cause one or more LBAs to be unmapped.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice.
- @param Lba The start block number.
- @param Blocks Total block number to be unmapped.
- @param Token The pointer to the token associated with the
- non-blocking erase block request.
- @retval EFI_SUCCESS Target blocks have been successfully unmapped.
- @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
- **/
- EFI_STATUS
- ScsiDiskUnmap (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINT64 Lba,
- IN UINTN Blocks,
- IN EFI_ERASE_BLOCK_TOKEN *Token OPTIONAL
- )
- {
- EFI_SCSI_IO_PROTOCOL *ScsiIo;
- SCSI_ERASEBLK_REQUEST *EraseBlkReq;
- EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;
- EFI_SCSI_DISK_UNMAP_BLOCK_DESP *BlkDespPtr;
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- UINT8 *Cdb;
- UINT32 MaxLbaCnt;
- UINT32 MaxBlkDespCnt;
- UINT32 BlkDespCnt;
- UINT16 UnmapParamListLen;
- VOID *UnmapParamList;
- EFI_EVENT AsyncUnmapEvent;
- EFI_TPL OldTpl;
- ScsiIo = ScsiDiskDevice->ScsiIo;
- MaxLbaCnt = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;
- MaxBlkDespCnt = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;
- EraseBlkReq = NULL;
- UnmapParamList = NULL;
- AsyncUnmapEvent = NULL;
- ReturnStatus = EFI_SUCCESS;
- if (Blocks / (UINTN)MaxLbaCnt > MaxBlkDespCnt) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));
- if (EraseBlkReq == NULL) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);
- if (EraseBlkReq->CommandPacket.Cdb == NULL) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- BlkDespCnt = (UINT32)((Blocks - 1) / MaxLbaCnt + 1);
- UnmapParamListLen = (UINT16)(sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)
- + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));
- UnmapParamList = AllocateZeroPool (UnmapParamListLen);
- if (UnmapParamList == NULL) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- *((UINT16 *)UnmapParamList) = SwapBytes16 (UnmapParamListLen - 2);
- *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
- BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));
- while (Blocks > 0) {
- if (Blocks > MaxLbaCnt) {
- *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
- *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);
- Blocks -= MaxLbaCnt;
- Lba += MaxLbaCnt;
- } else {
- *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);
- *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32)Blocks);
- Blocks = 0;
- }
- BlkDespPtr++;
- }
- CommandPacket = &EraseBlkReq->CommandPacket;
- CommandPacket->Timeout = SCSI_DISK_TIMEOUT;
- CommandPacket->OutDataBuffer = UnmapParamList;
- CommandPacket->OutTransferLength = UnmapParamListLen;
- CommandPacket->CdbLength = 0xA;
- CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;
- //
- // Fill Cdb for UNMAP Command
- //
- Cdb = CommandPacket->Cdb;
- Cdb[0] = EFI_SCSI_OP_UNMAP;
- WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));
- if ((Token != NULL) && (Token->Event != NULL)) {
- //
- // Non-blocking UNMAP request
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- ScsiDiskAsyncUnmapNotify,
- EraseBlkReq,
- &AsyncUnmapEvent
- );
- if (EFI_ERROR (Status)) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);
- gBS->RestoreTPL (OldTpl);
- EraseBlkReq->Token = Token;
- Status = ScsiIo->ExecuteScsiCommand (
- ScsiIo,
- CommandPacket,
- AsyncUnmapEvent
- );
- if (EFI_ERROR (Status)) {
- ReturnStatus = EFI_DEVICE_ERROR;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&EraseBlkReq->Link);
- gBS->RestoreTPL (OldTpl);
- goto Done;
- } else {
- //
- // Directly return if the non-blocking UNMAP request is queued.
- //
- return EFI_SUCCESS;
- }
- } else {
- //
- // Blocking UNMAP request
- //
- Status = ScsiIo->ExecuteScsiCommand (
- ScsiIo,
- CommandPacket,
- NULL
- );
- if (EFI_ERROR (Status)) {
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- }
- //
- // Only blocking UNMAP request will reach here.
- //
- Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
- CommandPacket->HostAdapterStatus
- ));
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- Status = CheckTargetStatus (CommandPacket->TargetStatus);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
- CommandPacket->HostAdapterStatus
- ));
- ReturnStatus = EFI_DEVICE_ERROR;
- goto Done;
- }
- Done:
- if (EraseBlkReq != NULL) {
- if (EraseBlkReq->CommandPacket.Cdb != NULL) {
- FreePool (EraseBlkReq->CommandPacket.Cdb);
- }
- FreePool (EraseBlkReq);
- }
- if (UnmapParamList != NULL) {
- FreePool (UnmapParamList);
- }
- if (AsyncUnmapEvent != NULL) {
- gBS->CloseEvent (AsyncUnmapEvent);
- }
- return ReturnStatus;
- }
- /**
- Erase a specified number of device blocks.
- @param[in] This Indicates a pointer to the calling context.
- @param[in] MediaId The media ID that the erase request is for.
- @param[in] Lba The starting logical block address to be
- erased. The caller is responsible for erasing
- only legitimate locations.
- @param[in, out] Token A pointer to the token associated with the
- transaction.
- @param[in] Size The size in bytes to be erased. This must be
- a multiple of the physical block size of the
- device.
- @retval EFI_SUCCESS The erase request was queued if Event is not
- NULL. The data was erased correctly to the
- device if the Event is NULL.to the device.
- @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
- protection.
- @retval EFI_DEVICE_ERROR The device reported an error while attempting
- to perform the erase operation.
- @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
- valid.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskEraseBlocks (
- IN EFI_ERASE_BLOCK_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
- IN UINTN Size
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- UINTN BlockSize;
- UINTN NumberOfBlocks;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- MediaChange = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- }
- //
- // Get the intrinsic block size
- //
- Media = ScsiDiskDevice->BlkIo.Media;
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if (MediaId != Media->MediaId) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Media->ReadOnly) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
- if (Size == 0) {
- if ((Token != NULL) && (Token->Event != NULL)) {
- Token->TransactionStatus = EFI_SUCCESS;
- gBS->SignalEvent (Token->Event);
- }
- Status = EFI_SUCCESS;
- goto Done;
- }
- BlockSize = Media->BlockSize;
- if ((Size % BlockSize) != 0) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- NumberOfBlocks = Size / BlockSize;
- if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((Token != NULL) && (Token->Event != NULL)) {
- Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);
- } else {
- Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);
- }
- Done:
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Send a security protocol command to a device that receives data and/or the result
- of one or more commands sent by SendData.
- The ReceiveData function sends a security protocol command to the given MediaId.
- The security protocol command sent is defined by SecurityProtocolId and contains
- the security protocol specific data SecurityProtocolSpecificData. The function
- returns the data from the security protocol command in PayloadBuffer.
- For devices supporting the SCSI command set, the security protocol command is sent
- using the SECURITY PROTOCOL IN command defined in SPC-4.
- If PayloadBufferSize is too small to store the available data from the security
- protocol command, the function shall copy PayloadBufferSize bytes into the
- PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
- If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
- the function shall return EFI_INVALID_PARAMETER.
- If the given MediaId does not support security protocol commands, the function shall
- return EFI_UNSUPPORTED. If there is no media in the device, the function returns
- EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
- the function returns EFI_MEDIA_CHANGED.
- If the security protocol fails to complete within the Timeout period, the function
- shall return EFI_TIMEOUT.
- If the security protocol command completes without an error, the function shall
- return EFI_SUCCESS. If the security protocol command completes with an error, the
- function shall return EFI_DEVICE_ERROR.
- @param This Indicates a pointer to the calling context.
- @param MediaId ID of the medium to receive data from.
- @param Timeout The timeout, in 100ns units, to use for the execution
- of the security protocol command. A Timeout value of 0
- means that this function will wait indefinitely for the
- security protocol command to execute. If Timeout is greater
- than zero, then this function will return EFI_TIMEOUT if the
- time required to execute the receive data command is greater than Timeout.
- @param SecurityProtocolId The value of the "Security Protocol" parameter of
- the security protocol command to be sent.
- @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
- of the security protocol command to be sent.
- @param PayloadBufferSize Size in bytes of the payload data buffer.
- @param PayloadBuffer A pointer to a destination buffer to store the security
- protocol command specific payload data for the security
- protocol command. The caller is responsible for having
- either implicit or explicit ownership of the buffer.
- @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
- data written to the payload data buffer.
- @retval EFI_SUCCESS The security protocol command completed successfully.
- @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
- data from the device. The PayloadBuffer contains the truncated data.
- @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
- @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
- PayloadBufferSize is non-zero.
- @retval EFI_TIMEOUT A timeout occurred while waiting for the security
- protocol command to execute.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskReceiveData (
- IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
- IN UINT32 MediaId OPTIONAL,
- IN UINT64 Timeout,
- IN UINT8 SecurityProtocolId,
- IN UINT16 SecurityProtocolSpecificData,
- IN UINTN PayloadBufferSize,
- OUT VOID *PayloadBuffer,
- OUT UINTN *PayloadTransferSize
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- VOID *AlignedBuffer;
- BOOLEAN AlignedBufferAllocated;
- AlignedBuffer = NULL;
- MediaChange = FALSE;
- AlignedBufferAllocated = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Validate Media
- //
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if ((MediaId != 0) && (MediaId != Media->MediaId)) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (PayloadBufferSize != 0) {
- if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
- AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
- if (AlignedBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- ZeroMem (AlignedBuffer, PayloadBufferSize);
- AlignedBufferAllocated = TRUE;
- } else {
- AlignedBuffer = PayloadBuffer;
- }
- }
- Status = ScsiSecurityProtocolInCommand (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- SecurityProtocolId,
- SecurityProtocolSpecificData,
- FALSE,
- PayloadBufferSize,
- AlignedBuffer,
- PayloadTransferSize
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- if (AlignedBufferAllocated) {
- CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);
- }
- if (PayloadBufferSize < *PayloadTransferSize) {
- Status = EFI_WARN_BUFFER_TOO_SMALL;
- goto Done;
- }
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Done:
- if (AlignedBufferAllocated) {
- ZeroMem (AlignedBuffer, PayloadBufferSize);
- FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
- }
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Send a security protocol command to a device.
- The SendData function sends a security protocol command containing the payload
- PayloadBuffer to the given MediaId. The security protocol command sent is
- defined by SecurityProtocolId and contains the security protocol specific data
- SecurityProtocolSpecificData. If the underlying protocol command requires a
- specific padding for the command payload, the SendData function shall add padding
- bytes to the command payload to satisfy the padding requirements.
- For devices supporting the SCSI command set, the security protocol command is sent
- using the SECURITY PROTOCOL OUT command defined in SPC-4.
- If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
- return EFI_INVALID_PARAMETER.
- If the given MediaId does not support security protocol commands, the function
- shall return EFI_UNSUPPORTED. If there is no media in the device, the function
- returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
- device, the function returns EFI_MEDIA_CHANGED.
- If the security protocol fails to complete within the Timeout period, the function
- shall return EFI_TIMEOUT.
- If the security protocol command completes without an error, the function shall return
- EFI_SUCCESS. If the security protocol command completes with an error, the function
- shall return EFI_DEVICE_ERROR.
- @param This Indicates a pointer to the calling context.
- @param MediaId ID of the medium to receive data from.
- @param Timeout The timeout, in 100ns units, to use for the execution
- of the security protocol command. A Timeout value of 0
- means that this function will wait indefinitely for the
- security protocol command to execute. If Timeout is greater
- than zero, then this function will return EFI_TIMEOUT if the
- time required to execute the receive data command is greater than Timeout.
- @param SecurityProtocolId The value of the "Security Protocol" parameter of
- the security protocol command to be sent.
- @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
- of the security protocol command to be sent.
- @param PayloadBufferSize Size in bytes of the payload data buffer.
- @param PayloadBuffer A pointer to a destination buffer to store the security
- protocol command specific payload data for the security
- protocol command.
- @retval EFI_SUCCESS The security protocol command completed successfully.
- @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
- @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
- @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
- @retval EFI_TIMEOUT A timeout occurred while waiting for the security
- protocol command to execute.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskSendData (
- IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
- IN UINT32 MediaId OPTIONAL,
- IN UINT64 Timeout,
- IN UINT8 SecurityProtocolId,
- IN UINT16 SecurityProtocolSpecificData,
- IN UINTN PayloadBufferSize,
- OUT VOID *PayloadBuffer
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO_MEDIA *Media;
- EFI_STATUS Status;
- BOOLEAN MediaChange;
- EFI_TPL OldTpl;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- VOID *AlignedBuffer;
- BOOLEAN AlignedBufferAllocated;
- AlignedBuffer = NULL;
- MediaChange = FALSE;
- AlignedBufferAllocated = FALSE;
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);
- Media = ScsiDiskDevice->BlkIo.Media;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {
- Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
- if (MediaChange) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIoProtocolGuid,
- &ScsiDiskDevice->BlkIo,
- &ScsiDiskDevice->BlkIo
- );
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiBlockIo2ProtocolGuid,
- &ScsiDiskDevice->BlkIo2,
- &ScsiDiskDevice->BlkIo2
- );
- if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiEraseBlockProtocolGuid,
- &ScsiDiskDevice->EraseBlock,
- &ScsiDiskDevice->EraseBlock
- );
- }
- if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {
- gBS->ReinstallProtocolInterface (
- ScsiDiskDevice->Handle,
- &gEfiStorageSecurityCommandProtocolGuid,
- &ScsiDiskDevice->StorageSecurity,
- &ScsiDiskDevice->StorageSecurity
- );
- }
- if (Media->MediaPresent) {
- Status = EFI_MEDIA_CHANGED;
- } else {
- Status = EFI_NO_MEDIA;
- }
- goto Done;
- }
- }
- //
- // Validate Media
- //
- if (!(Media->MediaPresent)) {
- Status = EFI_NO_MEDIA;
- goto Done;
- }
- if ((MediaId != 0) && (MediaId != Media->MediaId)) {
- Status = EFI_MEDIA_CHANGED;
- goto Done;
- }
- if (Media->ReadOnly) {
- Status = EFI_WRITE_PROTECTED;
- goto Done;
- }
- if (PayloadBufferSize != 0) {
- if (PayloadBuffer == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
- if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {
- AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);
- if (AlignedBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);
- AlignedBufferAllocated = TRUE;
- } else {
- AlignedBuffer = PayloadBuffer;
- }
- }
- Status = ScsiSecurityProtocolOutCommand (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- SecurityProtocolId,
- SecurityProtocolSpecificData,
- FALSE,
- PayloadBufferSize,
- AlignedBuffer
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Done:
- if (AlignedBufferAllocated) {
- ZeroMem (AlignedBuffer, PayloadBufferSize);
- FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);
- }
- gBS->RestoreTPL (OldTpl);
- return Status;
- }
- /**
- Detect Device and read out capacity ,if error occurs, parse the sense key.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param MustReadCapacity The flag about reading device capacity
- @param MediaChange The pointer of flag indicates if media has changed
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to detect media
- **/
- EFI_STATUS
- ScsiDiskDetectMedia (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN BOOLEAN MustReadCapacity,
- OUT BOOLEAN *MediaChange
- )
- {
- EFI_STATUS Status;
- EFI_SCSI_SENSE_DATA *SenseData;
- UINTN NumberOfSenseKeys;
- BOOLEAN NeedRetry;
- BOOLEAN NeedReadCapacity;
- UINT8 Retry;
- UINT8 MaxRetry;
- EFI_BLOCK_IO_MEDIA OldMedia;
- UINTN Action;
- EFI_EVENT TimeoutEvt;
- Status = EFI_SUCCESS;
- SenseData = NULL;
- NumberOfSenseKeys = 0;
- Retry = 0;
- MaxRetry = 3;
- Action = ACTION_NO_ACTION;
- NeedReadCapacity = FALSE;
- *MediaChange = FALSE;
- TimeoutEvt = NULL;
- CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
- Status = gBS->CreateEvent (
- EVT_TIMER,
- TPL_CALLBACK,
- NULL,
- NULL,
- &TimeoutEvt
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS (120));
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
- //
- // Sending Test_Unit cmd to poll device status.
- // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
- // We limit the upper boundary to 120 seconds.
- //
- while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
- Status = ScsiDiskTestUnitReady (
- ScsiDiskDevice,
- &NeedRetry,
- &SenseData,
- &NumberOfSenseKeys
- );
- if (!EFI_ERROR (Status)) {
- Status = DetectMediaParsingSenseKeys (
- ScsiDiskDevice,
- SenseData,
- NumberOfSenseKeys,
- &Action
- );
- if (EFI_ERROR (Status)) {
- goto EXIT;
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {
- continue;
- } else {
- break;
- }
- } else {
- Retry++;
- if (!NeedRetry || (Retry >= MaxRetry)) {
- goto EXIT;
- }
- }
- }
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
- //
- // ACTION_NO_ACTION: need not read capacity
- // other action code: need read capacity
- //
- if (Action == ACTION_READ_CAPACITY) {
- NeedReadCapacity = TRUE;
- }
- //
- // READ_CAPACITY command is not supported by any of the UFS WLUNs.
- //
- if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
- NeedReadCapacity = FALSE;
- MustReadCapacity = FALSE;
- ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
- }
- //
- // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
- // retrieve capacity via Read Capacity command
- //
- if (NeedReadCapacity || MustReadCapacity) {
- //
- // retrieve media information
- //
- for (Retry = 0; Retry < MaxRetry; Retry++) {
- Status = ScsiDiskReadCapacity (
- ScsiDiskDevice,
- &NeedRetry,
- &SenseData,
- &NumberOfSenseKeys
- );
- if (!EFI_ERROR (Status)) {
- //
- // analyze sense key to action
- //
- Status = DetectMediaParsingSenseKeys (
- ScsiDiskDevice,
- SenseData,
- NumberOfSenseKeys,
- &Action
- );
- if (EFI_ERROR (Status)) {
- //
- // if Status is error, it may indicate crisis error,
- // so return without retry.
- //
- goto EXIT;
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {
- Retry = 0;
- continue;
- } else {
- break;
- }
- } else {
- Retry++;
- if (!NeedRetry || (Retry >= MaxRetry)) {
- goto EXIT;
- }
- }
- }
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
- }
- if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
- //
- // Media change information got from the device
- //
- *MediaChange = TRUE;
- }
- if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
- *MediaChange = TRUE;
- ScsiDiskDevice->BlkIo.Media->MediaId += 1;
- }
- if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
- *MediaChange = TRUE;
- ScsiDiskDevice->BlkIo.Media->MediaId += 1;
- }
- if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
- *MediaChange = TRUE;
- ScsiDiskDevice->BlkIo.Media->MediaId += 1;
- }
- if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
- if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
- //
- // when change from no media to media present, reset the MediaId to 1.
- //
- ScsiDiskDevice->BlkIo.Media->MediaId = 1;
- } else {
- //
- // when no media, reset the MediaId to zero.
- //
- ScsiDiskDevice->BlkIo.Media->MediaId = 0;
- }
- *MediaChange = TRUE;
- }
- EXIT:
- if (TimeoutEvt != NULL) {
- gBS->CloseEvent (TimeoutEvt);
- }
- return Status;
- }
- /**
- Send out Inquiry command to Device.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param NeedRetry Indicates if needs try again when error happens
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to detect media
- **/
- EFI_STATUS
- ScsiDiskInquiryDevice (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry
- )
- {
- UINT32 InquiryDataLength;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- EFI_SCSI_SENSE_DATA *SenseDataArray;
- UINTN NumberOfSenseKeys;
- EFI_STATUS Status;
- UINT8 MaxRetry;
- UINT8 Index;
- EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
- EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;
- UINTN PageLength;
- InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
- SenseDataLength = 0;
- Status = ScsiInquiryCommand (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)&(ScsiDiskDevice->InquiryData),
- &InquiryDataLength,
- FALSE
- );
- //
- // no need to check HostAdapterStatus and TargetStatus
- //
- if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
- ParseInquiryData (ScsiDiskDevice);
- if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
- //
- // Check whether the device supports Block Limits VPD page (0xB0)
- //
- SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
- if (SupportedVpdPages == NULL) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
- InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
- SenseDataLength = 0;
- Status = ScsiInquiryCommandEx (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)SupportedVpdPages,
- &InquiryDataLength,
- TRUE,
- EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
- );
- if (!EFI_ERROR (Status)) {
- PageLength = (SupportedVpdPages->PageLength2 << 8)
- | SupportedVpdPages->PageLength1;
- //
- // Sanity checks for coping with broken devices
- //
- if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {
- DEBUG ((
- DEBUG_WARN,
- "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
- __FUNCTION__,
- (UINT32)PageLength
- ));
- PageLength = 0;
- }
- if ((PageLength > 0) &&
- (SupportedVpdPages->SupportedVpdPageList[0] !=
- EFI_SCSI_PAGE_CODE_SUPPORTED_VPD))
- {
- DEBUG ((
- DEBUG_WARN,
- "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
- __FUNCTION__,
- EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
- ));
- PageLength = 0;
- }
- //
- // Locate the code for the Block Limits VPD page
- //
- for (Index = 0; Index < PageLength; Index++) {
- //
- // Sanity check
- //
- if ((Index > 0) &&
- (SupportedVpdPages->SupportedVpdPageList[Index] <=
- SupportedVpdPages->SupportedVpdPageList[Index - 1]))
- {
- DEBUG ((
- DEBUG_WARN,
- "%a: non-ascending code in Supported VPD Pages page @ %u\n",
- __FUNCTION__,
- Index
- ));
- Index = 0;
- PageLength = 0;
- break;
- }
- if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
- break;
- }
- }
- //
- // Query the Block Limits VPD page
- //
- if (Index < PageLength) {
- BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
- if (BlockLimits == NULL) {
- FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
- InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
- SenseDataLength = 0;
- Status = ScsiInquiryCommandEx (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)BlockLimits,
- &InquiryDataLength,
- TRUE,
- EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
- );
- if (!EFI_ERROR (Status)) {
- ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
- (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
- BlockLimits->OptimalTransferLengthGranularity1;
- ScsiDiskDevice->UnmapInfo.MaxLbaCnt =
- (BlockLimits->MaximumUnmapLbaCount4 << 24) |
- (BlockLimits->MaximumUnmapLbaCount3 << 16) |
- (BlockLimits->MaximumUnmapLbaCount2 << 8) |
- BlockLimits->MaximumUnmapLbaCount1;
- ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =
- (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |
- (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |
- (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8) |
- BlockLimits->MaximumUnmapBlockDescriptorCount1;
- ScsiDiskDevice->EraseBlock.EraseLengthGranularity =
- (BlockLimits->OptimalUnmapGranularity4 << 24) |
- (BlockLimits->OptimalUnmapGranularity3 << 16) |
- (BlockLimits->OptimalUnmapGranularity2 << 8) |
- BlockLimits->OptimalUnmapGranularity1;
- if (BlockLimits->UnmapGranularityAlignmentValid != 0) {
- ScsiDiskDevice->UnmapInfo.GranularityAlignment =
- (BlockLimits->UnmapGranularityAlignment4 << 24) |
- (BlockLimits->UnmapGranularityAlignment3 << 16) |
- (BlockLimits->UnmapGranularityAlignment2 << 8) |
- BlockLimits->UnmapGranularityAlignment1;
- }
- if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {
- //
- // A value of 0 indicates that the optimal unmap granularity is
- // not reported.
- //
- ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
- }
- ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;
- }
- FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
- }
- }
- FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
- }
- }
- if (!EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- } else if (Status == EFI_NOT_READY) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // if goes here, meant ScsiInquiryCommand() failed.
- // if ScsiDiskRequestSenseKeys() succeeds at last,
- // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
- //
- MaxRetry = 3;
- for (Index = 0; Index < MaxRetry; Index++) {
- Status = ScsiDiskRequestSenseKeys (
- ScsiDiskDevice,
- NeedRetry,
- &SenseDataArray,
- &NumberOfSenseKeys,
- TRUE
- );
- if (!EFI_ERROR (Status)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- }
- if (!*NeedRetry) {
- return EFI_DEVICE_ERROR;
- }
- }
- //
- // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
- // set *NeedRetry = FALSE to avoid the outside caller try again.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- /**
- To test device.
- When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
- When Test Unit Ready command encounters any error caused by host adapter or
- target, return error without retrieving Sense Keys.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param NeedRetry The pointer of flag indicates try again
- @param SenseDataArray The pointer of an array of sense data
- @param NumberOfSenseKeys The pointer of the number of sense data array
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to test unit
- **/
- EFI_STATUS
- ScsiDiskTestUnitReady (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
- OUT UINTN *NumberOfSenseKeys
- )
- {
- EFI_STATUS Status;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- UINT8 Index;
- UINT8 MaxRetry;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- *NumberOfSenseKeys = 0;
- //
- // Parameter 3 and 4: do not require sense data, retrieve it when needed.
- //
- Status = ScsiTestUnitReadyCommand (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus
- );
- //
- // no need to check HostAdapterStatus and TargetStatus
- //
- if (Status == EFI_NOT_READY) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- if (SenseDataLength != 0) {
- *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
- *SenseDataArray = ScsiDiskDevice->SenseData;
- return EFI_SUCCESS;
- }
- MaxRetry = 3;
- for (Index = 0; Index < MaxRetry; Index++) {
- Status = ScsiDiskRequestSenseKeys (
- ScsiDiskDevice,
- NeedRetry,
- SenseDataArray,
- NumberOfSenseKeys,
- FALSE
- );
- if (!EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- }
- if (!*NeedRetry) {
- return EFI_DEVICE_ERROR;
- }
- }
- //
- // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
- // set *NeedRetry = FALSE to avoid the outside caller try again.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- /**
- Parsing Sense Keys which got from request sense command.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param NumberOfSenseKeys The number of sense key
- @param Action The pointer of action which indicates what is need to do next
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to complete the parsing
- **/
- EFI_STATUS
- DetectMediaParsingSenseKeys (
- OUT SCSI_DISK_DEV *ScsiDiskDevice,
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN NumberOfSenseKeys,
- OUT UINTN *Action
- )
- {
- BOOLEAN RetryLater;
- //
- // Default is to read capacity, unless..
- //
- *Action = ACTION_READ_CAPACITY;
- if (NumberOfSenseKeys == 0) {
- if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
- *Action = ACTION_NO_ACTION;
- }
- return EFI_SUCCESS;
- }
- if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
- //
- // No Sense Key returned from last submitted command
- //
- if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
- *Action = ACTION_NO_ACTION;
- }
- return EFI_SUCCESS;
- }
- if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
- ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
- ScsiDiskDevice->BlkIo.Media->LastBlock = 0;
- *Action = ACTION_NO_ACTION;
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
- return EFI_SUCCESS;
- }
- if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
- ScsiDiskDevice->BlkIo.Media->MediaId++;
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
- return EFI_SUCCESS;
- }
- if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
- *Action = ACTION_RETRY_COMMAND_LATER;
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
- return EFI_SUCCESS;
- }
- if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
- *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
- return EFI_DEVICE_ERROR;
- }
- if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
- *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
- return EFI_DEVICE_ERROR;
- }
- if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
- if (RetryLater) {
- *Action = ACTION_RETRY_COMMAND_LATER;
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
- return EFI_SUCCESS;
- }
- *Action = ACTION_NO_ACTION;
- return EFI_DEVICE_ERROR;
- }
- *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
- DEBUG ((DEBUG_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
- return EFI_SUCCESS;
- }
- /**
- Send read capacity command to device and get the device parameter.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param NeedRetry The pointer of flag indicates if need a retry
- @param SenseDataArray The pointer of an array of sense data
- @param NumberOfSenseKeys The number of sense key
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
- **/
- EFI_STATUS
- ScsiDiskReadCapacity (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
- OUT UINTN *NumberOfSenseKeys
- )
- {
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- EFI_STATUS CommandStatus;
- EFI_STATUS Status;
- UINT8 Index;
- UINT8 MaxRetry;
- UINT8 SenseDataLength;
- UINT32 DataLength10;
- UINT32 DataLength16;
- EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;
- EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
- CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
- if (CapacityData10 == NULL) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- if (CapacityData16 == NULL) {
- FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- SenseDataLength = 0;
- DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
- DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
- ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
- ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- *NumberOfSenseKeys = 0;
- *NeedRetry = FALSE;
- //
- // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
- // 16 byte command should be used to access large hard disk >2TB
- //
- CommandStatus = ScsiReadCapacityCommand (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)CapacityData10,
- &DataLength10,
- FALSE
- );
- ScsiDiskDevice->Cdb16Byte = FALSE;
- if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
- (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff))
- {
- //
- // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
- //
- ScsiDiskDevice->Cdb16Byte = TRUE;
- //
- // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
- // and LowestAlignedLba
- //
- CommandStatus = ScsiReadCapacity16Command (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)CapacityData16,
- &DataLength16,
- FALSE
- );
- }
- //
- // no need to check HostAdapterStatus and TargetStatus
- //
- if (CommandStatus == EFI_SUCCESS) {
- GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
- FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
- FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- return EFI_SUCCESS;
- }
- FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
- FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- if (CommandStatus == EFI_NOT_READY) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // if goes here, meant ScsiReadCapacityCommand() failed.
- // if ScsiDiskRequestSenseKeys() succeeds at last,
- // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
- //
- MaxRetry = 3;
- for (Index = 0; Index < MaxRetry; Index++) {
- Status = ScsiDiskRequestSenseKeys (
- ScsiDiskDevice,
- NeedRetry,
- SenseDataArray,
- NumberOfSenseKeys,
- TRUE
- );
- if (!EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- }
- if (!*NeedRetry) {
- return EFI_DEVICE_ERROR;
- }
- }
- //
- // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
- // set *NeedRetry = FALSE to avoid the outside caller try again.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- /**
- Check the HostAdapter status and re-interpret it in EFI_STATUS.
- @param HostAdapterStatus Host Adapter status
- @retval EFI_SUCCESS Host adapter is OK.
- @retval EFI_TIMEOUT Timeout.
- @retval EFI_NOT_READY Adapter NOT ready.
- @retval EFI_DEVICE_ERROR Adapter device error.
- **/
- EFI_STATUS
- CheckHostAdapterStatus (
- IN UINT8 HostAdapterStatus
- )
- {
- switch (HostAdapterStatus) {
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
- return EFI_SUCCESS;
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
- return EFI_TIMEOUT;
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
- return EFI_NOT_READY;
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
- case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
- return EFI_DEVICE_ERROR;
- default:
- return EFI_SUCCESS;
- }
- }
- /**
- Check the target status and re-interpret it in EFI_STATUS.
- @param TargetStatus Target status
- @retval EFI_NOT_READY Device is NOT ready.
- @retval EFI_DEVICE_ERROR
- @retval EFI_SUCCESS
- **/
- EFI_STATUS
- CheckTargetStatus (
- IN UINT8 TargetStatus
- )
- {
- switch (TargetStatus) {
- case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
- case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
- case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
- return EFI_SUCCESS;
- case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
- case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
- case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
- case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
- return EFI_NOT_READY;
- case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
- return EFI_DEVICE_ERROR;
- default:
- return EFI_SUCCESS;
- }
- }
- /**
- Retrieve all sense keys from the device.
- When encountering error during the process, if retrieve sense keys before
- error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
- and NeedRetry set to FALSE; otherwise, return the proper return status.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param NeedRetry The pointer of flag indicates if need a retry
- @param SenseDataArray The pointer of an array of sense data
- @param NumberOfSenseKeys The number of sense key
- @param AskResetIfError The flag indicates if need reset when error occurs
- @retval EFI_DEVICE_ERROR Indicates that error occurs
- @retval EFI_SUCCESS Successfully to request sense key
- **/
- EFI_STATUS
- ScsiDiskRequestSenseKeys (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray,
- OUT UINTN *NumberOfSenseKeys,
- IN BOOLEAN AskResetIfError
- )
- {
- EFI_SCSI_SENSE_DATA *PtrSenseData;
- UINT8 SenseDataLength;
- BOOLEAN SenseReq;
- EFI_STATUS Status;
- EFI_STATUS FallStatus;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- FallStatus = EFI_SUCCESS;
- SenseDataLength = (UINT8)sizeof (EFI_SCSI_SENSE_DATA);
- ZeroMem (
- ScsiDiskDevice->SenseData,
- sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
- );
- *NumberOfSenseKeys = 0;
- *SenseDataArray = ScsiDiskDevice->SenseData;
- Status = EFI_SUCCESS;
- PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
- if (PtrSenseData == NULL) {
- return EFI_DEVICE_ERROR;
- }
- for (SenseReq = TRUE; SenseReq;) {
- ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
- Status = ScsiRequestSenseCommand (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- PtrSenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus
- );
- if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
- FallStatus = EFI_SUCCESS;
- } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- FallStatus = EFI_DEVICE_ERROR;
- } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- FallStatus = EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- if (AskResetIfError) {
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- }
- FallStatus = EFI_DEVICE_ERROR;
- }
- if (EFI_ERROR (FallStatus)) {
- if (*NumberOfSenseKeys != 0) {
- *NeedRetry = FALSE;
- Status = EFI_SUCCESS;
- goto EXIT;
- } else {
- Status = EFI_DEVICE_ERROR;
- goto EXIT;
- }
- }
- CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
- (*NumberOfSenseKeys) += 1;
- //
- // no more sense key or number of sense keys exceeds predefined,
- // skip the loop.
- //
- if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
- (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber))
- {
- SenseReq = FALSE;
- }
- }
- EXIT:
- FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
- return Status;
- }
- /**
- Get information from media read capacity command.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
- @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
- **/
- VOID
- GetMediaInfo (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice,
- IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,
- IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16
- )
- {
- UINT8 *Ptr;
- if (!ScsiDiskDevice->Cdb16Byte) {
- ScsiDiskDevice->BlkIo.Media->LastBlock = ((UINT32)Capacity10->LastLba3 << 24) |
- (Capacity10->LastLba2 << 16) |
- (Capacity10->LastLba1 << 8) |
- Capacity10->LastLba0;
- ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
- (Capacity10->BlockSize2 << 16) |
- (Capacity10->BlockSize1 << 8) |
- Capacity10->BlockSize0;
- ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;
- ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;
- if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
- ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
- }
- } else {
- Ptr = (UINT8 *)&ScsiDiskDevice->BlkIo.Media->LastBlock;
- *Ptr++ = Capacity16->LastLba0;
- *Ptr++ = Capacity16->LastLba1;
- *Ptr++ = Capacity16->LastLba2;
- *Ptr++ = Capacity16->LastLba3;
- *Ptr++ = Capacity16->LastLba4;
- *Ptr++ = Capacity16->LastLba5;
- *Ptr++ = Capacity16->LastLba6;
- *Ptr = Capacity16->LastLba7;
- ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
- (Capacity16->BlockSize2 << 16) |
- (Capacity16->BlockSize1 << 8) |
- Capacity16->BlockSize0;
- ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
- Capacity16->LowestAlignLogic1;
- ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);
- if (!ScsiDiskDevice->BlockLimitsVpdSupported) {
- if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32)-1) {
- ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)-1;
- } else {
- ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;
- }
- }
- }
- ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
- }
- /**
- Parse Inquiry data.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- **/
- VOID
- ParseInquiryData (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice
- )
- {
- ScsiDiskDevice->FixedDevice = (BOOLEAN)((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
- ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN)(!ScsiDiskDevice->FixedDevice);
- }
- /**
- Read sector from SCSI Disk.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param Buffer The buffer to fill in the read out data
- @param Lba Logic block address
- @param NumberOfBlocks The number of blocks to read
- @retval EFI_DEVICE_ERROR Indicates a device error.
- @retval EFI_SUCCESS Operation is successful.
- **/
- EFI_STATUS
- ScsiDiskReadSectors (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT VOID *Buffer,
- IN EFI_LBA Lba,
- IN UINTN NumberOfBlocks
- )
- {
- UINTN BlocksRemaining;
- UINT8 *PtrBuffer;
- UINT32 BlockSize;
- UINT32 ByteCount;
- UINT32 MaxBlock;
- UINT32 SectorCount;
- UINT32 NextSectorCount;
- UINT64 Timeout;
- EFI_STATUS Status;
- UINT8 Index;
- UINT8 MaxRetry;
- BOOLEAN NeedRetry;
- Status = EFI_SUCCESS;
- BlocksRemaining = NumberOfBlocks;
- BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
- //
- // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- MaxBlock = 0xFFFF;
- } else {
- MaxBlock = 0xFFFFFFFF;
- }
- PtrBuffer = Buffer;
- while (BlocksRemaining > 0) {
- if (BlocksRemaining <= MaxBlock) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- SectorCount = (UINT16)BlocksRemaining;
- } else {
- SectorCount = (UINT32)BlocksRemaining;
- }
- } else {
- SectorCount = MaxBlock;
- }
- ByteCount = SectorCount * BlockSize;
- //
- // |------------------------|-----------------|------------------|-----------------|
- // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- //
- // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
- // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
- // From the above table, we could know 2.1Mbytes per second is lowest one.
- // The timeout value is rounded up to nearest integer and here an additional 30s is added
- // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
- // commands in the Standby/Idle mode.
- //
- Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
- MaxRetry = 2;
- for (Index = 0; Index < MaxRetry; Index++) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskRead10 (
- ScsiDiskDevice,
- &NeedRetry,
- Timeout,
- PtrBuffer,
- &ByteCount,
- (UINT32)Lba,
- SectorCount
- );
- } else {
- Status = ScsiDiskRead16 (
- ScsiDiskDevice,
- &NeedRetry,
- Timeout,
- PtrBuffer,
- &ByteCount,
- Lba,
- SectorCount
- );
- }
- if (!EFI_ERROR (Status)) {
- break;
- }
- if (!NeedRetry) {
- return EFI_DEVICE_ERROR;
- }
- //
- // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
- // lowered ByteCount on output, we must make sure that we lower
- // SectorCount accordingly. SectorCount will be encoded in the CDB, and
- // it is invalid to request more sectors in the CDB than the entire
- // transfer (ie. ByteCount) can carry.
- //
- // In addition, ByteCount is only expected to go down, or stay unchanged.
- // Therefore we don't need to update Timeout: the original timeout should
- // accommodate shorter transfers too.
- //
- NextSectorCount = ByteCount / BlockSize;
- if (NextSectorCount < SectorCount) {
- SectorCount = NextSectorCount;
- //
- // Account for any rounding down.
- //
- ByteCount = SectorCount * BlockSize;
- }
- }
- if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
- return EFI_DEVICE_ERROR;
- }
- //
- // actual transferred sectors
- //
- SectorCount = ByteCount / BlockSize;
- Lba += SectorCount;
- PtrBuffer = PtrBuffer + SectorCount * BlockSize;
- BlocksRemaining -= SectorCount;
- }
- return EFI_SUCCESS;
- }
- /**
- Write sector to SCSI Disk.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @param Buffer The buffer of data to be written into SCSI Disk
- @param Lba Logic block address
- @param NumberOfBlocks The number of blocks to read
- @retval EFI_DEVICE_ERROR Indicates a device error.
- @retval EFI_SUCCESS Operation is successful.
- **/
- EFI_STATUS
- ScsiDiskWriteSectors (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN VOID *Buffer,
- IN EFI_LBA Lba,
- IN UINTN NumberOfBlocks
- )
- {
- UINTN BlocksRemaining;
- UINT8 *PtrBuffer;
- UINT32 BlockSize;
- UINT32 ByteCount;
- UINT32 MaxBlock;
- UINT32 SectorCount;
- UINT32 NextSectorCount;
- UINT64 Timeout;
- EFI_STATUS Status;
- UINT8 Index;
- UINT8 MaxRetry;
- BOOLEAN NeedRetry;
- Status = EFI_SUCCESS;
- BlocksRemaining = NumberOfBlocks;
- BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
- //
- // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- MaxBlock = 0xFFFF;
- } else {
- MaxBlock = 0xFFFFFFFF;
- }
- PtrBuffer = Buffer;
- while (BlocksRemaining > 0) {
- if (BlocksRemaining <= MaxBlock) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- SectorCount = (UINT16)BlocksRemaining;
- } else {
- SectorCount = (UINT32)BlocksRemaining;
- }
- } else {
- SectorCount = MaxBlock;
- }
- ByteCount = SectorCount * BlockSize;
- //
- // |------------------------|-----------------|------------------|-----------------|
- // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- //
- // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
- // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
- // From the above table, we could know 2.1Mbytes per second is lowest one.
- // The timeout value is rounded up to nearest integer and here an additional 30s is added
- // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
- // commands in the Standby/Idle mode.
- //
- Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
- MaxRetry = 2;
- for (Index = 0; Index < MaxRetry; Index++) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskWrite10 (
- ScsiDiskDevice,
- &NeedRetry,
- Timeout,
- PtrBuffer,
- &ByteCount,
- (UINT32)Lba,
- SectorCount
- );
- } else {
- Status = ScsiDiskWrite16 (
- ScsiDiskDevice,
- &NeedRetry,
- Timeout,
- PtrBuffer,
- &ByteCount,
- Lba,
- SectorCount
- );
- }
- if (!EFI_ERROR (Status)) {
- break;
- }
- if (!NeedRetry) {
- return EFI_DEVICE_ERROR;
- }
- //
- // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
- // has lowered ByteCount on output, we must make sure that we lower
- // SectorCount accordingly. SectorCount will be encoded in the CDB, and
- // it is invalid to request more sectors in the CDB than the entire
- // transfer (ie. ByteCount) can carry.
- //
- // In addition, ByteCount is only expected to go down, or stay unchanged.
- // Therefore we don't need to update Timeout: the original timeout should
- // accommodate shorter transfers too.
- //
- NextSectorCount = ByteCount / BlockSize;
- if (NextSectorCount < SectorCount) {
- SectorCount = NextSectorCount;
- //
- // Account for any rounding down.
- //
- ByteCount = SectorCount * BlockSize;
- }
- }
- if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
- return EFI_DEVICE_ERROR;
- }
- //
- // actual transferred sectors
- //
- SectorCount = ByteCount / BlockSize;
- Lba += SectorCount;
- PtrBuffer = PtrBuffer + SectorCount * BlockSize;
- BlocksRemaining -= SectorCount;
- }
- return EFI_SUCCESS;
- }
- /**
- Asynchronously read sector from SCSI Disk.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
- @param Buffer The buffer to fill in the read out data.
- @param Lba Logic block address.
- @param NumberOfBlocks The number of blocks to read.
- @param Token A pointer to the token associated with the
- non-blocking read request.
- @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
- @retval EFI_DEVICE_ERROR Indicates a device error.
- @retval EFI_SUCCESS Operation is successful.
- **/
- EFI_STATUS
- ScsiDiskAsyncReadSectors (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT VOID *Buffer,
- IN EFI_LBA Lba,
- IN UINTN NumberOfBlocks,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- UINTN BlocksRemaining;
- UINT8 *PtrBuffer;
- UINT32 BlockSize;
- UINT32 ByteCount;
- UINT32 MaxBlock;
- UINT32 SectorCount;
- UINT64 Timeout;
- SCSI_BLKIO2_REQUEST *BlkIo2Req;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- if ((Token == NULL) || (Token->Event == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
- if (BlkIo2Req == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- BlkIo2Req->Token = Token;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
- gBS->RestoreTPL (OldTpl);
- InitializeListHead (&BlkIo2Req->ScsiRWQueue);
- Status = EFI_SUCCESS;
- BlocksRemaining = NumberOfBlocks;
- BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
- //
- // Limit the data bytes that can be transferred by one Read(10) or Read(16)
- // Command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- MaxBlock = 0xFFFF;
- } else {
- MaxBlock = 0xFFFFFFFF;
- }
- PtrBuffer = Buffer;
- while (BlocksRemaining > 0) {
- if (BlocksRemaining <= MaxBlock) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- SectorCount = (UINT16)BlocksRemaining;
- } else {
- SectorCount = (UINT32)BlocksRemaining;
- }
- } else {
- SectorCount = MaxBlock;
- }
- ByteCount = SectorCount * BlockSize;
- //
- // |------------------------|-----------------|------------------|-----------------|
- // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- //
- // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
- // we have to use the lowest transfer rate to calculate the possible
- // maximum timeout value for each operation.
- // From the above table, we could know 2.1Mbytes per second is lowest one.
- // The timeout value is rounded up to nearest integer and here an additional
- // 30s is added to follow ATA spec in which it mentioned that the device
- // may take up to 30s to respond commands in the Standby/Idle mode.
- //
- Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncRead10 (
- ScsiDiskDevice,
- Timeout,
- 0,
- PtrBuffer,
- ByteCount,
- (UINT32)Lba,
- SectorCount,
- BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncRead16 (
- ScsiDiskDevice,
- Timeout,
- 0,
- PtrBuffer,
- ByteCount,
- Lba,
- SectorCount,
- BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- //
- // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
- // length of a SCSI I/O command is too large.
- // In this case, we retry sending the SCSI command with a data length
- // half of its previous value.
- //
- if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
- if ((MaxBlock > 1) && (SectorCount > 1)) {
- MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
- continue;
- }
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
- //
- // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
- // SCSI sub-task running. Otherwise, it will be freed in the callback
- // function ScsiDiskNotify().
- //
- RemoveEntryList (&BlkIo2Req->Link);
- FreePool (BlkIo2Req);
- BlkIo2Req = NULL;
- gBS->RestoreTPL (OldTpl);
- //
- // It is safe to return error status to the caller, since there is no
- // previous SCSI sub-task executing.
- //
- Status = EFI_DEVICE_ERROR;
- goto Done;
- } else {
- gBS->RestoreTPL (OldTpl);
- //
- // There are previous SCSI commands still running, EFI_SUCCESS should
- // be returned to make sure that the caller does not free resources
- // still using by these SCSI commands.
- //
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
- //
- // Sectors submitted for transfer
- //
- SectorCount = ByteCount / BlockSize;
- Lba += SectorCount;
- PtrBuffer = PtrBuffer + SectorCount * BlockSize;
- BlocksRemaining -= SectorCount;
- }
- Status = EFI_SUCCESS;
- Done:
- if (BlkIo2Req != NULL) {
- BlkIo2Req->LastScsiRW = TRUE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
- RemoveEntryList (&BlkIo2Req->Link);
- FreePool (BlkIo2Req);
- BlkIo2Req = NULL;
- gBS->SignalEvent (Token->Event);
- }
- gBS->RestoreTPL (OldTpl);
- }
- return Status;
- }
- /**
- Asynchronously write sector to SCSI Disk.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
- @param Buffer The buffer of data to be written into SCSI Disk.
- @param Lba Logic block address.
- @param NumberOfBlocks The number of blocks to read.
- @param Token A pointer to the token associated with the
- non-blocking read request.
- @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
- @retval EFI_DEVICE_ERROR Indicates a device error.
- @retval EFI_SUCCESS Operation is successful.
- **/
- EFI_STATUS
- ScsiDiskAsyncWriteSectors (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN VOID *Buffer,
- IN EFI_LBA Lba,
- IN UINTN NumberOfBlocks,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- UINTN BlocksRemaining;
- UINT8 *PtrBuffer;
- UINT32 BlockSize;
- UINT32 ByteCount;
- UINT32 MaxBlock;
- UINT32 SectorCount;
- UINT64 Timeout;
- SCSI_BLKIO2_REQUEST *BlkIo2Req;
- EFI_STATUS Status;
- EFI_TPL OldTpl;
- if ((Token == NULL) || (Token->Event == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
- if (BlkIo2Req == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- BlkIo2Req->Token = Token;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);
- gBS->RestoreTPL (OldTpl);
- InitializeListHead (&BlkIo2Req->ScsiRWQueue);
- Status = EFI_SUCCESS;
- BlocksRemaining = NumberOfBlocks;
- BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;
- //
- // Limit the data bytes that can be transferred by one Read(10) or Read(16)
- // Command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- MaxBlock = 0xFFFF;
- } else {
- MaxBlock = 0xFFFFFFFF;
- }
- PtrBuffer = Buffer;
- while (BlocksRemaining > 0) {
- if (BlocksRemaining <= MaxBlock) {
- if (!ScsiDiskDevice->Cdb16Byte) {
- SectorCount = (UINT16)BlocksRemaining;
- } else {
- SectorCount = (UINT32)BlocksRemaining;
- }
- } else {
- SectorCount = MaxBlock;
- }
- ByteCount = SectorCount * BlockSize;
- //
- // |------------------------|-----------------|------------------|-----------------|
- // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
- // |------------------------|-----------------|------------------|-----------------|
- //
- // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
- // we have to use the lowest transfer rate to calculate the possible
- // maximum timeout value for each operation.
- // From the above table, we could know 2.1Mbytes per second is lowest one.
- // The timeout value is rounded up to nearest integer and here an additional
- // 30s is added to follow ATA spec in which it mentioned that the device
- // may take up to 30s to respond commands in the Standby/Idle mode.
- //
- Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncWrite10 (
- ScsiDiskDevice,
- Timeout,
- 0,
- PtrBuffer,
- ByteCount,
- (UINT32)Lba,
- SectorCount,
- BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncWrite16 (
- ScsiDiskDevice,
- Timeout,
- 0,
- PtrBuffer,
- ByteCount,
- Lba,
- SectorCount,
- BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- //
- // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
- // length of a SCSI I/O command is too large.
- // In this case, we retry sending the SCSI command with a data length
- // half of its previous value.
- //
- if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
- if ((MaxBlock > 1) && (SectorCount > 1)) {
- MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
- continue;
- }
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
- //
- // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
- // SCSI sub-task running. Otherwise, it will be freed in the callback
- // function ScsiDiskNotify().
- //
- RemoveEntryList (&BlkIo2Req->Link);
- FreePool (BlkIo2Req);
- BlkIo2Req = NULL;
- gBS->RestoreTPL (OldTpl);
- //
- // It is safe to return error status to the caller, since there is no
- // previous SCSI sub-task executing.
- //
- Status = EFI_DEVICE_ERROR;
- goto Done;
- } else {
- gBS->RestoreTPL (OldTpl);
- //
- // There are previous SCSI commands still running, EFI_SUCCESS should
- // be returned to make sure that the caller does not free resources
- // still using by these SCSI commands.
- //
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
- //
- // Sectors submitted for transfer
- //
- SectorCount = ByteCount / BlockSize;
- Lba += SectorCount;
- PtrBuffer = PtrBuffer + SectorCount * BlockSize;
- BlocksRemaining -= SectorCount;
- }
- Status = EFI_SUCCESS;
- Done:
- if (BlkIo2Req != NULL) {
- BlkIo2Req->LastScsiRW = TRUE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
- RemoveEntryList (&BlkIo2Req->Link);
- FreePool (BlkIo2Req);
- BlkIo2Req = NULL;
- gBS->SignalEvent (Token->Event);
- }
- gBS->RestoreTPL (OldTpl);
- }
- return Status;
- }
- /**
- Submit Read(10) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice
- @param NeedRetry The pointer of flag indicates if needs retry if error happens
- @param Timeout The time to complete the command
- @param DataBuffer The buffer to fill with the read out data
- @param DataLength The length of buffer
- @param StartLba The start logic block address
- @param SectorCount The number of blocks to read
- @return EFI_STATUS is returned by calling ScsiRead10Command().
- **/
- EFI_STATUS
- ScsiDiskRead10 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- IN UINT64 Timeout,
- OUT UINT8 *DataBuffer,
- IN OUT UINT32 *DataLength,
- IN UINT32 StartLba,
- IN UINT32 SectorCount
- )
- {
- UINT8 SenseDataLength;
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- UINTN Action;
- //
- // Implement a backoff algorithm to resolve some compatibility issues that
- // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
- // big data in a single operation.
- // This algorithm will at first try to execute original request. If the request fails
- // with media error sense data or else, it will reduce the transfer length to half and
- // try again till the operation succeeds or fails with one sector transfer length.
- //
- BackOff:
- *NeedRetry = FALSE;
- Action = ACTION_NO_ACTION;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- ReturnStatus = ScsiRead10Command (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- DataBuffer,
- DataLength,
- StartLba,
- SectorCount
- );
- if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return ReturnStatus;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
- DEBUG ((DEBUG_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
- DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
- if (Action == ACTION_RETRY_COMMAND_LATER) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
- if (SectorCount <= 1) {
- //
- // Jump out if the operation still fails with one sector transfer length.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // Try again with half length if the sense data shows we need to retry.
- //
- SectorCount >>= 1;
- *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
- goto BackOff;
- } else {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- }
- return ReturnStatus;
- }
- /**
- Submit Write(10) Command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice
- @param NeedRetry The pointer of flag indicates if needs retry if error happens
- @param Timeout The time to complete the command
- @param DataBuffer The buffer to fill with the read out data
- @param DataLength The length of buffer
- @param StartLba The start logic block address
- @param SectorCount The number of blocks to write
- @return EFI_STATUS is returned by calling ScsiWrite10Command().
- **/
- EFI_STATUS
- ScsiDiskWrite10 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- IN UINT64 Timeout,
- IN UINT8 *DataBuffer,
- IN OUT UINT32 *DataLength,
- IN UINT32 StartLba,
- IN UINT32 SectorCount
- )
- {
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- UINTN Action;
- //
- // Implement a backoff algorithm to resolve some compatibility issues that
- // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
- // big data in a single operation.
- // This algorithm will at first try to execute original request. If the request fails
- // with media error sense data or else, it will reduce the transfer length to half and
- // try again till the operation succeeds or fails with one sector transfer length.
- //
- BackOff:
- *NeedRetry = FALSE;
- Action = ACTION_NO_ACTION;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- ReturnStatus = ScsiWrite10Command (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- DataBuffer,
- DataLength,
- StartLba,
- SectorCount
- );
- if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return ReturnStatus;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
- DEBUG ((DEBUG_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
- DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
- if (Action == ACTION_RETRY_COMMAND_LATER) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
- if (SectorCount <= 1) {
- //
- // Jump out if the operation still fails with one sector transfer length.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // Try again with half length if the sense data shows we need to retry.
- //
- SectorCount >>= 1;
- *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
- goto BackOff;
- } else {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- }
- return ReturnStatus;
- }
- /**
- Submit Read(16) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice
- @param NeedRetry The pointer of flag indicates if needs retry if error happens
- @param Timeout The time to complete the command
- @param DataBuffer The buffer to fill with the read out data
- @param DataLength The length of buffer
- @param StartLba The start logic block address
- @param SectorCount The number of blocks to read
- @return EFI_STATUS is returned by calling ScsiRead16Command().
- **/
- EFI_STATUS
- ScsiDiskRead16 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- IN UINT64 Timeout,
- OUT UINT8 *DataBuffer,
- IN OUT UINT32 *DataLength,
- IN UINT64 StartLba,
- IN UINT32 SectorCount
- )
- {
- UINT8 SenseDataLength;
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- UINTN Action;
- //
- // Implement a backoff algorithm to resolve some compatibility issues that
- // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
- // big data in a single operation.
- // This algorithm will at first try to execute original request. If the request fails
- // with media error sense data or else, it will reduce the transfer length to half and
- // try again till the operation succeeds or fails with one sector transfer length.
- //
- BackOff:
- *NeedRetry = FALSE;
- Action = ACTION_NO_ACTION;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- ReturnStatus = ScsiRead16Command (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- DataBuffer,
- DataLength,
- StartLba,
- SectorCount
- );
- if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return ReturnStatus;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
- DEBUG ((DEBUG_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
- DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
- if (Action == ACTION_RETRY_COMMAND_LATER) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
- if (SectorCount <= 1) {
- //
- // Jump out if the operation still fails with one sector transfer length.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // Try again with half length if the sense data shows we need to retry.
- //
- SectorCount >>= 1;
- *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
- goto BackOff;
- } else {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- }
- return ReturnStatus;
- }
- /**
- Submit Write(16) Command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice
- @param NeedRetry The pointer of flag indicates if needs retry if error happens
- @param Timeout The time to complete the command
- @param DataBuffer The buffer to fill with the read out data
- @param DataLength The length of buffer
- @param StartLba The start logic block address
- @param SectorCount The number of blocks to write
- @return EFI_STATUS is returned by calling ScsiWrite16Command().
- **/
- EFI_STATUS
- ScsiDiskWrite16 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- OUT BOOLEAN *NeedRetry,
- IN UINT64 Timeout,
- IN UINT8 *DataBuffer,
- IN OUT UINT32 *DataLength,
- IN UINT64 StartLba,
- IN UINT32 SectorCount
- )
- {
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
- UINT8 SenseDataLength;
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- UINTN Action;
- //
- // Implement a backoff algorithm to resolve some compatibility issues that
- // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
- // big data in a single operation.
- // This algorithm will at first try to execute original request. If the request fails
- // with media error sense data or else, it will reduce the transfer length to half and
- // try again till the operation succeeds or fails with one sector transfer length.
- //
- BackOff:
- *NeedRetry = FALSE;
- Action = ACTION_NO_ACTION;
- SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
- ReturnStatus = ScsiWrite16Command (
- ScsiDiskDevice->ScsiIo,
- Timeout,
- ScsiDiskDevice->SenseData,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- DataBuffer,
- DataLength,
- StartLba,
- SectorCount
- );
- if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
- *NeedRetry = FALSE;
- return ReturnStatus;
- }
- //
- // go ahead to check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- Status = CheckTargetStatus (TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Status == EFI_DEVICE_ERROR) {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
- DEBUG ((DEBUG_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
- DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
- if (Action == ACTION_RETRY_COMMAND_LATER) {
- *NeedRetry = TRUE;
- return EFI_DEVICE_ERROR;
- } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
- if (SectorCount <= 1) {
- //
- // Jump out if the operation still fails with one sector transfer length.
- //
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- //
- // Try again with half length if the sense data shows we need to retry.
- //
- SectorCount >>= 1;
- *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
- goto BackOff;
- } else {
- *NeedRetry = FALSE;
- return EFI_DEVICE_ERROR;
- }
- }
- return ReturnStatus;
- }
- /**
- Internal helper notify function in which determine whether retry of a SCSI
- Read/Write command is needed and signal the event passed from Block I/O(2) if
- the SCSI I/O operation completes.
- @param Event The instance of EFI_EVENT.
- @param Context The parameter passed in.
- **/
- VOID
- EFIAPI
- ScsiDiskNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- EFI_STATUS Status;
- SCSI_ASYNC_RW_REQUEST *Request;
- SCSI_DISK_DEV *ScsiDiskDevice;
- EFI_BLOCK_IO2_TOKEN *Token;
- UINTN Action;
- UINT32 OldDataLength;
- UINT32 OldSectorCount;
- UINT8 MaxRetry;
- gBS->CloseEvent (Event);
- Request = (SCSI_ASYNC_RW_REQUEST *)Context;
- ScsiDiskDevice = Request->ScsiDiskDevice;
- Token = Request->BlkIo2Req->Token;
- OldDataLength = Request->DataLength;
- OldSectorCount = Request->SectorCount;
- MaxRetry = 2;
- //
- // If previous sub-tasks already fails, no need to process this sub-task.
- //
- if (Token->TransactionStatus != EFI_SUCCESS) {
- goto Exit;
- }
- //
- // Check HostAdapterStatus and TargetStatus
- // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
- //
- Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
- if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
- if (++Request->TimesRetry > MaxRetry) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- } else {
- goto Retry;
- }
- } else if (Status == EFI_DEVICE_ERROR) {
- //
- // reset the scsi channel
- //
- ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- Status = CheckTargetStatus (Request->TargetStatus);
- if (Status == EFI_NOT_READY) {
- //
- // reset the scsi device
- //
- ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
- if (++Request->TimesRetry > MaxRetry) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- } else {
- goto Retry;
- }
- } else if (Status == EFI_DEVICE_ERROR) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
- DEBUG ((DEBUG_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
- DetectMediaParsingSenseKeys (
- ScsiDiskDevice,
- Request->SenseData,
- Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
- &Action
- );
- if (Action == ACTION_RETRY_COMMAND_LATER) {
- if (++Request->TimesRetry > MaxRetry) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- } else {
- goto Retry;
- }
- } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
- if (Request->SectorCount <= 1) {
- //
- // Jump out if the operation still fails with one sector transfer
- // length.
- //
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- //
- // Try again with two half length request if the sense data shows we need
- // to retry.
- //
- Request->SectorCount >>= 1;
- Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
- Request->TimesRetry = 0;
- goto Retry;
- } else {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- }
- //
- // This sub-task succeeds, no need to retry.
- //
- goto Exit;
- Retry:
- if (Request->InBuffer != NULL) {
- //
- // SCSI read command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncRead10 (
- ScsiDiskDevice,
- Request->Timeout,
- Request->TimesRetry,
- Request->InBuffer,
- Request->DataLength,
- (UINT32)Request->StartLba,
- Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncRead16 (
- ScsiDiskDevice,
- Request->Timeout,
- Request->TimesRetry,
- Request->InBuffer,
- Request->DataLength,
- Request->StartLba,
- Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- } else if (OldSectorCount != Request->SectorCount) {
- //
- // Original sub-task will be split into two new sub-tasks with smaller
- // DataLength
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncRead10 (
- ScsiDiskDevice,
- Request->Timeout,
- 0,
- Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
- OldDataLength - Request->DataLength,
- (UINT32)Request->StartLba + Request->SectorCount,
- OldSectorCount - Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncRead16 (
- ScsiDiskDevice,
- Request->Timeout,
- 0,
- Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
- OldDataLength - Request->DataLength,
- Request->StartLba + Request->SectorCount,
- OldSectorCount - Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- }
- } else {
- //
- // SCSI write command
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncWrite10 (
- ScsiDiskDevice,
- Request->Timeout,
- Request->TimesRetry,
- Request->OutBuffer,
- Request->DataLength,
- (UINT32)Request->StartLba,
- Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncWrite16 (
- ScsiDiskDevice,
- Request->Timeout,
- Request->TimesRetry,
- Request->OutBuffer,
- Request->DataLength,
- Request->StartLba,
- Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- } else if (OldSectorCount != Request->SectorCount) {
- //
- // Original sub-task will be split into two new sub-tasks with smaller
- // DataLength
- //
- if (!ScsiDiskDevice->Cdb16Byte) {
- Status = ScsiDiskAsyncWrite10 (
- ScsiDiskDevice,
- Request->Timeout,
- 0,
- Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
- OldDataLength - Request->DataLength,
- (UINT32)Request->StartLba + Request->SectorCount,
- OldSectorCount - Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- } else {
- Status = ScsiDiskAsyncWrite16 (
- ScsiDiskDevice,
- Request->Timeout,
- 0,
- Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
- OldDataLength - Request->DataLength,
- Request->StartLba + Request->SectorCount,
- OldSectorCount - Request->SectorCount,
- Request->BlkIo2Req,
- Token
- );
- }
- if (EFI_ERROR (Status)) {
- Token->TransactionStatus = EFI_DEVICE_ERROR;
- goto Exit;
- }
- }
- }
- Exit:
- RemoveEntryList (&Request->Link);
- if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
- (Request->BlkIo2Req->LastScsiRW))
- {
- //
- // The last SCSI R/W command of a BlockIo2 request completes
- //
- RemoveEntryList (&Request->BlkIo2Req->Link);
- FreePool (Request->BlkIo2Req); // Should be freed only once
- gBS->SignalEvent (Token->Event);
- }
- FreePool (Request->SenseData);
- FreePool (Request);
- }
- /**
- Submit Async Read(10) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice.
- @param Timeout The time to complete the command.
- @param TimesRetry The number of times the command has been retried.
- @param DataBuffer The buffer to fill with the read out data.
- @param DataLength The length of buffer.
- @param StartLba The start logic block address.
- @param SectorCount The number of blocks to read.
- @param BlkIo2Req The upstream BlockIo2 request.
- @param Token The pointer to the token associated with the
- non-blocking read request.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- @return others Status returned by calling
- ScsiRead10CommandEx().
- **/
- EFI_STATUS
- ScsiDiskAsyncRead10 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINT64 Timeout,
- IN UINT8 TimesRetry,
- OUT UINT8 *DataBuffer,
- IN UINT32 DataLength,
- IN UINT32 StartLba,
- IN UINT32 SectorCount,
- IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- EFI_STATUS Status;
- SCSI_ASYNC_RW_REQUEST *Request;
- EFI_EVENT AsyncIoEvent;
- EFI_TPL OldTpl;
- AsyncIoEvent = NULL;
- Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
- if (Request == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
- gBS->RestoreTPL (OldTpl);
- Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
- Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
- if (Request->SenseData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ErrorExit;
- }
- Request->ScsiDiskDevice = ScsiDiskDevice;
- Request->Timeout = Timeout;
- Request->TimesRetry = TimesRetry;
- Request->InBuffer = DataBuffer;
- Request->DataLength = DataLength;
- Request->StartLba = StartLba;
- Request->SectorCount = SectorCount;
- Request->BlkIo2Req = BlkIo2Req;
- //
- // Create Event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- ScsiDiskNotify,
- Request,
- &AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- Status = ScsiRead10CommandEx (
- ScsiDiskDevice->ScsiIo,
- Request->Timeout,
- Request->SenseData,
- &Request->SenseDataLength,
- &Request->HostAdapterStatus,
- &Request->TargetStatus,
- Request->InBuffer,
- &Request->DataLength,
- (UINT32)Request->StartLba,
- Request->SectorCount,
- AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- return EFI_SUCCESS;
- ErrorExit:
- if (AsyncIoEvent != NULL) {
- gBS->CloseEvent (AsyncIoEvent);
- }
- if (Request != NULL) {
- if (Request->SenseData != NULL) {
- FreePool (Request->SenseData);
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&Request->Link);
- gBS->RestoreTPL (OldTpl);
- FreePool (Request);
- }
- return Status;
- }
- /**
- Submit Async Write(10) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice.
- @param Timeout The time to complete the command.
- @param TimesRetry The number of times the command has been retried.
- @param DataBuffer The buffer contains the data to write.
- @param DataLength The length of buffer.
- @param StartLba The start logic block address.
- @param SectorCount The number of blocks to write.
- @param BlkIo2Req The upstream BlockIo2 request.
- @param Token The pointer to the token associated with the
- non-blocking read request.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- @return others Status returned by calling
- ScsiWrite10CommandEx().
- **/
- EFI_STATUS
- ScsiDiskAsyncWrite10 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINT64 Timeout,
- IN UINT8 TimesRetry,
- IN UINT8 *DataBuffer,
- IN UINT32 DataLength,
- IN UINT32 StartLba,
- IN UINT32 SectorCount,
- IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- EFI_STATUS Status;
- SCSI_ASYNC_RW_REQUEST *Request;
- EFI_EVENT AsyncIoEvent;
- EFI_TPL OldTpl;
- AsyncIoEvent = NULL;
- Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
- if (Request == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
- gBS->RestoreTPL (OldTpl);
- Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
- Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
- if (Request->SenseData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ErrorExit;
- }
- Request->ScsiDiskDevice = ScsiDiskDevice;
- Request->Timeout = Timeout;
- Request->TimesRetry = TimesRetry;
- Request->OutBuffer = DataBuffer;
- Request->DataLength = DataLength;
- Request->StartLba = StartLba;
- Request->SectorCount = SectorCount;
- Request->BlkIo2Req = BlkIo2Req;
- //
- // Create Event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- ScsiDiskNotify,
- Request,
- &AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- Status = ScsiWrite10CommandEx (
- ScsiDiskDevice->ScsiIo,
- Request->Timeout,
- Request->SenseData,
- &Request->SenseDataLength,
- &Request->HostAdapterStatus,
- &Request->TargetStatus,
- Request->OutBuffer,
- &Request->DataLength,
- (UINT32)Request->StartLba,
- Request->SectorCount,
- AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- return EFI_SUCCESS;
- ErrorExit:
- if (AsyncIoEvent != NULL) {
- gBS->CloseEvent (AsyncIoEvent);
- }
- if (Request != NULL) {
- if (Request->SenseData != NULL) {
- FreePool (Request->SenseData);
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&Request->Link);
- gBS->RestoreTPL (OldTpl);
- FreePool (Request);
- }
- return Status;
- }
- /**
- Submit Async Read(16) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice.
- @param Timeout The time to complete the command.
- @param TimesRetry The number of times the command has been retried.
- @param DataBuffer The buffer to fill with the read out data.
- @param DataLength The length of buffer.
- @param StartLba The start logic block address.
- @param SectorCount The number of blocks to read.
- @param BlkIo2Req The upstream BlockIo2 request.
- @param Token The pointer to the token associated with the
- non-blocking read request.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- @return others Status returned by calling
- ScsiRead16CommandEx().
- **/
- EFI_STATUS
- ScsiDiskAsyncRead16 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINT64 Timeout,
- IN UINT8 TimesRetry,
- OUT UINT8 *DataBuffer,
- IN UINT32 DataLength,
- IN UINT64 StartLba,
- IN UINT32 SectorCount,
- IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- EFI_STATUS Status;
- SCSI_ASYNC_RW_REQUEST *Request;
- EFI_EVENT AsyncIoEvent;
- EFI_TPL OldTpl;
- AsyncIoEvent = NULL;
- Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
- if (Request == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
- gBS->RestoreTPL (OldTpl);
- Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
- Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
- if (Request->SenseData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ErrorExit;
- }
- Request->ScsiDiskDevice = ScsiDiskDevice;
- Request->Timeout = Timeout;
- Request->TimesRetry = TimesRetry;
- Request->InBuffer = DataBuffer;
- Request->DataLength = DataLength;
- Request->StartLba = StartLba;
- Request->SectorCount = SectorCount;
- Request->BlkIo2Req = BlkIo2Req;
- //
- // Create Event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- ScsiDiskNotify,
- Request,
- &AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- Status = ScsiRead16CommandEx (
- ScsiDiskDevice->ScsiIo,
- Request->Timeout,
- Request->SenseData,
- &Request->SenseDataLength,
- &Request->HostAdapterStatus,
- &Request->TargetStatus,
- Request->InBuffer,
- &Request->DataLength,
- Request->StartLba,
- Request->SectorCount,
- AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- return EFI_SUCCESS;
- ErrorExit:
- if (AsyncIoEvent != NULL) {
- gBS->CloseEvent (AsyncIoEvent);
- }
- if (Request != NULL) {
- if (Request->SenseData != NULL) {
- FreePool (Request->SenseData);
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&Request->Link);
- gBS->RestoreTPL (OldTpl);
- FreePool (Request);
- }
- return Status;
- }
- /**
- Submit Async Write(16) command.
- @param ScsiDiskDevice The pointer of ScsiDiskDevice.
- @param Timeout The time to complete the command.
- @param TimesRetry The number of times the command has been retried.
- @param DataBuffer The buffer contains the data to write.
- @param DataLength The length of buffer.
- @param StartLba The start logic block address.
- @param SectorCount The number of blocks to write.
- @param BlkIo2Req The upstream BlockIo2 request.
- @param Token The pointer to the token associated with the
- non-blocking read request.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
- lack of resources.
- @return others Status returned by calling
- ScsiWrite16CommandEx().
- **/
- EFI_STATUS
- ScsiDiskAsyncWrite16 (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN UINT64 Timeout,
- IN UINT8 TimesRetry,
- IN UINT8 *DataBuffer,
- IN UINT32 DataLength,
- IN UINT64 StartLba,
- IN UINT32 SectorCount,
- IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,
- IN EFI_BLOCK_IO2_TOKEN *Token
- )
- {
- EFI_STATUS Status;
- SCSI_ASYNC_RW_REQUEST *Request;
- EFI_EVENT AsyncIoEvent;
- EFI_TPL OldTpl;
- AsyncIoEvent = NULL;
- Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
- if (Request == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
- gBS->RestoreTPL (OldTpl);
- Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));
- Request->SenseData = AllocateZeroPool (Request->SenseDataLength);
- if (Request->SenseData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ErrorExit;
- }
- Request->ScsiDiskDevice = ScsiDiskDevice;
- Request->Timeout = Timeout;
- Request->TimesRetry = TimesRetry;
- Request->OutBuffer = DataBuffer;
- Request->DataLength = DataLength;
- Request->StartLba = StartLba;
- Request->SectorCount = SectorCount;
- Request->BlkIo2Req = BlkIo2Req;
- //
- // Create Event
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- ScsiDiskNotify,
- Request,
- &AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- Status = ScsiWrite16CommandEx (
- ScsiDiskDevice->ScsiIo,
- Request->Timeout,
- Request->SenseData,
- &Request->SenseDataLength,
- &Request->HostAdapterStatus,
- &Request->TargetStatus,
- Request->OutBuffer,
- &Request->DataLength,
- Request->StartLba,
- Request->SectorCount,
- AsyncIoEvent
- );
- if (EFI_ERROR (Status)) {
- goto ErrorExit;
- }
- return EFI_SUCCESS;
- ErrorExit:
- if (AsyncIoEvent != NULL) {
- gBS->CloseEvent (AsyncIoEvent);
- }
- if (Request != NULL) {
- if (Request->SenseData != NULL) {
- FreePool (Request->SenseData);
- }
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&Request->Link);
- gBS->RestoreTPL (OldTpl);
- FreePool (Request);
- }
- return Status;
- }
- /**
- Check sense key to find if media presents.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @retval TRUE NOT any media
- @retval FALSE Media presents
- **/
- BOOLEAN
- ScsiDiskIsNoMedia (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsNoMedia;
- IsNoMedia = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- //
- // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
- // Additional Sense Code is ASC_NO_MEDIA (0x3A)
- //
- if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
- (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA))
- {
- IsNoMedia = TRUE;
- }
- SensePtr++;
- }
- return IsNoMedia;
- }
- /**
- Parse sense key.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @retval TRUE Error
- @retval FALSE NOT error
- **/
- BOOLEAN
- ScsiDiskIsMediaError (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsError;
- IsError = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- switch (SensePtr->Sense_Key) {
- case EFI_SCSI_SK_MEDIUM_ERROR:
- //
- // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
- //
- switch (SensePtr->Addnl_Sense_Code) {
- //
- // fall through
- //
- case EFI_SCSI_ASC_MEDIA_ERR1:
- //
- // fall through
- //
- case EFI_SCSI_ASC_MEDIA_ERR2:
- //
- // fall through
- //
- case EFI_SCSI_ASC_MEDIA_ERR3:
- case EFI_SCSI_ASC_MEDIA_ERR4:
- IsError = TRUE;
- break;
- default:
- break;
- }
- break;
- case EFI_SCSI_SK_NOT_READY:
- //
- // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
- //
- switch (SensePtr->Addnl_Sense_Code) {
- //
- // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
- //
- case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
- IsError = TRUE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- SensePtr++;
- }
- return IsError;
- }
- /**
- Check sense key to find if hardware error happens.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @retval TRUE Hardware error exits.
- @retval FALSE NO error.
- **/
- BOOLEAN
- ScsiDiskIsHardwareError (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsError;
- IsError = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- //
- // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
- //
- if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
- IsError = TRUE;
- }
- SensePtr++;
- }
- return IsError;
- }
- /**
- Check sense key to find if media has changed.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @retval TRUE Media is changed.
- @retval FALSE Media is NOT changed.
- **/
- BOOLEAN
- ScsiDiskIsMediaChange (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsMediaChanged;
- IsMediaChanged = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- //
- // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
- // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
- //
- if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
- (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE))
- {
- IsMediaChanged = TRUE;
- }
- SensePtr++;
- }
- return IsMediaChanged;
- }
- /**
- Check sense key to find if reset happens.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @retval TRUE It is reset before.
- @retval FALSE It is NOT reset before.
- **/
- BOOLEAN
- ScsiDiskIsResetBefore (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsResetBefore;
- IsResetBefore = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- //
- // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
- // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
- //
- if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
- (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET))
- {
- IsResetBefore = TRUE;
- }
- SensePtr++;
- }
- return IsResetBefore;
- }
- /**
- Check sense key to find if the drive is ready.
- @param SenseData The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts The number of sense key
- @param RetryLater The flag means if need a retry
- @retval TRUE Drive is ready.
- @retval FALSE Drive is NOT ready.
- **/
- BOOLEAN
- ScsiDiskIsDriveReady (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts,
- OUT BOOLEAN *RetryLater
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN IsReady;
- IsReady = TRUE;
- *RetryLater = FALSE;
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- switch (SensePtr->Sense_Key) {
- case EFI_SCSI_SK_NOT_READY:
- //
- // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
- //
- switch (SensePtr->Addnl_Sense_Code) {
- case EFI_SCSI_ASC_NOT_READY:
- //
- // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
- //
- switch (SensePtr->Addnl_Sense_Code_Qualifier) {
- case EFI_SCSI_ASCQ_IN_PROGRESS:
- //
- // Additional Sense Code Qualifier is
- // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
- //
- IsReady = FALSE;
- *RetryLater = TRUE;
- break;
- default:
- IsReady = FALSE;
- *RetryLater = FALSE;
- break;
- }
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- SensePtr++;
- }
- return IsReady;
- }
- /**
- Check sense key to find if it has sense key.
- @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
- @param SenseCounts - The number of sense key
- @retval TRUE It has sense key.
- @retval FALSE It has NOT any sense key.
- **/
- BOOLEAN
- ScsiDiskHaveSenseKey (
- IN EFI_SCSI_SENSE_DATA *SenseData,
- IN UINTN SenseCounts
- )
- {
- EFI_SCSI_SENSE_DATA *SensePtr;
- UINTN Index;
- BOOLEAN HaveSenseKey;
- if (SenseCounts == 0) {
- HaveSenseKey = FALSE;
- } else {
- HaveSenseKey = TRUE;
- }
- SensePtr = SenseData;
- for (Index = 0; Index < SenseCounts; Index++) {
- //
- // Sense Key is SK_NO_SENSE (0x0)
- //
- if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
- (Index == 0))
- {
- HaveSenseKey = FALSE;
- }
- SensePtr++;
- }
- return HaveSenseKey;
- }
- /**
- Release resource about disk device.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- **/
- VOID
- ReleaseScsiDiskDeviceResources (
- IN SCSI_DISK_DEV *ScsiDiskDevice
- )
- {
- if (ScsiDiskDevice == NULL) {
- return;
- }
- if (ScsiDiskDevice->SenseData != NULL) {
- FreePool (ScsiDiskDevice->SenseData);
- ScsiDiskDevice->SenseData = NULL;
- }
- if (ScsiDiskDevice->ControllerNameTable != NULL) {
- FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
- ScsiDiskDevice->ControllerNameTable = NULL;
- }
- FreePool (ScsiDiskDevice);
- ScsiDiskDevice = NULL;
- }
- /**
- Determine if Block Io & Block Io2 should be produced.
- @param ChildHandle Child Handle to retrieve Parent information.
- @retval TRUE Should produce Block Io & Block Io2.
- @retval FALSE Should not produce Block Io & Block Io2.
- **/
- BOOLEAN
- DetermineInstallBlockIo (
- IN EFI_HANDLE ChildHandle
- )
- {
- EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
- //
- // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
- // check its attribute, logic or physical.
- //
- ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
- if (ExtScsiPassThru != NULL) {
- if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
- return TRUE;
- }
- }
- //
- // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
- // check its attribute, logic or physical.
- //
- ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
- if (ScsiPassThru != NULL) {
- if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- Search protocol database and check to see if the protocol
- specified by ProtocolGuid is present on a ControllerHandle and opened by
- ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
- If the ControllerHandle is found, then the protocol specified by ProtocolGuid
- will be opened on it.
- @param ProtocolGuid ProtocolGuid pointer.
- @param ChildHandle Child Handle to retrieve Parent information.
- **/
- VOID *
- EFIAPI
- GetParentProtocol (
- IN EFI_GUID *ProtocolGuid,
- IN EFI_HANDLE ChildHandle
- )
- {
- UINTN Index;
- UINTN HandleCount;
- VOID *Interface;
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- //
- // Retrieve the list of all handles from the handle database
- //
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- ProtocolGuid,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
- //
- // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
- //
- for (Index = 0; Index < HandleCount; Index++) {
- Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
- if (!EFI_ERROR (Status)) {
- Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
- if (!EFI_ERROR (Status)) {
- gBS->FreePool (HandleBuffer);
- return Interface;
- }
- }
- }
- gBS->FreePool (HandleBuffer);
- return NULL;
- }
- /**
- Determine if EFI Erase Block Protocol should be produced.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
- @param ChildHandle Handle of device.
- @retval TRUE Should produce EFI Erase Block Protocol.
- @retval FALSE Should not produce EFI Erase Block Protocol.
- **/
- BOOLEAN
- DetermineInstallEraseBlock (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN EFI_HANDLE ChildHandle
- )
- {
- UINT8 HostAdapterStatus;
- UINT8 TargetStatus;
- EFI_STATUS CommandStatus;
- EFI_STATUS Status;
- BOOLEAN UfsDevice;
- BOOLEAN RetVal;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- UINT8 SenseDataLength;
- UINT32 DataLength16;
- EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
- UfsDevice = FALSE;
- RetVal = TRUE;
- CapacityData16 = NULL;
- //
- // UNMAP command is not supported by any of the UFS WLUNs.
- //
- if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {
- RetVal = FALSE;
- goto Done;
- }
- Status = gBS->HandleProtocol (
- ChildHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&DevicePathNode
- );
- //
- // Device Path protocol must be installed on the device handle.
- //
- ASSERT_EFI_ERROR (Status);
- while (!IsDevicePathEndType (DevicePathNode)) {
- //
- // For now, only support Erase Block Protocol on UFS devices.
- //
- if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
- (DevicePathNode->SubType == MSG_UFS_DP))
- {
- UfsDevice = TRUE;
- break;
- }
- DevicePathNode = NextDevicePathNode (DevicePathNode);
- }
- if (!UfsDevice) {
- RetVal = FALSE;
- goto Done;
- }
- //
- // Check whether the erase functionality is enabled on the UFS device.
- //
- CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- if (CapacityData16 == NULL) {
- RetVal = FALSE;
- goto Done;
- }
- SenseDataLength = 0;
- DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
- ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- CommandStatus = ScsiReadCapacity16Command (
- ScsiDiskDevice->ScsiIo,
- SCSI_DISK_TIMEOUT,
- NULL,
- &SenseDataLength,
- &HostAdapterStatus,
- &TargetStatus,
- (VOID *)CapacityData16,
- &DataLength16,
- FALSE
- );
- if (CommandStatus == EFI_SUCCESS) {
- //
- // Universal Flash Storage (UFS) Version 2.0
- // Section 11.3.9.2
- // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
- //
- if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||
- ((CapacityData16->LowestAlignLogic2 & BIT6) == 0))
- {
- DEBUG ((
- DEBUG_VERBOSE,
- "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
- CapacityData16->LowestAlignLogic2
- ));
- RetVal = FALSE;
- goto Done;
- }
- } else {
- DEBUG ((
- DEBUG_VERBOSE,
- "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
- CommandStatus
- ));
- RetVal = FALSE;
- goto Done;
- }
- //
- // Check whether the UFS device server implements the UNMAP command.
- //
- if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||
- (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0))
- {
- DEBUG ((
- DEBUG_VERBOSE,
- "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
- ));
- RetVal = FALSE;
- goto Done;
- }
- Done:
- if (CapacityData16 != NULL) {
- FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
- }
- return RetVal;
- }
- /**
- Determine if EFI Storage Security Command Protocol should be produced.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
- @param ChildHandle Handle of device.
- @retval TRUE Should produce EFI Storage Security Command Protocol.
- @retval FALSE Should not produce EFI Storage Security Command Protocol.
- **/
- BOOLEAN
- DetermineInstallStorageSecurity (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN EFI_HANDLE ChildHandle
- )
- {
- EFI_STATUS Status;
- UFS_DEVICE_PATH *UfsDevice;
- BOOLEAN RetVal;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- UfsDevice = NULL;
- RetVal = TRUE;
- Status = gBS->HandleProtocol (
- ChildHandle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&DevicePathNode
- );
- //
- // Device Path protocol must be installed on the device handle.
- //
- ASSERT_EFI_ERROR (Status);
- while (!IsDevicePathEndType (DevicePathNode)) {
- //
- // For now, only support Storage Security Command Protocol on UFS devices.
- //
- if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&
- (DevicePathNode->SubType == MSG_UFS_DP))
- {
- UfsDevice = (UFS_DEVICE_PATH *)DevicePathNode;
- break;
- }
- DevicePathNode = NextDevicePathNode (DevicePathNode);
- }
- if (UfsDevice == NULL) {
- RetVal = FALSE;
- goto Done;
- }
- if (UfsDevice->Lun != UFS_WLUN_RPMB) {
- RetVal = FALSE;
- }
- Done:
- return RetVal;
- }
- /**
- Provides inquiry information for the controller type.
- This function is used by the IDE bus driver to get inquiry data. Data format
- of Identify data is defined by the Interface GUID.
- @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
- @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
- @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
- @retval EFI_SUCCESS The command was accepted without any errors.
- @retval EFI_NOT_FOUND Device does not support this data class
- @retval EFI_DEVICE_ERROR Error reading InquiryData from device
- @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskInfoInquiry (
- IN EFI_DISK_INFO_PROTOCOL *This,
- IN OUT VOID *InquiryData,
- IN OUT UINT32 *InquiryDataSize
- )
- {
- EFI_STATUS Status;
- SCSI_DISK_DEV *ScsiDiskDevice;
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
- Status = EFI_BUFFER_TOO_SMALL;
- if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
- Status = EFI_SUCCESS;
- CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
- }
- *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
- return Status;
- }
- /**
- Provides identify information for the controller type.
- This function is used by the IDE bus driver to get identify data. Data format
- of Identify data is defined by the Interface GUID.
- @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
- instance.
- @param[in, out] IdentifyData Pointer to a buffer for the identify data.
- @param[in, out] IdentifyDataSize Pointer to the value for the identify data
- size.
- @retval EFI_SUCCESS The command was accepted without any errors.
- @retval EFI_NOT_FOUND Device does not support this data class
- @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
- @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskInfoIdentify (
- IN EFI_DISK_INFO_PROTOCOL *This,
- IN OUT VOID *IdentifyData,
- IN OUT UINT32 *IdentifyDataSize
- )
- {
- EFI_STATUS Status;
- SCSI_DISK_DEV *ScsiDiskDevice;
- if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
- //
- // Physical SCSI bus does not support this data class.
- //
- return EFI_NOT_FOUND;
- }
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
- Status = EFI_BUFFER_TOO_SMALL;
- if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
- Status = EFI_SUCCESS;
- CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
- }
- *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
- return Status;
- }
- /**
- Provides sense data information for the controller type.
- This function is used by the IDE bus driver to get sense data.
- Data format of Sense data is defined by the Interface GUID.
- @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
- @param[in, out] SenseData Pointer to the SenseData.
- @param[in, out] SenseDataSize Size of SenseData in bytes.
- @param[out] SenseDataNumber Pointer to the value for the sense data size.
- @retval EFI_SUCCESS The command was accepted without any errors.
- @retval EFI_NOT_FOUND Device does not support this data class.
- @retval EFI_DEVICE_ERROR Error reading SenseData from device.
- @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskInfoSenseData (
- IN EFI_DISK_INFO_PROTOCOL *This,
- IN OUT VOID *SenseData,
- IN OUT UINT32 *SenseDataSize,
- OUT UINT8 *SenseDataNumber
- )
- {
- return EFI_NOT_FOUND;
- }
- /**
- This function is used by the IDE bus driver to get controller information.
- @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
- @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
- @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
- @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
- @retval EFI_UNSUPPORTED This is not an IDE device.
- **/
- EFI_STATUS
- EFIAPI
- ScsiDiskInfoWhichIde (
- IN EFI_DISK_INFO_PROTOCOL *This,
- OUT UINT32 *IdeChannel,
- OUT UINT32 *IdeDevice
- )
- {
- SCSI_DISK_DEV *ScsiDiskDevice;
- if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
- //
- // This is not an IDE physical device.
- //
- return EFI_UNSUPPORTED;
- }
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);
- *IdeChannel = ScsiDiskDevice->Channel;
- *IdeDevice = ScsiDiskDevice->Device;
- return EFI_SUCCESS;
- }
- /**
- Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
- This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
- implement Identify() interface for DiskInfo protocol. The ATA command is sent
- via SCSI Request Packet.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
- @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
- @retval others Some error occurred during the identification that ATAPI device.
- **/
- EFI_STATUS
- AtapiIdentifyDevice (
- IN OUT SCSI_DISK_DEV *ScsiDiskDevice
- )
- {
- EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
- UINT8 Cdb[6];
- //
- // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
- //
- ZeroMem (&CommandPacket, sizeof (CommandPacket));
- ZeroMem (Cdb, sizeof (Cdb));
- Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
- CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
- CommandPacket.Cdb = Cdb;
- CommandPacket.CdbLength = (UINT8)sizeof (Cdb);
- CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
- CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
- return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
- }
- /**
- Initialize the installation of DiskInfo protocol.
- This function prepares for the installation of DiskInfo protocol on the child handle.
- By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
- detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
- to be IDE/AHCI interface GUID.
- @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
- @param ChildHandle Child handle to install DiskInfo protocol.
- **/
- VOID
- InitializeInstallDiskInfo (
- IN SCSI_DISK_DEV *ScsiDiskDevice,
- IN EFI_HANDLE ChildHandle
- )
- {
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;
- ATAPI_DEVICE_PATH *AtapiDevicePath;
- SATA_DEVICE_PATH *SataDevicePath;
- UINTN IdentifyRetry;
- Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathNode);
- //
- // Device Path protocol must be installed on the device handle.
- //
- ASSERT_EFI_ERROR (Status);
- //
- // Copy the DiskInfo protocol template.
- //
- CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
- while (!IsDevicePathEnd (DevicePathNode)) {
- ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
- if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
- (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
- (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
- (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP)))
- {
- IdentifyRetry = 3;
- do {
- //
- // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
- // with IDE/AHCI interface GUID.
- //
- Status = AtapiIdentifyDevice (ScsiDiskDevice);
- if (!EFI_ERROR (Status)) {
- if (DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) {
- //
- // We find the valid ATAPI device path
- //
- AtapiDevicePath = (ATAPI_DEVICE_PATH *)ChildDevicePathNode;
- ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
- ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
- //
- // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
- //
- CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
- } else {
- //
- // We find the valid SATA device path
- //
- SataDevicePath = (SATA_DEVICE_PATH *)ChildDevicePathNode;
- ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
- ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
- //
- // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
- //
- CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
- }
- return;
- }
- } while (--IdentifyRetry > 0);
- } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
- (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP))
- {
- CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
- break;
- }
- DevicePathNode = ChildDevicePathNode;
- }
- return;
- }
|