123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- usbmass.c
- Abstract:
- This module implements support for the USB Mass Storage driver.
- Author:
- Evan Green 27-Jan-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/intrface/disk.h>
- #include <minoca/usb/usb.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- #define CONVERT_BIG_ENDIAN_TO_CPU32(_Value) \
- ((((_Value) << 24) & 0xFF000000) | \
- (((_Value) << 8) & 0x00FF0000) | \
- (((_Value) >> 8) & 0x0000FF00) | \
- (((_Value) >> 24) & 0x000000FF))
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the allocation tag used throughout the mass storage driver.
- //
- #define USB_MASS_ALLOCATION_TAG 0x4D627355 // 'MbsU'
- //
- // Define the interface protocol numbers used by Mass Storage.
- //
- #define USB_MASS_BULK_ONLY_PROTOCOL 0x50
- //
- // Define the class-specific mass storage request codes.
- //
- #define USB_MASS_REQUEST_GET_MAX_LUN 0xFE
- #define USB_MASS_REQUEST_RESET_DEVICE 0xFF
- //
- // Define the maximum size of the buffer used for command headers and data
- // transfers.
- //
- #define USB_MASS_COMMAND_BUFFER_SIZE 0x200
- #define USB_MASS_MAX_DATA_TRANSFER (64 * 1024)
- //
- // Define the limit of how many times the status transfer can be sent when the
- // IN endpoint is stalling.
- //
- #define USB_MASS_STATUS_TRANSFER_ATTEMPT_LIMIT 2
- //
- // Define the number of times to retry an I/O request before giving up on the
- // IRP.
- //
- #define USB_MASS_IO_REQUEST_RETRY_COUNT 3
- //
- // Define the SCSI command block and command status signatures.
- //
- #define SCSI_COMMAND_BLOCK_SIGNATURE 0x43425355
- #define SCSI_COMMAND_STATUS_SIGNATURE 0x53425355
- //
- // Define SCSI result status codes returned in the command status wrapper.
- //
- #define SCSI_STATUS_SUCCESS 0x00
- #define SCSI_STATUS_FAILED 0x01
- #define SCSI_STATUS_PHASE_ERROR 0x02
- //
- // Define the number of bits the LUN is shifted in most SCSI commands.
- //
- #define SCSI_COMMAND_LUN_SHIFT 5
- //
- // Define the flags in the command block wrapper.
- //
- #define SCSI_COMMAND_BLOCK_FLAG_DATA_IN 0x80
- //
- // Define SCSI commands.
- //
- #define SCSI_COMMAND_TEST_UNIT_READY 0x00
- #define SCSI_COMMAND_REQUEST_SENSE 0x03
- #define SCSI_COMMAND_INQUIRY 0x12
- #define SCSI_COMMAND_MODE_SENSE_6 0x1A
- #define SCSI_COMMAND_READ_FORMAT_CAPACITIES 0x23
- #define SCSI_COMMAND_READ_CAPACITY 0x25
- #define SCSI_COMMAND_READ_10 0x28
- #define SCSI_COMMAND_WRITE_10 0x2A
- //
- // Define command sizes.
- //
- #define SCSI_COMMAND_TEST_UNIT_READY_SIZE 12
- #define SCSI_COMMAND_REQUEST_SENSE_SIZE 12
- #define SCSI_COMMAND_INQUIRY_SIZE 12
- #define SCSI_COMMAND_MODE_SENSE_6_SIZE 6
- #define SCSI_COMMAND_READ_FORMAT_CAPACITIES_SIZE 10
- #define SCSI_COMMAND_READ_CAPACITY_SIZE 10
- #define SCSI_COMMAND_READ_10_SIZE 12
- #define SCSI_COMMAND_WRITE_10_SIZE 12
- //
- // Define command data sizes.
- //
- #define SCSI_COMMAND_REQUEST_SENSE_DATA_SIZE 18
- #define SCSI_COMMAND_READ_FORMAT_CAPACITIES_DATA_SIZE 0xFC
- #define SCSI_COMMAND_MODE_SENSE_6_DATA_SIZE 0xC0
- //
- // Define USB Mass storage driver errors that can be reported back to the
- // system.
- //
- #define USB_MASS_ERROR_FAILED_RESET_RECOVERY 0x00000001
- //
- // Set this flag if the USB mass storage device has claimed an interface.
- //
- #define USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED 0x00000001
- //
- // Set this flag if the USB mass storage device owns the paging disk and has
- // prepared the USB core for handling paging.
- //
- #define USB_MASS_STORAGE_FLAG_PAGING_ENABLED 0x00000002
- //
- // Define the number of times a command is repeated.
- //
- #define USB_MASS_RETRY_COUNT 3
- //
- // Define the number of seconds to wait for the unit to become ready.
- //
- #define USB_MASS_UNIT_READY_TIMEOUT 30
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _USB_MASS_STORAGE_TYPE {
- UsbMassStorageInvalid,
- UsbMassStorageDevice,
- UsbMassStorageLogicalDisk
- } USB_MASS_STORAGE_TYPE, *PUSB_MASS_STORAGE_TYPE;
- /*++
- Structure Description:
- This structure defines the set of buffers and transfers required to send
- USB mass storage requests.
- Members:
- CommandBuffer - Stores a pointer to an I/O buffer used as scratch space
- for status and command transfers and small data transfers.
- StatusTransfer - Stores a pointer to the IN USB transfer used for SCSI
- command status results.
- CommandTransfer - Stores a pointer to the OUT USB transfer used for SCSI
- commands.
- DataInTransfer - Stores a pointer to the USB transfer used when a
- command needs to read additional data from the device.
- DataOutTransfer - Stores a pointer to the USB transfer used to write data
- out to the disk.
- --*/
- typedef struct _USB_MASS_STORAGE_TRANSFERS {
- PIO_BUFFER CommandBuffer;
- PUSB_TRANSFER StatusTransfer;
- PUSB_TRANSFER CommandTransfer;
- PUSB_TRANSFER DataInTransfer;
- PUSB_TRANSFER DataOutTransfer;
- } USB_MASS_STORAGE_TRANSFERS, *PUSB_MASS_STORAGE_TRANSFERS;
- /*++
- Structure Description:
- This structure stores the state necessary to complete polled I/O to a USB
- mass storage device. It is meant to be used at high run level during
- critical code paths (e.g. system failure).
- Members:
- IoTransfers - Stores a pointer to the set of transfers used to complete
- I/O requests in polled mode.
- ControlTransfer - Stores a pointer to a control transfer that can be used
- in polled mode.
- ResetRequired - Stores a boolean indicating if a reset is required on all
- endpoints before executing polled transfers.
- --*/
- typedef struct _USB_MASS_STORAGE_POLLED_IO_STATE {
- USB_MASS_STORAGE_TRANSFERS IoTransfers;
- PUSB_TRANSFER ControlTransfer;
- BOOL ResetRequired;
- } USB_MASS_STORAGE_POLLED_IO_STATE, *PUSB_MASS_STORAGE_POLLED_IO_STATE;
- /*++
- Structure Description:
- This structure stores context about a USB Mass storage device.
- Members:
- Type - Stores a tag used to differentiate devices from disks.
- ReferenceCount - Stores a reference count for the device.
- UsbCoreHandle - Stores the handle to the device as identified by the USB
- core library.
- Lock - Stores a pointer to a lock that synchronizes the LUNs' access to the
- device, and serializes transfers.
- LogicalDiskList - Stores the list of logical disks on this device.
- PolledIoState - Stores a pointer to an optional I/O state used for polled
- I/O communications with the USB mass storage device during critical
- code paths.
- LunCount - Stores the maximum number of LUNs on this device.
- InEndpoint - Stores the endpoint number for the bulk IN endpoint.
- OutEndpoint - Stores the endpointer number for the bulk OUT endpoint.
- InterfaceNumber - Stores the USB Mass Storage interface number that this
- driver instance is attached to.
- Flags - Stores a bitmask of flags for this device.
- See USB_MASS_STORAGE_FLAG_* for definitions.
- --*/
- typedef struct _USB_MASS_STORAGE_DEVICE {
- USB_MASS_STORAGE_TYPE Type;
- volatile ULONG ReferenceCount;
- HANDLE UsbCoreHandle;
- PQUEUED_LOCK Lock;
- LIST_ENTRY LogicalDiskList;
- volatile PUSB_MASS_STORAGE_POLLED_IO_STATE PolledIoState;
- UCHAR LunCount;
- UCHAR InEndpoint;
- UCHAR OutEndpoint;
- UCHAR InterfaceNumber;
- ULONG Flags;
- } USB_MASS_STORAGE_DEVICE, *PUSB_MASS_STORAGE_DEVICE;
- /*++
- Structure Description:
- This structure stores context about a USB Mass storage logical disk.
- Members:
- Type - Stores a tag used to differentiate devices from disks.
- ReferenceCount - Stores a reference count for the disk.
- ListEntry - Stores pointers to the next and previous logical disks in the
- device.
- OsDevice - Stores a pointer to the OS device.
- Transfers - Stores the default set of transfers used to communicate with
- the USB mass storage device.
- LunNumber - Stores this logical disk's LUN number (a SCSI term).
- Device - Stores a pointer back to the device that this logical disk lives
- on.
- IoRequestAttempts - Stores the number of attempts that have been made
- to complete the current I/O request.
- StatusTransferAttempts - Stores the number of attempts that have been made
- to receive the status transfer.
- Event - Stores a pointer to an event to wait for in the case of
- synchronous commands.
- Irp - Stores a pointer to the IRP that the disk is currently serving.
- Whether this is NULL or non-NULL also serves to tell the callback
- routine whether to signal the IRP or the event.
- BlockCount - Stores the maximum number of blocks in the device.
- BlockShift - Stores the number of bits to shift to convert from bytes to
- blocks. This means the block size must be a power of two.
- CurrentFragment - Stores the current fragment number in a long transfer.
- CurrentFragmentOffset - Stores the offset (in bytes) into the current
- fragment in a long transfer.
- CurrentBytesTransferred - Stores the number of bytes that have been
- tranferred on behalf of the current I/O IRP.
- Connected - Stores a boolean indicating the disk's connection status.
- DiskInterface - Stores the disk interface published for this disk.
- --*/
- typedef struct _USB_DISK {
- USB_MASS_STORAGE_TYPE Type;
- volatile ULONG ReferenceCount;
- LIST_ENTRY ListEntry;
- PDEVICE OsDevice;
- UCHAR LunNumber;
- PUSB_MASS_STORAGE_DEVICE Device;
- USB_MASS_STORAGE_TRANSFERS Transfers;
- ULONG IoRequestAttempts;
- ULONG StatusTransferAttempts;
- PKEVENT Event;
- PIRP Irp;
- ULONG BlockCount;
- ULONG BlockShift;
- UINTN CurrentFragment;
- UINTN CurrentFragmentOffset;
- UINTN CurrentBytesTransferred;
- BOOL Connected;
- DISK_INTERFACE DiskInterface;
- } USB_DISK, *PUSB_DISK;
- /*++
- Structure Description:
- This structure defines a SCSI Command Block Wrapper (CBW), which contains
- the command format used to communicate with disks.
- Members:
- Signature - Stores a magic constant value. Use SCSI_COMMAND_BLOCK_SIGNATURE.
- Tag - Stores a unique value used to identify this command among others. The
- tag value in the ending command status word will be set to this value to
- signify which command is being acknowledged. The hardware does not
- interpret this value other than to copy it into the CSW at the end.
- DataTransferLength - Store the number of bytes the host expects to transfer
- on the Bulk-In or Bulk-Out endpoint (as indicated by the direction bit)
- during the execution of this command. If this field is zero, the device
- and host shall transfer no data between the CBW and CSW, and the device
- shall ignore the value of the Direction bit in the flags.
- Flags - Stores pretty much just one flag, the direction of the transfer
- (in or out).
- LunNumber - Stores the Logical Unit Number (disk index) to which the
- command block is being sent.
- CommandLength - Stores the valid length of the Command portion in bytes. The
- only legcal values are 1 through 16.
- --*/
- typedef struct _SCSI_COMMAND_BLOCK {
- ULONG Signature;
- ULONG Tag;
- ULONG DataTransferLength;
- UCHAR Flags;
- UCHAR LunNumber;
- UCHAR CommandLength;
- UCHAR Command[16];
- } PACKED SCSI_COMMAND_BLOCK, *PSCSI_COMMAND_BLOCK;
- /*++
- Structure Description:
- This structure defines a SCSI Command Status Wrapper (CSW), which is sent
- by the disk to contain the ending status of the command just sent.
- Members:
- Signature - Stores a magic constant value. Use
- SCSI_COMMAND_STATUS_SIGNATURE.
- Tag - Stores the unique tag value supplied by the host when the command
- was issued. This allows the host to match up statuses with their
- corresponding commands
- DataResidue - Stores a value for Data-Out transfers that represents the
- difference between the amount of data expected as stated in the
- data transfer length and the actual amount of data processed by the
- device. For Data-In the device shall report the difference between the
- amount of data expected as stated in the data transfer length field of
- the command and the actual amount of relevant data sent by the device.
- This shall not exceed the value sent in the transfer length.
- Status - Stores the status code representing the result of the procedure.
- See SCSI_STATUS_* definitions.
- --*/
- typedef struct _SCSI_COMMAND_STATUS {
- ULONG Signature;
- ULONG Tag;
- ULONG DataResidue;
- UCHAR Status;
- } PACKED SCSI_COMMAND_STATUS, *PSCSI_COMMAND_STATUS;
- /*++
- Structure Description:
- This structure defines tHe result returned from the device of an INQUIRY
- command for page 0.
- Members:
- PeripheralDeviceType - Stores the device currently connected to the logical
- unit.
- RemovableFlag - Stores a flag indicating if the device is removable (0x80
- if removable).
- VersionInformation - Stores the ISO, ECMA, and ANSI versions.
- ResponseDataFormat - Stores the response data format.
- AdditionalLength - Stores 31, the number of additional bytes in the
- information.
- Reserved - Stores reserved fields that should be set to 0.
- VendorInformation - Stores the vendor ID string.
- ProductInformation - Stores the product ID string.
- ProductRevision - Stores the product revision string, which should be in an
- "n.nn" type format.
- VendorData - Stores the first byte of the vendor-specific data. Disks like
- to transmit at least 36 bytes, and get fussy when they can't.
- --*/
- typedef struct _SCSI_INQUIRY_PAGE0 {
- UCHAR PeripheralDeviceType;
- UCHAR RemovableFlag;
- UCHAR VersionInformation;
- UCHAR ResponseDataFormat;
- UCHAR AdditionalLength;
- UCHAR Reserved[2];
- UCHAR VendorInformation[8];
- UCHAR ProductInformation[16];
- UCHAR ProductRevision[4];
- UCHAR VendorData;
- } PACKED SCSI_INQUIRY_PAGE0, *PSCSI_INQUIRY_PAGE0;
- /*++
- Structure Description:
- This structure defines tje result returned from the device of a READ
- FORMAT CAPACITIES command.
- Members:
- Reserved - Stores three unused bytes.
- CapacityListLength - Stores the size of the remaining structure (not
- counting this byte). This value should be at least 8 to contain the
- rest of this structure.
- BlockCount - Stores the number of blocks on the device.
- DescriptorCode - Stores whether this descriptor defines the maximum
- formattable capacity for this cartridge, the current media capacity, or
- the maximum formattable capacity for any cartridge.
- BlockLength - Stores the length of one block, in bytes. This value is
- commonly 512.
- --*/
- typedef struct _SCSI_FORMAT_CAPACITIES {
- UCHAR Reserved[3];
- UCHAR CapacityListLength;
- ULONG BlockCount;
- UCHAR DescriptorCode;
- ULONG BlockLength;
- } PACKED SCSI_FORMAT_CAPACITIES, *PSCSI_FORMAT_CAPACITIES;
- /*++
- Structure Description:
- This structure defines tje result returned from the device of a READ
- CAPACITY command.
- Members:
- LastValidBlockAddress - Stores the last valid logical block address for
- media access commands.
- BlockLength - Stores the length of one block, in bytes. This value is
- commonly 512.
- --*/
- typedef struct _SCSI_CAPACITY {
- ULONG LastValidBlockAddress;
- ULONG BlockLength;
- } PACKED SCSI_CAPACITY, *PSCSI_CAPACITY;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- UsbMassAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- UsbMassDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- UsbMassDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- UsbMassDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- UsbMassDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- UsbMassDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- KSTATUS
- UsbMasspStartDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspEnumerateChildren (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- );
- KSTATUS
- UsbMasspEnablePaging (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspRemoveDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspDestroyDevice (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspDeviceAddReference (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspDeviceReleaseReference (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- KSTATUS
- UsbMasspSetUpUsbDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- );
- KSTATUS
- UsbMasspGetLunCount (
- PUSB_MASS_STORAGE_DEVICE Device,
- PUCHAR LunCount
- );
- KSTATUS
- UsbMasspCreateLogicalDisks (
- PUSB_MASS_STORAGE_DEVICE Device,
- ULONG DiskCount
- );
- VOID
- UsbMasspDestroyLogicalDisks (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- PUSB_MASS_STORAGE_POLLED_IO_STATE
- UsbMasspCreatePolledIoState (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- VOID
- UsbMasspDestroyPolledIoState (
- PUSB_MASS_STORAGE_POLLED_IO_STATE PolledIoState
- );
- KSTATUS
- UsbMasspCreateTransfers (
- PUSB_MASS_STORAGE_DEVICE Device,
- PUSB_MASS_STORAGE_TRANSFERS Transfers,
- PVOID UserData,
- PUSB_TRANSFER_CALLBACK CallbackRoutine
- );
- VOID
- UsbMasspDestroyTransfers (
- PUSB_MASS_STORAGE_TRANSFERS Transfers
- );
- KSTATUS
- UsbMasspStartDisk (
- PUSB_DISK Disk
- );
- VOID
- UsbMasspRemoveDisk (
- PUSB_DISK Disk
- );
- VOID
- UsbMasspDestroyDisk (
- PUSB_DISK Disk
- );
- VOID
- UsbMasspDiskAddReference (
- PUSB_DISK Disk
- );
- VOID
- UsbMasspDiskReleaseReference (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspSendInquiry (
- PUSB_DISK Disk,
- UCHAR Page,
- PVOID *ResultBuffer,
- PULONG ResultBufferSize
- );
- KSTATUS
- UsbMasspTestUnitReady (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspRequestSense (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspModeSense (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspReadFormatCapacities (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspReadCapacity (
- PUSB_DISK Disk
- );
- PVOID
- UsbMasspSetupCommand (
- PUSB_DISK Disk,
- ULONG Tag,
- ULONG DataLength,
- UCHAR CommandLength,
- BOOL DataIn,
- BOOL PolledIo,
- PVOID TransferVirtualAddress,
- PHYSICAL_ADDRESS TransferPhysicalAddress
- );
- KSTATUS
- UsbMasspSendCommand (
- PUSB_DISK Disk
- );
- VOID
- UsbMasspTransferCompletionCallback (
- PUSB_TRANSFER Transfer
- );
- KSTATUS
- UsbMasspEvaluateCommandStatus (
- PUSB_DISK Disk,
- BOOL PolledIo,
- BOOL DisableRecovery,
- PULONG BytesTransferred
- );
- KSTATUS
- UsbMasspSendNextIoRequest (
- PUSB_DISK Disk
- );
- KSTATUS
- UsbMasspResetRecovery (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- );
- KSTATUS
- UsbMasspReset (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- );
- KSTATUS
- UsbMasspClearHalts (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- );
- KSTATUS
- UsbMasspClearEndpoint (
- PUSB_MASS_STORAGE_DEVICE Device,
- UCHAR Endpoint,
- BOOL PolledIo
- );
- KSTATUS
- UsbMasspBlockIoInitialize (
- PVOID DiskToken
- );
- KSTATUS
- UsbMasspBlockIoRead (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- UsbMasspBlockIoWrite (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- UsbMasspPerformPolledIo (
- PIRP_READ_WRITE IrpReadWrite,
- PUSB_DISK Disk,
- BOOL Write
- );
- KSTATUS
- UsbMasspSendPolledIoCommand (
- PUSB_DISK Disk,
- PULONG BytesCompleted
- );
- KSTATUS
- UsbMasspResetForPolledIo (
- PUSB_MASS_STORAGE_DEVICE Device
- );
- KSTATUS
- UsbMasspSendPolledIoControlTransfer (
- PUSB_MASS_STORAGE_DEVICE Device,
- USB_TRANSFER_DIRECTION TransferDirection,
- PUSB_SETUP_PACKET SetupPacket
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER UsbMassDriver = NULL;
- UUID UsbMassDiskInterfaceUuid = UUID_DISK_INTERFACE;
- DISK_INTERFACE UsbMassDiskInterfaceTemplate = {
- DISK_INTERFACE_VERSION,
- NULL,
- 0,
- 0,
- UsbMasspBlockIoInitialize,
- NULL,
- UsbMasspBlockIoRead,
- UsbMasspBlockIoWrite
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the USB Mass Storage driver. It
- registers the other dispatch functions, and performs driver-wide
- initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- UsbMassDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = UsbMassAddDevice;
- FunctionTable.DispatchStateChange = UsbMassDispatchStateChange;
- FunctionTable.DispatchOpen = UsbMassDispatchOpen;
- FunctionTable.DispatchClose = UsbMassDispatchClose;
- FunctionTable.DispatchIo = UsbMassDispatchIo;
- FunctionTable.DispatchSystemControl = UsbMassDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- UsbMassAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a device is detected for which the USB Mass
- Storage driver acts as the function driver. The driver will attach itself
- to the stack.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- PUSB_MASS_STORAGE_DEVICE NewDevice;
- KSTATUS Status;
- //
- // Create the device context and attach to the device.
- //
- NewDevice = MmAllocateNonPagedPool(sizeof(USB_MASS_STORAGE_DEVICE),
- USB_MASS_ALLOCATION_TAG);
- if (NewDevice == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(NewDevice, sizeof(USB_MASS_STORAGE_DEVICE));
- NewDevice->Type = UsbMassStorageDevice;
- NewDevice->ReferenceCount = 1;
- NewDevice->UsbCoreHandle = INVALID_HANDLE;
- INITIALIZE_LIST_HEAD(&(NewDevice->LogicalDiskList));
- NewDevice->Lock = KeCreateQueuedLock();
- if (NewDevice->Lock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- //
- // Attempt to attach to the USB core.
- //
- Status = UsbDriverAttach(DeviceToken,
- UsbMassDriver,
- &(NewDevice->UsbCoreHandle));
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- ASSERT(NewDevice->UsbCoreHandle != INVALID_HANDLE);
- Status = IoAttachDriverToDevice(Driver, DeviceToken, NewDevice);
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (NewDevice != NULL) {
- //
- // Release the reference, closing the USB core handle and
- // destroying the device.
- //
- UsbMasspDeviceReleaseReference(NewDevice);
- }
- }
- return Status;
- }
- VOID
- UsbMassDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PUSB_MASS_STORAGE_DEVICE Device;
- PUSB_DISK Disk;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- Device = (PUSB_MASS_STORAGE_DEVICE)DeviceContext;
- if (Device->Type == UsbMassStorageDevice) {
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- if (Irp->Direction == IrpUp) {
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_SUCCESS);
- }
- break;
- case IrpMinorStartDevice:
- //
- // Attempt to fire the thing up if the bus has already started it.
- //
- if (Irp->Direction == IrpUp) {
- Status = UsbMasspStartDevice(Irp, Device);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- }
- }
- break;
- case IrpMinorQueryChildren:
- if (Irp->Direction == IrpUp) {
- UsbMasspEnumerateChildren(Irp, Device);
- }
- break;
- case IrpMinorRemoveDevice:
- if (Irp->Direction == IrpUp) {
- UsbMasspRemoveDevice(Irp, Device);
- }
- break;
- //
- // For all other IRPs, do nothing.
- //
- default:
- break;
- }
- } else {
- Disk = (PUSB_DISK)DeviceContext;
- ASSERT(Disk->Type == UsbMassStorageLogicalDisk);
- switch (Irp->MinorCode) {
- case IrpMinorStartDevice:
- if (Irp->Direction == IrpUp) {
- Status = UsbMasspStartDisk(Disk);
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- }
- break;
- case IrpMinorQueryResources:
- case IrpMinorQueryChildren:
- if (Irp->Direction == IrpUp) {
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_SUCCESS);
- }
- break;
- case IrpMinorRemoveDevice:
- if (Irp->Direction == IrpUp) {
- UsbMasspRemoveDisk(Disk);
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_SUCCESS);
- }
- break;
- default:
- break;
- }
- }
- return;
- }
- VOID
- UsbMassDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PUSB_DISK Disk;
- KSTATUS Status;
- Disk = (PUSB_DISK)DeviceContext;
- if (Disk->Type != UsbMassStorageLogicalDisk) {
- return;
- }
- ASSERT(Disk->Connected != FALSE);
- //
- // If this is an open for the paging device then enable paging on this
- // device.
- //
- if ((Irp->U.Open.OpenFlags & OPEN_FLAG_PAGING_DEVICE) != 0) {
- Status = UsbMasspEnablePaging(Disk->Device);
- if (!KSUCCESS(Status)) {
- goto DispatchOpenEnd;
- }
- }
- UsbMasspDiskAddReference(Disk);
- Irp->U.Open.DeviceContext = NULL;
- Status = STATUS_SUCCESS;
- DispatchOpenEnd:
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- return;
- }
- VOID
- UsbMassDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PUSB_DISK Disk;
- Disk = (PUSB_DISK)DeviceContext;
- if (Disk->Type != UsbMassStorageLogicalDisk) {
- return;
- }
- UsbMasspDiskReleaseReference(Disk);
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- UsbMassDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- BOOL CompleteIrp;
- PUSB_DISK Disk;
- PIO_BUFFER_FRAGMENT Fragment;
- UINTN FragmentIndex;
- UINTN FragmentOffset;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- ULONG IrpReadWriteFlags;
- BOOL LockHeld;
- BOOL ReadWriteIrpPrepared;
- KSTATUS Status;
- CompleteIrp = TRUE;
- Disk = (PUSB_DISK)DeviceContext;
- LockHeld = FALSE;
- ReadWriteIrpPrepared = FALSE;
- ASSERT(Disk->Type == UsbMassStorageLogicalDisk);
- //
- // Set the read/write flags for preparation. As USB mass storage does not
- // do DMA directly, nor does it do polled I/O, don't set either flag.
- //
- IrpReadWriteFlags = 0;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- //
- // If the IRP is on the way up, then clean up after the DMA as this IRP is
- // still sitting in the channel. An IRP going up is already complete.
- //
- if (Irp->Direction != IrpDown) {
- CompleteIrp = FALSE;
- ASSERT(Irp == Disk->Irp);
- Disk->Irp = NULL;
- KeReleaseQueuedLock(Disk->Device->Lock);
- Status = IoCompleteReadWriteIrp(&(Irp->U.ReadWrite), IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- IoUpdateIrpStatus(Irp, Status);
- }
- } else {
- ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
- //
- // Before acquiring the device's lock and starting the transfer,
- // prepare the I/O context for USB Mass Storage (i.e. it must use
- // physical addresses that are less than 4GB and be cache aligned).
- //
- Status = IoPrepareReadWriteIrp(&(Irp->U.ReadWrite),
- 1 << Disk->BlockShift,
- 0,
- MAX_ULONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- ReadWriteIrpPrepared = TRUE;
- IoBuffer = Irp->U.ReadWrite.IoBuffer;
- //
- // Map the I/O buffer.
- //
- // TODO: Make sure USB Mass does not need the I/O buffer mapped.
- //
- Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- //
- // Find the starting fragment based on the current offset.
- //
- IoBufferOffset = MmGetIoBufferCurrentOffset(IoBuffer);
- FragmentIndex = 0;
- FragmentOffset = 0;
- while (IoBufferOffset != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = &(IoBuffer->Fragment[FragmentIndex]);
- if (IoBufferOffset < Fragment->Size) {
- FragmentOffset = IoBufferOffset;
- break;
- }
- IoBufferOffset -= Fragment->Size;
- FragmentIndex += 1;
- }
- //
- // Lock the disk to serialize all I/O access to the device.
- //
- KeAcquireQueuedLock(Disk->Device->Lock);
- LockHeld = TRUE;
- if (Disk->Connected == FALSE) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto DispatchIoEnd;
- }
- //
- // Otherwise start the I/O on a connected device.
- //
- Disk->CurrentFragment = FragmentIndex;
- Disk->CurrentFragmentOffset = FragmentOffset;
- Disk->CurrentBytesTransferred = 0;
- Disk->Irp = Irp;
- ASSERT(Irp->U.ReadWrite.IoSizeInBytes != 0);
- ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoSizeInBytes,
- (1 << Disk->BlockShift)));
- ASSERT(IS_ALIGNED(Irp->U.ReadWrite.IoOffset, (1 << Disk->BlockShift)));
- //
- // Pend the IRP first so that the request can't complete in between
- // submitting it and marking it pended.
- //
- CompleteIrp = FALSE;
- IoPendIrp(UsbMassDriver, Irp);
- //
- // Fire the first I/O request off to the disk. If this fails, expect to
- // get called on the way up, as the IRP has already been pended. Thus,
- // act like the lock is not held and the context was not prepared.
- //
- Disk->IoRequestAttempts = 0;
- Status = UsbMasspSendNextIoRequest(Disk);
- if (!KSUCCESS(Status)) {
- CompleteIrp = TRUE;
- LockHeld = FALSE;
- ReadWriteIrpPrepared = FALSE;
- goto DispatchIoEnd;
- }
- }
- DispatchIoEnd:
- if (CompleteIrp != FALSE) {
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Disk->Device->Lock);
- }
- if (ReadWriteIrpPrepared != FALSE) {
- IoCompleteReadWriteIrp(&(Irp->U.ReadWrite), IrpReadWriteFlags);
- }
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- }
- return;
- }
- VOID
- UsbMassDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PVOID Context;
- PUSB_DISK Disk;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- ULONGLONG FileSize;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- //
- // Do nothing for non-logical disks.
- //
- Disk = (PUSB_DISK)DeviceContext;
- if (Disk->Type != UsbMassStorageLogicalDisk) {
- return;
- }
- //
- // System control IRPs should only be arriving if the disk is connected.
- //
- ASSERT(Disk->Connected != FALSE);
- //
- // Handle the IRP for logical disks.
- //
- Context = Irp->U.SystemControl.SystemContext;
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlLookup:
- Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
- Status = STATUS_PATH_NOT_FOUND;
- if (Lookup->Root != FALSE) {
- //
- // Enable opening of the root as a single file.
- //
- Properties = &(Lookup->Properties);
- Properties->FileId = 0;
- Properties->Type = IoObjectBlockDevice;
- Properties->HardLinkCount = 1;
- ASSERT(((1 << Disk->BlockShift) != 0) && (Disk->BlockCount != 0));
- Properties->BlockSize = 1 << Disk->BlockShift;
- Properties->BlockCount = Disk->BlockCount;
- FileSize = (ULONGLONG)Disk->BlockCount <<
- (ULONGLONG)Disk->BlockShift;
- WRITE_INT64_SYNC(&(Properties->FileSize), FileSize);
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- break;
- //
- // Writes to the disk's properties are not allowed. Fail if the data
- // has changed.
- //
- case IrpMinorSystemControlWriteFileProperties:
- FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
- Properties = FileOperation->FileProperties;
- READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
- FileSize = (ULONGLONG)Disk->BlockCount << (ULONGLONG)Disk->BlockShift;
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectBlockDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != (1 << Disk->BlockShift)) ||
- (Properties->BlockCount != Disk->BlockCount) ||
- (PropertiesFileSize != FileSize)) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- break;
- //
- // Do not support USB mass storage device truncation.
- //
- case IrpMinorSystemControlTruncate:
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- //
- // Gather and return device information.
- //
- case IrpMinorSystemControlDeviceInformation:
- break;
- case IrpMinorSystemControlSynchronize:
- IoCompleteIrp(UsbMassDriver, Irp, STATUS_SUCCESS);
- break;
- //
- // Ignore everything unrecognized.
- //
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- KSTATUS
- UsbMasspStartDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine starts up the USB Mass Storage device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this mass storage device.
- Return Value:
- Status code.
- --*/
- {
- UCHAR LunCount;
- KSTATUS Status;
- ASSERT(Device->Type == UsbMassStorageDevice);
- //
- // Claim the interface.
- //
- Status = UsbMasspSetUpUsbDevice(Irp, Device);
- if (!KSUCCESS(Status)) {
- goto StartDeviceEnd;
- }
- if (Device->LunCount == 0) {
- Status = UsbMasspGetLunCount(Device, &LunCount);
- if (!KSUCCESS(Status)) {
- goto StartDeviceEnd;
- }
- //
- // Fire up all those little disks.
- //
- Status = UsbMasspCreateLogicalDisks(Device, LunCount);
- if (!KSUCCESS(Status)) {
- goto StartDeviceEnd;
- }
- Device->LunCount = LunCount;
- }
- StartDeviceEnd:
- return Status;
- }
- KSTATUS
- UsbMasspEnablePaging (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine enables paging on the given USB mass storage device. It
- converts all transfers for all disks to paging device transfers, which USB
- core will handle separately from other non-critical transfers.
- Arguments:
- Device - Supplies a pointer to a USB mass storage device.
- Return Value:
- Status code.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PUSB_DISK Disk;
- BOOL LockHeld;
- KSTATUS Status;
- PUSB_MASS_STORAGE_TRANSFERS Transfers;
- LockHeld = FALSE;
- //
- // If the device has already been enabled for paging, then work here is
- // done.
- //
- if ((Device->Flags & USB_MASS_STORAGE_FLAG_PAGING_ENABLED) != 0) {
- return STATUS_SUCCESS;
- }
- //
- // Notify USB core that a paging device has arrived and that it would like
- // its transfers to be serviced on their own work queue.
- //
- Status = UsbInitializePagingDeviceTransfers();
- if (!KSUCCESS(Status)) {
- goto InitializePagingEnd;
- }
- //
- // Now acquire the device's lock to synchronize with transfer submissions
- // and try to convert this device's transfer to be paging transfers.
- //
- KeAcquireQueuedLock(Device->Lock);
- LockHeld = TRUE;
- if ((Device->Flags & USB_MASS_STORAGE_FLAG_PAGING_ENABLED) != 0) {
- Status = STATUS_SUCCESS;
- goto InitializePagingEnd;
- }
- //
- // Iterate over all transfers for all the disks, converting them to be
- // paging device transfers. Because all disks share the same device lock,
- // all disks need to start using the paging path, even if a disk is not
- // involved in paging.
- //
- CurrentEntry = Device->LogicalDiskList.Next;
- while (CurrentEntry != &(Device->LogicalDiskList)) {
- Disk = LIST_VALUE(CurrentEntry, USB_DISK, ListEntry);
- Transfers = &(Disk->Transfers);
- Transfers->CommandTransfer->Flags |= USB_TRANSFER_FLAG_PAGING_DEVICE;
- Transfers->StatusTransfer->Flags |= USB_TRANSFER_FLAG_PAGING_DEVICE;
- Transfers->DataInTransfer->Flags |= USB_TRANSFER_FLAG_PAGING_DEVICE;
- Transfers->DataOutTransfer->Flags |= USB_TRANSFER_FLAG_PAGING_DEVICE;
- CurrentEntry = CurrentEntry->Next;
- }
- Device->Flags |= USB_MASS_STORAGE_FLAG_PAGING_ENABLED;
- KeReleaseQueuedLock(Device->Lock);
- LockHeld = FALSE;
- Status = STATUS_SUCCESS;
- InitializePagingEnd:
- if (LockHeld != FALSE) {
- KeReleaseQueuedLock(Device->Lock);
- }
- return Status;
- }
- VOID
- UsbMasspEnumerateChildren (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine enumerates the USB Mass Storage device's children.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this mass storage device.
- Return Value:
- None.
- --*/
- {
- ULONG ChildCount;
- ULONG ChildIndex;
- PDEVICE *Children;
- PLIST_ENTRY CurrentEntry;
- PUSB_DISK Disk;
- KSTATUS Status;
- ASSERT(Device->Type == UsbMassStorageDevice);
- ChildCount = Device->LunCount;
- Children = NULL;
- if (Device->LunCount == 0) {
- Status = STATUS_SUCCESS;
- goto EnumerateChildrenEnd;
- }
- Children = MmAllocatePagedPool(sizeof(PDEVICE) * ChildCount,
- USB_MASS_ALLOCATION_TAG);
- if (Children == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto EnumerateChildrenEnd;
- }
- RtlZeroMemory(Children, sizeof(PDEVICE) * ChildCount);
- //
- // Loop through and add every disk.
- //
- ChildIndex = 0;
- CurrentEntry = Device->LogicalDiskList.Next;
- while (CurrentEntry != &(Device->LogicalDiskList)) {
- Disk = LIST_VALUE(CurrentEntry, USB_DISK, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Disk->OsDevice == NULL) {
- Status = IoCreateDevice(UsbMassDriver,
- Disk,
- Irp->Device,
- "UsbDisk",
- DISK_CLASS_ID,
- NULL,
- &(Disk->OsDevice));
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- }
- if (Disk->OsDevice != NULL) {
- Disk->Connected = TRUE;
- Children[ChildIndex] = Disk->OsDevice;
- ChildIndex += 1;
- }
- }
- ChildCount = ChildIndex;
- Status = STATUS_SUCCESS;
- EnumerateChildrenEnd:
- if (!KSUCCESS(Status)) {
- if (Children != NULL) {
- MmFreePagedPool(Children);
- Children = NULL;
- ChildCount = 0;
- }
- }
- ASSERT((Irp->U.QueryChildren.Children == NULL) &&
- (Irp->U.QueryChildren.ChildCount == 0));
- Irp->U.QueryChildren.Children = Children;
- Irp->U.QueryChildren.ChildCount = ChildCount;
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- return;
- }
- VOID
- UsbMasspRemoveDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine removes the USB Mass Storage device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this mass storage device.
- Return Value:
- None.
- --*/
- {
- ASSERT(Device->Type == UsbMassStorageDevice);
- //
- // Detach the device from USB core. This marks it as disconnected and
- // cancels all transfers associated with the device.
- //
- // N.B. Since all the logical disks have already received a remove IRP,
- // the transfers should be inactive already.
- //
- UsbDetachDevice(Device->UsbCoreHandle);
- //
- // The logical disk list for this device should be empty if the device
- // successfully completed enumeration. That is, all the logical disk
- // should have received a removal IRP that this driver handled, acting as
- // the bus driver. If it is not empty, then the device never made it to
- // enumeration, or one logical disk failed to enumerate, and the disks need
- // to be cleaned up.
- //
- UsbMasspDestroyLogicalDisks(Device);
- //
- // Release the interface used for the USB mass storage device.
- //
- if ((Device->Flags & USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED) != 0) {
- UsbReleaseInterface(Device->UsbCoreHandle, Device->InterfaceNumber);
- Device->Flags &= ~USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED;
- }
- //
- // Release the reference taken during device add. Logical disks may still
- // have references on the device and USB core.
- //
- UsbMasspDeviceReleaseReference(Device);
- return;
- }
- VOID
- UsbMasspDestroyDevice (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine destroys a USB mass storage device.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- //
- // The device should have already received the removal IRP or have never
- // made it off the ground before it gets destroyed, so assert that there
- // are no references, its logical disk list is empty and the interface is
- // not claimed.
- //
- ASSERT(Device->ReferenceCount == 0);
- ASSERT(LIST_EMPTY(&(Device->LogicalDiskList)) != FALSE);
- ASSERT((Device->Flags & USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED) == 0);
- //
- // Destroy the polled I/O state if it exists.
- //
- if (Device->PolledIoState != NULL) {
- UsbMasspDestroyPolledIoState(Device->PolledIoState);
- }
- //
- // Release the USB core handle. The USB core device does not get dropped
- // until all of its transfers are destroyed. As a result, this handle
- // remains open until the last logical disk reference is dropped, making it
- // pointless to put this close in the device removal routine.
- //
- UsbDeviceClose(Device->UsbCoreHandle);
- //
- // Destroy the lock if necessary.
- //
- if (Device->Lock != NULL) {
- ASSERT(KeIsQueuedLockHeld(Device->Lock) == FALSE);
- KeDestroyQueuedLock(Device->Lock);
- }
- //
- // Release the device itself.
- //
- MmFreeNonPagedPool(Device);
- return;
- }
- VOID
- UsbMasspDeviceAddReference (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine adds a reference to USB mass storage device.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- return;
- }
- VOID
- UsbMasspDeviceReleaseReference (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine releases a reference from the USB mass storage device.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- UsbMasspDestroyDevice(Device);
- }
- return;
- }
- KSTATUS
- UsbMasspSetUpUsbDevice (
- PIRP Irp,
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine claims the mass storage interface for the given device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to this mass storage device.
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION_DESCRIPTION Configuration;
- PLIST_ENTRY CurrentEntry;
- USB_TRANSFER_DIRECTION Direction;
- PUSB_ENDPOINT_DESCRIPTION Endpoint;
- UCHAR EndpointType;
- BOOL InEndpointFound;
- PUSB_INTERFACE_DESCRIPTION Interface;
- BOOL OutEndpointFound;
- KSTATUS Status;
- ASSERT(Device->Type == UsbMassStorageDevice);
- if ((Device->Flags & USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED) != 0) {
- Status = STATUS_SUCCESS;
- goto SetUpUsbDeviceEnd;
- }
- //
- // If the configuration isn't yet set, set the first one.
- //
- Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
- if (Configuration == NULL) {
- Status = UsbSetConfiguration(Device->UsbCoreHandle, 0, TRUE);
- if (!KSUCCESS(Status)) {
- goto SetUpUsbDeviceEnd;
- }
- Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
- ASSERT(Configuration != NULL);
- }
- //
- // Get and verify the interface.
- //
- Interface = UsbGetDesignatedInterface(Irp->Device, Device->UsbCoreHandle);
- if (Interface == NULL) {
- Status = STATUS_NO_INTERFACE;
- goto SetUpUsbDeviceEnd;
- }
- if (Interface->Descriptor.Class != UsbInterfaceClassMassStorage) {
- Status = STATUS_NO_INTERFACE;
- goto SetUpUsbDeviceEnd;
- }
- if (Interface->Descriptor.Protocol != USB_MASS_BULK_ONLY_PROTOCOL) {
- RtlDebugPrint("USB Mass Storage Error: Unsupported protocol 0x%x. Only "
- "the Bulk-Only protocol (0x50) is supported.\n");
- ASSERT(FALSE);
- Status = STATUS_NOT_SUPPORTED;
- goto SetUpUsbDeviceEnd;
- }
- //
- // Locate the IN and OUT bulk endpoints.
- //
- InEndpointFound = FALSE;
- OutEndpointFound = FALSE;
- CurrentEntry = Interface->EndpointListHead.Next;
- while (CurrentEntry != &(Interface->EndpointListHead)) {
- Endpoint = LIST_VALUE(CurrentEntry,
- USB_ENDPOINT_DESCRIPTION,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Deconstruct the components of the endpoint descriptor.
- //
- EndpointType = Endpoint->Descriptor.Attributes &
- USB_ENDPOINT_ATTRIBUTES_TYPE_MASK;
- if ((Endpoint->Descriptor.EndpointAddress &
- USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
- Direction = UsbTransferDirectionIn;
- } else {
- Direction = UsbTransferDirectionOut;
- }
- //
- // Look to match the endpoint up to one of the required ones.
- //
- if (EndpointType == USB_ENDPOINT_ATTRIBUTES_TYPE_BULK) {
- if ((InEndpointFound == FALSE) &&
- (Direction == UsbTransferDirectionIn)) {
- InEndpointFound = TRUE;
- Device->InEndpoint = Endpoint->Descriptor.EndpointAddress;
- } else if ((OutEndpointFound == FALSE) &&
- (Direction == UsbTransferDirectionOut)) {
- OutEndpointFound = TRUE;
- Device->OutEndpoint = Endpoint->Descriptor.EndpointAddress;
- }
- }
- if ((InEndpointFound != FALSE) && (OutEndpointFound != FALSE)) {
- break;
- }
- }
- if ((InEndpointFound == FALSE) || (OutEndpointFound == FALSE)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto SetUpUsbDeviceEnd;
- }
- //
- // Everything's all ready, claim the interface.
- //
- Status = UsbClaimInterface(Device->UsbCoreHandle,
- Interface->Descriptor.InterfaceNumber);
- if (!KSUCCESS(Status)) {
- goto SetUpUsbDeviceEnd;
- }
- Device->InterfaceNumber = Interface->Descriptor.InterfaceNumber;
- Device->Flags |= USB_MASS_STORAGE_FLAG_INTERFACE_CLAIMED;
- Status = STATUS_SUCCESS;
- SetUpUsbDeviceEnd:
- return Status;
- }
- KSTATUS
- UsbMasspGetLunCount (
- PUSB_MASS_STORAGE_DEVICE Device,
- PUCHAR LunCount
- )
- /*++
- Routine Description:
- This routine returns the maximum number of logical disks contained in this
- mass storage device.
- Arguments:
- Device - Supplies a pointer to this mass storage device.
- LunCount - Supplies a pointer where the number of devices will be
- returned on success.
- Return Value:
- Status code.
- --*/
- {
- ULONG Alignment;
- PIO_BUFFER IoBuffer;
- ULONG IoBufferFlags;
- ULONG MaxTransferLength;
- PUSB_SETUP_PACKET Setup;
- KSTATUS Status;
- PUSB_TRANSFER Transfer;
- PVOID TransferBuffer;
- ULONG TransferLength;
- Transfer = NULL;
- //
- // Create the I/O buffer that will be used for the transfer.
- //
- Alignment = MmGetIoBufferAlignment();
- TransferLength = sizeof(USB_SETUP_PACKET) + sizeof(UCHAR);
- MaxTransferLength = ALIGN_RANGE_UP(TransferLength, Alignment);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- IoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- Alignment,
- MaxTransferLength,
- IoBufferFlags);
- if (IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetMaxLunEnd;
- }
- ASSERT(IoBuffer->FragmentCount == 1);
- TransferBuffer = IoBuffer->Fragment[0].VirtualAddress;
- Setup = (PUSB_SETUP_PACKET)TransferBuffer;
- Setup->RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_CLASS |
- USB_SETUP_REQUEST_INTERFACE_RECIPIENT;
- Setup->Request = USB_MASS_REQUEST_GET_MAX_LUN;
- Setup->Value = 0;
- Setup->Index = Device->InterfaceNumber;
- Setup->Length = sizeof(UCHAR);
- //
- // Create a USB transfer.
- //
- Transfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- 0,
- MaxTransferLength,
- 0);
- if (Transfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto GetMaxLunEnd;
- }
- Transfer->Direction = UsbTransferDirectionIn;
- Transfer->Length = TransferLength;
- Transfer->Buffer = IoBuffer->Fragment[0].VirtualAddress;
- Transfer->BufferPhysicalAddress = IoBuffer->Fragment[0].PhysicalAddress;
- Transfer->BufferActualLength = IoBuffer->Fragment[0].Size;
- //
- // Submit the transfer and wait for it to complete. The spec says that
- // devices that don't support multiple LUNs may stall the transfer.
- //
- Status = UsbSubmitSynchronousTransfer(Transfer);
- if ((Status == STATUS_DEVICE_IO_ERROR) &&
- (Transfer->Error == UsbErrorTransferStalled)) {
- //
- // Clear the halt condition of endpoint zero. One might think that this
- // is not possible, but indeed it is.
- //
- Status = UsbMasspClearEndpoint(Device, 0, FALSE);
- if (!KSUCCESS(Status)) {
- goto GetMaxLunEnd;
- }
- *LunCount = 1;
- goto GetMaxLunEnd;
- }
- if (!KSUCCESS(Status)) {
- goto GetMaxLunEnd;
- }
- ASSERT(KSUCCESS(Transfer->Status));
- if (Transfer->LengthTransferred != TransferLength) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto GetMaxLunEnd;
- }
- *LunCount = *((PUCHAR)Transfer->Buffer +
- sizeof(USB_SETUP_PACKET));
- //
- // Add 1 since the data value was a "max index", but the caller wants a
- // count.
- //
- *LunCount += 1;
- Status = STATUS_SUCCESS;
- GetMaxLunEnd:
- if (Transfer != NULL) {
- UsbDestroyTransfer(Transfer);
- }
- if (IoBuffer != NULL) {
- MmFreeIoBuffer(IoBuffer);
- }
- return Status;
- }
- KSTATUS
- UsbMasspCreateLogicalDisks (
- PUSB_MASS_STORAGE_DEVICE Device,
- ULONG DiskCount
- )
- /*++
- Routine Description:
- This routine creates a number of logical disks to live under the given
- mass storage device. These disks will be added to the device.
- Arguments:
- Device - Supplies a pointer to this mass storage device.
- DiskCount - Supplies the number of logical disks to create.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DISK Disk;
- ULONG DiskIndex;
- KSTATUS Status;
- ASSERT(LIST_EMPTY(&(Device->LogicalDiskList)) != FALSE);
- Disk = NULL;
- for (DiskIndex = 0; DiskIndex < DiskCount; DiskIndex += 1) {
- Disk = MmAllocateNonPagedPool(sizeof(USB_DISK),
- USB_MASS_ALLOCATION_TAG);
- if (Disk == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateLogicalDisksEnd;
- }
- RtlZeroMemory(Disk, sizeof(USB_DISK));
- Disk->Type = UsbMassStorageLogicalDisk;
- Disk->ReferenceCount = 1;
- Disk->LunNumber = DiskIndex;
- Disk->Device = Device;
- UsbMasspDeviceAddReference(Device);
- //
- // Create the event for synchronous transfers.
- //
- Disk->Event = KeCreateEvent(NULL);
- if (Disk->Event == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateLogicalDisksEnd;
- }
- //
- // Create the set of default transfers for this disk.
- //
- Status = UsbMasspCreateTransfers(Device,
- &(Disk->Transfers),
- Disk,
- UsbMasspTransferCompletionCallback);
- if (!KSUCCESS(Status)) {
- goto CreateLogicalDisksEnd;
- }
- ASSERT(Disk->Connected == FALSE);
- //
- // Add the new disk to the list.
- //
- INSERT_BEFORE(&(Disk->ListEntry), &(Device->LogicalDiskList));
- Disk = NULL;
- }
- Status = STATUS_SUCCESS;
- CreateLogicalDisksEnd:
- if (!KSUCCESS(Status)) {
- if (Disk != NULL) {
- UsbMasspDiskReleaseReference(Disk);
- }
- UsbMasspDestroyLogicalDisks(Device);
- }
- return Status;
- }
- VOID
- UsbMasspDestroyLogicalDisks (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine destroys all logical disks associated with the given mass
- storage device.
- Arguments:
- Device - Supplies a pointer to this mass storage device.
- Return Value:
- None.
- --*/
- {
- PUSB_DISK Disk;
- while (LIST_EMPTY(&(Device->LogicalDiskList)) == FALSE) {
- Disk = LIST_VALUE(Device->LogicalDiskList.Next, USB_DISK, ListEntry);
- LIST_REMOVE(&(Disk->ListEntry));
- //
- // The mass storage driver should only need to call this on disks that
- // never completed enumeration.
- //
- ASSERT(Disk->OsDevice == NULL);
- ASSERT(Disk->Connected == FALSE);
- ASSERT(Disk->ReferenceCount == 1);
- UsbMasspDiskReleaseReference(Disk);
- }
- return;
- }
- PUSB_MASS_STORAGE_POLLED_IO_STATE
- UsbMasspCreatePolledIoState (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine creates polled I/O state for the given USB mass storage device.
- Arguments:
- Device - Supplies a pointer to the USB device that is to be the target of
- the polled I/O.
- Return Value:
- Returns a pointer to a polled I/O state for the device.
- --*/
- {
- ULONG AllocationSize;
- PUSB_TRANSFER ControlTransfer;
- PUSB_MASS_STORAGE_POLLED_IO_STATE PolledIoState;
- KSTATUS Status;
- AllocationSize = sizeof(USB_MASS_STORAGE_POLLED_IO_STATE);
- PolledIoState = MmAllocateNonPagedPool(AllocationSize,
- USB_MASS_ALLOCATION_TAG);
- if (PolledIoState == NULL) {
- return NULL;
- }
- RtlZeroMemory(PolledIoState, AllocationSize);
- //
- // Create the I/O transfers for the newly minted polled I/O state. Since
- // these transfers will be used with polled I/O, they lack a callback
- // routine and user data.
- //
- Status = UsbMasspCreateTransfers(Device,
- &(PolledIoState->IoTransfers),
- NULL,
- NULL);
- if (!KSUCCESS(Status)) {
- goto CreatePolledIoStateEnd;
- }
- //
- // Allocate a control transfer that will be used to perform reset recovery.
- // It only ever needs to send a setup packet.
- //
- ControlTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- 0,
- sizeof(USB_SETUP_PACKET),
- 0);
- if (ControlTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreatePolledIoStateEnd;
- }
- PolledIoState->ControlTransfer = ControlTransfer;
- //
- // Before polled I/O is used for the first time, assumably in a very
- // critical scenario (e.g. crash dump), then mass storage endpoints will
- // need to be reset.
- //
- PolledIoState->ResetRequired = TRUE;
- CreatePolledIoStateEnd:
- if (!KSUCCESS(Status)) {
- if (PolledIoState != NULL) {
- UsbMasspDestroyPolledIoState(PolledIoState);
- PolledIoState = NULL;
- }
- }
- return PolledIoState;
- }
- VOID
- UsbMasspDestroyPolledIoState (
- PUSB_MASS_STORAGE_POLLED_IO_STATE PolledIoState
- )
- /*++
- Routine Description:
- This routine destroys the given polled I/O state.
- Arguments:
- PolledIoState - Supplies a pointer to the polled I/O state to destroy.
- Return Value:
- None.
- --*/
- {
- ASSERT(PolledIoState != NULL);
- UsbMasspDestroyTransfers(&(PolledIoState->IoTransfers));
- if (PolledIoState->ControlTransfer != NULL) {
- UsbDestroyTransfer(PolledIoState->ControlTransfer);
- }
- MmFreeNonPagedPool(PolledIoState);
- return;
- }
- KSTATUS
- UsbMasspCreateTransfers (
- PUSB_MASS_STORAGE_DEVICE Device,
- PUSB_MASS_STORAGE_TRANSFERS Transfers,
- PVOID UserData,
- PUSB_TRANSFER_CALLBACK CallbackRoutine
- )
- /*++
- Routine Description:
- This routine initializes a set of USB disk transfers by creating the
- command, status, and data transfers as well as any necessary buffers.
- Arguments:
- Device - Supplies a pointer to the USB device to which the transfers
- belong.
- Transfers - Supplies a pointer to the USB disk transfers structure to be
- initialized.
- UserData - Supplies an optional pointer to the private user data with which
- the transfers will be initialized.
- CallbackRoutine - Supplies an optional pointer to the USB transfer
- callback routine with which the transfers will be initialized.
- Return Value:
- Status code.
- --*/
- {
- ULONG Alignment;
- PIO_BUFFER CommandBuffer;
- PUSB_TRANSFER CommandTransfer;
- PUSB_TRANSFER DataOutTransfer;
- ULONG IoBufferFlags;
- ULONG MaxCommandBlockSize;
- ULONG MaxCommandBufferSize;
- ULONG MaxCommandStatusSize;
- PHYSICAL_ADDRESS PhysicalAddress;
- KSTATUS Status;
- PUSB_TRANSFER StatusTransfer;
- //
- // Create the I/O buffer used for commands.
- //
- Alignment = MmGetIoBufferAlignment();
- MaxCommandBufferSize = ALIGN_RANGE_UP(USB_MASS_COMMAND_BUFFER_SIZE,
- Alignment);
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- Transfers->CommandBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- Alignment,
- MaxCommandBufferSize,
- IoBufferFlags);
- if (Transfers->CommandBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDiskTransfersEnd;
- }
- ASSERT(Transfers->CommandBuffer->FragmentCount == 1);
- //
- // Create a USB transfer to the get the Command Status Wrapper at the
- // end of a transfer.
- //
- StatusTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->InEndpoint,
- sizeof(SCSI_COMMAND_STATUS),
- 0);
- if (StatusTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDiskTransfersEnd;
- }
- StatusTransfer->Direction = UsbTransferDirectionIn;
- StatusTransfer->Length = sizeof(SCSI_COMMAND_STATUS);
- StatusTransfer->CallbackRoutine = CallbackRoutine;
- StatusTransfer->UserData = UserData;
- Transfers->StatusTransfer = StatusTransfer;
- //
- // The buffer's virtual and physical address is calculated for each
- // request, but there should always be exactly the same amount of
- // memory used for the status transfer.
- //
- MaxCommandStatusSize = ALIGN_RANGE_UP(sizeof(SCSI_COMMAND_STATUS),
- Alignment);
- Transfers->StatusTransfer->BufferActualLength = MaxCommandStatusSize;
- //
- // Create the command transfer for sending the Command Block Wrapper.
- //
- CommandTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->OutEndpoint,
- sizeof(SCSI_COMMAND_BLOCK),
- 0);
- if (CommandTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDiskTransfersEnd;
- }
- CommandTransfer->Direction = UsbTransferDirectionOut;
- CommandTransfer->Length = sizeof(SCSI_COMMAND_BLOCK);
- CommandBuffer = Transfers->CommandBuffer;
- CommandTransfer->Buffer = CommandBuffer->Fragment[0].VirtualAddress;
- PhysicalAddress = CommandBuffer->Fragment[0].PhysicalAddress;
- CommandTransfer->BufferPhysicalAddress = PhysicalAddress;
- MaxCommandBlockSize = ALIGN_RANGE_UP(sizeof(SCSI_COMMAND_BLOCK), Alignment);
- CommandTransfer->BufferActualLength = MaxCommandBlockSize;
- CommandTransfer->CallbackRoutine = CallbackRoutine;
- CommandTransfer->UserData = UserData;
- Transfers->CommandTransfer = CommandTransfer;
- //
- // Create the data in transfer for receiving data from an incoming
- // command.
- //
- Transfers->DataInTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->InEndpoint,
- USB_MASS_MAX_DATA_TRANSFER,
- 0);
- if (Transfers->DataInTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDiskTransfersEnd;
- }
- Transfers->DataInTransfer->Direction = UsbTransferDirectionIn;
- Transfers->DataInTransfer->CallbackRoutine = CallbackRoutine;
- Transfers->DataInTransfer->UserData = UserData;
- //
- // Create the data out transfer for sending data to the disk.
- //
- DataOutTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->OutEndpoint,
- USB_MASS_MAX_DATA_TRANSFER,
- 0);
- if (DataOutTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDiskTransfersEnd;
- }
- DataOutTransfer->Direction = UsbTransferDirectionOut;
- DataOutTransfer->CallbackRoutine = CallbackRoutine;
- DataOutTransfer->UserData = UserData;
- Transfers->DataOutTransfer = DataOutTransfer;
- Status = STATUS_SUCCESS;
- CreateDiskTransfersEnd:
- return Status;
- }
- VOID
- UsbMasspDestroyTransfers (
- PUSB_MASS_STORAGE_TRANSFERS Transfers
- )
- /*++
- Routine Description:
- This routine destroys a USB logical disk's transfers. It does not destroy
- the structure intself.
- Arguments:
- Transfers - Supplies a pointer to a USB disk tranfers structure.
- Return Value:
- None.
- --*/
- {
- if (Transfers->DataOutTransfer != NULL) {
- UsbDestroyTransfer(Transfers->DataOutTransfer);
- }
- if (Transfers->DataInTransfer != NULL) {
- UsbDestroyTransfer(Transfers->DataInTransfer);
- }
- if (Transfers->CommandTransfer != NULL) {
- UsbDestroyTransfer(Transfers->CommandTransfer);
- }
- if (Transfers->StatusTransfer != NULL) {
- UsbDestroyTransfer(Transfers->StatusTransfer);
- }
- if (Transfers->CommandBuffer != NULL) {
- MmFreeIoBuffer(Transfers->CommandBuffer);
- }
- return;
- }
- KSTATUS
- UsbMasspStartDisk (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine attempts to fire up a USB logical disk.
- Arguments:
- Disk - Supplies a pointer to the disk.
- Return Value:
- None.
- --*/
- {
- ULONG BufferSize;
- PSCSI_INQUIRY_PAGE0 Page0;
- BOOL PolledIoSupported;
- KSTATUS Status;
- ULONGLONG Timeout;
- ULONG Try;
- KeAcquireQueuedLock(Disk->Device->Lock);
- //
- // Send the INQUIRY for page 0 as a friendly "hello!".
- //
- BufferSize = sizeof(SCSI_INQUIRY_PAGE0);
- Status = UsbMasspSendInquiry(Disk, 0, (PVOID)&Page0, &BufferSize);
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- BufferSize = sizeof(SCSI_INQUIRY_PAGE0);
- Status = UsbMasspSendInquiry(Disk, 0, (PVOID)&Page0, &BufferSize);
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- //
- // Get the block device parameters of the disk.
- //
- for (Try = 0; Try < USB_MASS_RETRY_COUNT; Try += 1) {
- Status = UsbMasspReadFormatCapacities(Disk);
- if (KSUCCESS(Status)) {
- break;
- }
- Status = UsbMasspRequestSense(Disk);
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- }
- for (Try = 0; Try < USB_MASS_RETRY_COUNT; Try += 1) {
- Status = UsbMasspReadCapacity(Disk);
- if (KSUCCESS(Status)) {
- break;
- }
- if (!KSUCCESS(UsbMasspRequestSense(Disk))) {
- goto StartDiskEnd;
- }
- }
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- Timeout = KeGetRecentTimeCounter() +
- (HlQueryTimeCounterFrequency() * USB_MASS_UNIT_READY_TIMEOUT);
- do {
- Status = UsbMasspTestUnitReady(Disk);
- if (KSUCCESS(Status)) {
- break;
- }
- Status = UsbMasspRequestSense(Disk);
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- Status = STATUS_TIMEOUT;
- } while (KeGetRecentTimeCounter() <= Timeout);
- if (!KSUCCESS(Status)) {
- goto StartDiskEnd;
- }
- //
- // Determine if polled I/O is supported, and create the disk interface if
- // so.
- //
- if (Disk->DiskInterface.DiskToken == NULL) {
- PolledIoSupported = UsbIsPolledIoSupported(Disk->Device->UsbCoreHandle);
- if (PolledIoSupported != FALSE) {
- RtlCopyMemory(&(Disk->DiskInterface),
- &UsbMassDiskInterfaceTemplate,
- sizeof(DISK_INTERFACE));
- Disk->DiskInterface.DiskToken = Disk;
- Disk->DiskInterface.BlockSize = 1 << Disk->BlockShift;
- Disk->DiskInterface.BlockCount = Disk->BlockCount;
- Status = IoCreateInterface(&UsbMassDiskInterfaceUuid,
- Disk->OsDevice,
- &(Disk->DiskInterface),
- sizeof(DISK_INTERFACE));
- if (!KSUCCESS(Status)) {
- Disk->DiskInterface.DiskToken = NULL;
- goto StartDiskEnd;
- }
- }
- }
- StartDiskEnd:
- KeReleaseQueuedLock(Disk->Device->Lock);
- return Status;
- }
- VOID
- UsbMasspRemoveDisk (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine attempts to remove a USB logical disk.
- Arguments:
- Disk - Supplies a pointer to the disk.
- Return Value:
- None.
- --*/
- {
- PUSB_MASS_STORAGE_DEVICE Device;
- //
- // Tear down the disk interface if it was brought up.
- //
- if (Disk->DiskInterface.DiskToken != NULL) {
- IoDestroyInterface(&UsbMassDiskInterfaceUuid,
- Disk->OsDevice,
- &(Disk->DiskInterface));
- Disk->DiskInterface.DiskToken = NULL;
- }
- //
- // Acquire the lock. Once the lock is held, the device will be no longer
- // be in the middle of any transfers. This guarantees any pending IRPs will
- // finish before the device is torn down.
- //
- Device = Disk->Device;
- KeAcquireQueuedLock(Device->Lock);
- //
- // Assert that there is no active IRP.
- //
- ASSERT(Disk->Irp == NULL);
- //
- // Mark the disk as removed to prevent further IO.
- //
- Disk->Connected = FALSE;
- //
- // Remove the disk from the parents device list while holding the lock.
- //
- LIST_REMOVE(&(Disk->ListEntry));
- KeReleaseQueuedLock(Device->Lock);
- //
- // Release the reference on the disk taken during creation. The disk will
- // be destroyed once all the open handles are closed.
- //
- UsbMasspDiskReleaseReference(Disk);
- return;
- }
- VOID
- UsbMasspDestroyDisk (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine destroys a logical disk.
- Arguments:
- Disk - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- //
- // The reference count should be zero.
- //
- ASSERT(Disk->ReferenceCount == 0);
- //
- // Destroy all structures that were created.
- //
- UsbMasspDestroyTransfers(&(Disk->Transfers));
- if (Disk->Event != NULL) {
- KeDestroyEvent(Disk->Event);
- }
- //
- // Release the reference taken on the parent during disk creation.
- //
- UsbMasspDeviceReleaseReference(Disk->Device);
- //
- // Destroy the device structure.
- //
- MmFreeNonPagedPool(Disk);
- return;
- }
- VOID
- UsbMasspDiskAddReference (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine adds a reference to USB mass storage logical disk.
- Arguments:
- Disk - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Disk->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- return;
- }
- VOID
- UsbMasspDiskReleaseReference (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine releases a reference from the USB mass storage logical disk.
- Arguments:
- Disk - Supplies a pointer to the USB mass storage device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Disk->ReferenceCount), (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- UsbMasspDestroyDisk(Disk);
- }
- return;
- }
- KSTATUS
- UsbMasspSendInquiry (
- PUSB_DISK Disk,
- UCHAR Page,
- PVOID *ResultBuffer,
- PULONG ResultBufferSize
- )
- /*++
- Routine Description:
- This routine sends an inquiry to the USB disk device. This routine assumes
- the mass storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to inquire to.
- Page - Supplies the information page number to retrieve.
- ResultBuffer - Supplies a pointer where the buffer containing the
- information will be returned on success. This buffer will be pointing
- into the disk's command buffer.
- ResultBufferSize - Supplies a pointer pointing to an integer that on input
- contains the expected size of the buffer. On output, contains the number
- of bytes transferred.
- Return Value:
- Status code.
- --*/
- {
- ULONG BytesTransferred;
- PUCHAR InquiryCommand;
- KSTATUS Status;
- ASSERT(Disk->Irp == NULL);
- BytesTransferred = 0;
- *ResultBuffer = NULL;
- //
- // Set up the standard portion of the command block wrapper.
- //
- InquiryCommand = UsbMasspSetupCommand(Disk,
- 0,
- *ResultBufferSize,
- SCSI_COMMAND_INQUIRY_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for an inquiry command.
- //
- *InquiryCommand = SCSI_COMMAND_INQUIRY;
- ASSERT(Disk->LunNumber <= 7);
- *(InquiryCommand + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(InquiryCommand + 4) = *ResultBufferSize;
- Disk->Transfers.DataInTransfer->Length = *ResultBufferSize;
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto SendInquiryEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- goto SendInquiryEnd;
- }
- if (BytesTransferred > *ResultBufferSize) {
- Status = STATUS_BUFFER_TOO_SMALL;
- goto SendInquiryEnd;
- }
- *ResultBuffer = Disk->Transfers.DataInTransfer->Buffer;
- SendInquiryEnd:
- *ResultBufferSize = BytesTransferred;
- return Status;
- }
- KSTATUS
- UsbMasspTestUnitReady (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine sends a "test unit ready" command to the USB disk. This
- routine assumes the mass storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to send the command to.
- Return Value:
- STATUS_SUCCESS if the device is ready.
- STATUS_NOT_READY if the device is not ready.
- Other error codes on failure.
- --*/
- {
- ULONG BytesTransferred;
- KSTATUS Status;
- PUCHAR TestUnitReadyCommand;
- ASSERT(Disk->Irp == NULL);
- BytesTransferred = 0;
- //
- // Set up the standard portion of the command block wrapper.
- //
- TestUnitReadyCommand = UsbMasspSetupCommand(
- Disk,
- 0,
- 0,
- SCSI_COMMAND_TEST_UNIT_READY_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for an inquiry command.
- //
- *TestUnitReadyCommand = SCSI_COMMAND_TEST_UNIT_READY;
- ASSERT(Disk->LunNumber <= 7);
- *(TestUnitReadyCommand + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(TestUnitReadyCommand + 4) = 0;
- Disk->Transfers.DataInTransfer->Length = 0;
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto TestUnitReadyEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- Status = STATUS_NOT_READY;
- goto TestUnitReadyEnd;
- }
- TestUnitReadyEnd:
- return Status;
- }
- KSTATUS
- UsbMasspRequestSense (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine sends a "request sense data" command to the USB disk. This
- routine assumes the mass storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to inquire to.
- Return Value:
- STATUS_SUCCESS if the device is ready.
- STATUS_NOT_READY if the device is not ready.
- Other error codes on failure.
- --*/
- {
- ULONG BytesTransferred;
- PUCHAR RequestSenseCommand;
- KSTATUS Status;
- ASSERT(Disk->Irp == NULL);
- BytesTransferred = 0;
- //
- // Set up the standard portion of the command block wrapper.
- //
- RequestSenseCommand = UsbMasspSetupCommand(
- Disk,
- 0,
- SCSI_COMMAND_REQUEST_SENSE_DATA_SIZE,
- SCSI_COMMAND_REQUEST_SENSE_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for an inquiry command.
- //
- *RequestSenseCommand = SCSI_COMMAND_REQUEST_SENSE;
- ASSERT(Disk->LunNumber <= 7);
- *(RequestSenseCommand + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(RequestSenseCommand + 4) = SCSI_COMMAND_REQUEST_SENSE_DATA_SIZE;
- Disk->Transfers.DataInTransfer->Length =
- SCSI_COMMAND_REQUEST_SENSE_DATA_SIZE;
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto RequestSenseEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- goto RequestSenseEnd;
- }
- RequestSenseEnd:
- return Status;
- }
- KSTATUS
- UsbMasspModeSense (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine sends a "mode sense" command to the USB disk. This routine
- assumes the mass storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to inquire to.
- Return Value:
- STATUS_SUCCESS if the device is ready.
- STATUS_NOT_READY if the device is not ready.
- Other error codes on failure.
- --*/
- {
- ULONG BytesTransferred;
- PUCHAR RequestSenseCommand;
- KSTATUS Status;
- ASSERT(Disk->Irp == NULL);
- BytesTransferred = 0;
- //
- // Set up the standard portion of the command block wrapper.
- //
- RequestSenseCommand = UsbMasspSetupCommand(
- Disk,
- 0,
- SCSI_COMMAND_MODE_SENSE_6_DATA_SIZE,
- SCSI_COMMAND_MODE_SENSE_6_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for an inquiry command.
- //
- *RequestSenseCommand = SCSI_COMMAND_MODE_SENSE_6;
- ASSERT(Disk->LunNumber <= 7);
- *(RequestSenseCommand + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(RequestSenseCommand + 2) = 0x1C;
- *(RequestSenseCommand + 4) = SCSI_COMMAND_MODE_SENSE_6_DATA_SIZE;
- Disk->Transfers.DataInTransfer->Length =
- SCSI_COMMAND_MODE_SENSE_6_DATA_SIZE;
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto ModeSenseEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- goto ModeSenseEnd;
- }
- ModeSenseEnd:
- return Status;
- }
- KSTATUS
- UsbMasspReadFormatCapacities (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine reads the capacity into the device using the "read format
- capacities" command. The results will be written into the disk structure on
- success. This routine assumes the mass storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to query.
- Return Value:
- Status code.
- --*/
- {
- ULONG BlockSize;
- ULONG BytesTransferred;
- PSCSI_FORMAT_CAPACITIES Capacities;
- PUCHAR Command;
- PUSB_TRANSFER DataInTransfer;
- KSTATUS Status;
- ASSERT(Disk->Irp == NULL);
- Command = UsbMasspSetupCommand(
- Disk,
- 0,
- SCSI_COMMAND_READ_FORMAT_CAPACITIES_DATA_SIZE,
- SCSI_COMMAND_READ_FORMAT_CAPACITIES_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for a read format capacities command.
- //
- *Command = SCSI_COMMAND_READ_FORMAT_CAPACITIES;
- ASSERT(Disk->LunNumber <= 7);
- *(Command + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(Command + 8) = SCSI_COMMAND_READ_FORMAT_CAPACITIES_DATA_SIZE;
- DataInTransfer = Disk->Transfers.DataInTransfer;
- DataInTransfer->Length = SCSI_COMMAND_READ_FORMAT_CAPACITIES_DATA_SIZE;
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto ReadFormatCapacitiesEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- goto ReadFormatCapacitiesEnd;
- }
- if (BytesTransferred < sizeof(SCSI_FORMAT_CAPACITIES)) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ReadFormatCapacitiesEnd;
- }
- Capacities = (PSCSI_FORMAT_CAPACITIES)DataInTransfer->Buffer;
- Disk->BlockCount = CONVERT_BIG_ENDIAN_TO_CPU32(Capacities->BlockCount) + 1;
- BlockSize = CONVERT_BIG_ENDIAN_TO_CPU32(Capacities->BlockLength);
- if ((Disk->BlockCount == 0) || (BlockSize == 0)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ReadFormatCapacitiesEnd;
- }
- if (POWER_OF_2(BlockSize) == FALSE) {
- RtlDebugPrint("USB MASS: Invalid block size 0x%08x for device 0x%08x\n",
- BlockSize,
- Disk->OsDevice);
- Status = STATUS_INVALID_CONFIGURATION;
- goto ReadFormatCapacitiesEnd;
- }
- Disk->BlockShift = RtlCountTrailingZeros32(BlockSize);
- ReadFormatCapacitiesEnd:
- return Status;
- }
- KSTATUS
- UsbMasspReadCapacity (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine reads the capacity into the device. The results will be
- written into the disk structure on success. This routine assumes the mass
- storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk to query.
- Return Value:
- Status code.
- --*/
- {
- ULONG BlockSize;
- ULONG BytesTransferred;
- PSCSI_CAPACITY Capacity;
- PUCHAR Command;
- KSTATUS Status;
- ASSERT(Disk->Irp == NULL);
- Command = UsbMasspSetupCommand(Disk,
- 0,
- sizeof(SCSI_CAPACITY),
- SCSI_COMMAND_READ_CAPACITY_SIZE,
- TRUE,
- FALSE,
- NULL,
- 0);
- //
- // Set up the command portion for a read capacity command.
- //
- *Command = SCSI_COMMAND_READ_CAPACITY;
- ASSERT(Disk->LunNumber <= 7);
- *(Command + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- Disk->Transfers.DataInTransfer->Length = sizeof(SCSI_CAPACITY);
- //
- // Send the command.
- //
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto ReadCapacityEnd;
- }
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- if (!KSUCCESS(Status)) {
- goto ReadCapacityEnd;
- }
- if (BytesTransferred < sizeof(SCSI_CAPACITY)) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ReadCapacityEnd;
- }
- Capacity = (PSCSI_CAPACITY)Disk->Transfers.DataInTransfer->Buffer;
- Disk->BlockCount =
- CONVERT_BIG_ENDIAN_TO_CPU32(Capacity->LastValidBlockAddress) + 1;
- BlockSize = CONVERT_BIG_ENDIAN_TO_CPU32(Capacity->BlockLength);
- if ((Disk->BlockCount == 0) || (BlockSize == 0)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ReadCapacityEnd;
- }
- if (POWER_OF_2(BlockSize) == FALSE) {
- RtlDebugPrint("USB MASS: Invalid block size 0x%08x for device 0x%08x\n",
- BlockSize,
- Disk->OsDevice);
- Status = STATUS_INVALID_CONFIGURATION;
- goto ReadCapacityEnd;
- }
- Disk->BlockShift = RtlCountTrailingZeros32(BlockSize);
- ReadCapacityEnd:
- return Status;
- }
- PVOID
- UsbMasspSetupCommand (
- PUSB_DISK Disk,
- ULONG Tag,
- ULONG DataLength,
- UCHAR CommandLength,
- BOOL DataIn,
- BOOL PolledIo,
- PVOID TransferVirtualAddress,
- PHYSICAL_ADDRESS TransferPhysicalAddress
- )
- /*++
- Routine Description:
- This routine prepares to send a command to a disk by setting up the command
- block wrapper and command status wrapper. This routine assumes the mass
- storage device lock is already held.
- Arguments:
- Disk - Supplies a pointer to the disk that the command will be sent to.
- Tag - Supplies an optional tag value to use, which can be useful in matching
- up responses to requests.
- DataLength - Supplies the length of the non-command portion of the transfer.
- CommandLength - Supplies the length of the remaining free-form command
- part of the Command Block Wrapper.
- DataIn - Supplies a boolean indicating if the command is coming into the
- host (TRUE) or going out to the device (FALSE).
- PolledIo - Supplies a boolean indicating if the command is using the polled
- I/O transfers (TRUE) or the default transfers (FALSE).
- TransferVirtualAddress - Supplies a pointer to an optional buffer to use
- for the data transfer.
- TransferPhysicalAddress - Supplies the base physical address of the
- transfer buffer. This parameter is optional but is required if the
- transfer buffer is supplied.
- Return Value:
- Returns a pointer to the first free-form command byte in the Command Block
- Wrapper.
- --*/
- {
- ULONG AlignedDataLength;
- ULONG BufferAlignment;
- PSCSI_COMMAND_BLOCK Command;
- PUSB_TRANSFER CommandTransfer;
- PUSB_TRANSFER StatusTransfer;
- PUSB_MASS_STORAGE_TRANSFERS Transfers;
- if (PolledIo != FALSE) {
- ASSERT(Disk->Device->PolledIoState != NULL);
- Transfers = &(Disk->Device->PolledIoState->IoTransfers);
- } else {
- Transfers = &(Disk->Transfers);
- }
- CommandTransfer = Transfers->CommandTransfer;
- StatusTransfer = Transfers->StatusTransfer;
- //
- // Set up the Command Block Wrapper (CBW).
- //
- Command = CommandTransfer->Buffer;
- RtlZeroMemory(Command, sizeof(SCSI_COMMAND_BLOCK));
- Command->Signature = SCSI_COMMAND_BLOCK_SIGNATURE;
- Command->Tag = Tag;
- Command->DataTransferLength = DataLength;
- if (DataIn != FALSE) {
- Command->Flags = SCSI_COMMAND_BLOCK_FLAG_DATA_IN;
- } else {
- Command->Flags = 0;
- }
- Command->LunNumber = Disk->LunNumber;
- ASSERT(CommandLength <= 0x10);
- Command->CommandLength = CommandLength;
- //
- // If no transfer buffer is supplied, then the transfer will use the
- // command buffer. Set the status buffer after the data.
- //
- BufferAlignment = MmGetIoBufferAlignment();
- if (TransferVirtualAddress == NULL) {
- AlignedDataLength = ALIGN_RANGE_UP(DataLength, BufferAlignment);
- //
- // If a transfer buffer is supplied, the status buffer can start right
- // after the command.
- //
- } else {
- AlignedDataLength = 0;
- }
- ASSERT((CommandTransfer->BufferActualLength +
- StatusTransfer->BufferActualLength +
- AlignedDataLength) <=
- ALIGN_RANGE_UP(USB_MASS_COMMAND_BUFFER_SIZE, BufferAlignment));
- ASSERT(IS_ALIGNED((UINTN)CommandTransfer->Buffer, BufferAlignment));
- ASSERT(IS_ALIGNED(CommandTransfer->BufferPhysicalAddress, BufferAlignment));
- //
- // Set the location and zero out the CSW.
- //
- StatusTransfer->Buffer = CommandTransfer->Buffer +
- CommandTransfer->BufferActualLength +
- AlignedDataLength;
- StatusTransfer->BufferPhysicalAddress =
- CommandTransfer->BufferPhysicalAddress +
- CommandTransfer->BufferActualLength +
- AlignedDataLength;
- RtlZeroMemory(StatusTransfer->Buffer, sizeof(SCSI_COMMAND_STATUS));
- ASSERT(IS_ALIGNED((UINTN)StatusTransfer->Buffer, BufferAlignment));
- ASSERT(IS_ALIGNED(StatusTransfer->BufferPhysicalAddress, BufferAlignment));
- //
- // Set up the data in transfer to point immediately after the command block
- // or to the supplied buffer.
- //
- if (TransferVirtualAddress == NULL) {
- DataLength = AlignedDataLength;
- TransferVirtualAddress = CommandTransfer->Buffer +
- CommandTransfer->BufferActualLength;
- TransferPhysicalAddress = CommandTransfer->BufferPhysicalAddress +
- CommandTransfer->BufferActualLength;
- }
- ASSERT(TransferPhysicalAddress != INVALID_PHYSICAL_ADDRESS);
- Transfers->DataInTransfer->Length = 0;
- Transfers->DataInTransfer->Buffer = TransferVirtualAddress;
- Transfers->DataInTransfer->BufferPhysicalAddress = TransferPhysicalAddress;
- Transfers->DataInTransfer->BufferActualLength = DataLength;
- Transfers->DataOutTransfer->Length = 0;
- Transfers->DataOutTransfer->Buffer = TransferVirtualAddress;
- Transfers->DataOutTransfer->BufferPhysicalAddress = TransferPhysicalAddress;
- Transfers->DataOutTransfer->BufferActualLength = DataLength;
- return &(Command->Command);
- }
- KSTATUS
- UsbMasspSendCommand (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine sends the command that's primed up in the command buffer of
- the given USB disk. This routine assumes the mass storage device lock is
- already held.
- Arguments:
- Disk - Supplies a pointer to the disk that the command will be sent to.
- Irp - Supplies a pointer to an I/O IRP to continue when the transfer
- completes. If this is NULL, the transfer will be completed
- synchronously.
- Return Value:
- Status code. This status code may represent a failure to send, communicate,
- or the disk failing the operation in the CSW. If the Command Status Wrapper
- returns a phase error, this routine will reset the disk.
- --*/
- {
- KSTATUS Status;
- ASSERT(KeIsQueuedLockHeld(Disk->Device->Lock) != FALSE);
- if (Disk->Irp == NULL) {
- KeSignalEvent(Disk->Event, SignalOptionUnsignal);
- }
- Disk->StatusTransferAttempts = 0;
- //
- // Send the Command Block Wrapper.
- //
- Status = UsbSubmitTransfer(Disk->Transfers.CommandTransfer);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- //
- // If there's an IRP, return immediately.
- //
- if (Disk->Irp != NULL) {
- Status = STATUS_SUCCESS;
- goto SendCommandEnd;
- }
- //
- // This is a synchronous transfer. Mark that all transfers have been
- // submitted, and wait for them to come back.
- //
- KeWaitForEvent(Disk->Event, FALSE, WAIT_TIME_INDEFINITE);
- Status = STATUS_SUCCESS;
- SendCommandEnd:
- return Status;
- }
- VOID
- UsbMasspTransferCompletionCallback (
- PUSB_TRANSFER Transfer
- )
- /*++
- Routine Description:
- This routine is called when a USB transfer completes for mass storage.
- Arguments:
- Transfer - Supplies a pointer to the transfer that completed.
- Return Value:
- None.
- --*/
- {
- ULONG BytesTransferred;
- BOOL CompleteIrp;
- PUSB_DISK Disk;
- UCHAR Endpoint;
- PIRP Irp;
- KSTATUS Status;
- BOOL SubmitStatusTransfer;
- PUSB_MASS_STORAGE_TRANSFERS Transfers;
- BOOL TransferSent;
- CompleteIrp = FALSE;
- Disk = (PUSB_DISK)Transfer->UserData;
- Irp = Disk->Irp;
- SubmitStatusTransfer = FALSE;
- Transfers = &(Disk->Transfers);
- TransferSent = FALSE;
- ASSERT((Disk != NULL) && (Disk->Type == UsbMassStorageLogicalDisk));
- ASSERT(KeIsQueuedLockHeld(Disk->Device->Lock) != FALSE);
- //
- // Handle stall failures according to the transfer type. All other failures
- // should just roll through until the command status transfer is returned.
- //
- if ((Transfer != Transfers->CommandTransfer) &&
- !KSUCCESS(Transfer->Status) &&
- (Transfer->Error == UsbErrorTransferStalled)) {
- //
- // Pick the correct endpoint to clear. The status and data IN transfers
- // clear the IN endpoint. The data OUT transfer clears the out endpoint.
- //
- Endpoint = Disk->Device->InEndpoint;
- if (Transfer == Transfers->DataOutTransfer) {
- Endpoint = Disk->Device->OutEndpoint;
- }
- UsbMasspClearEndpoint(Disk->Device, Endpoint, FALSE);
- //
- // Attempt to receive another command status wrapper if allowed.
- //
- if ((Transfer == Transfers->StatusTransfer) &&
- (Disk->StatusTransferAttempts <
- USB_MASS_STATUS_TRANSFER_ATTEMPT_LIMIT)) {
- SubmitStatusTransfer = TRUE;
- }
- }
- //
- // If this is a successful command transfer completing, then fire off the
- // next transfer in the set. If the command transfer fails, this I/O
- // request is toast.
- //
- if (Transfer == Transfers->CommandTransfer) {
- if (KSUCCESS(Transfer->Status)) {
- //
- // If there's data, submit the appropriate data transfer.
- //
- Disk->Transfers.DataInTransfer->Error = UsbErrorNone;
- Disk->Transfers.DataOutTransfer->Error = UsbErrorNone;
- if (Disk->Transfers.DataInTransfer->Length != 0) {
- ASSERT(Disk->Transfers.DataOutTransfer->Length == 0);
- TransferSent = TRUE;
- Status = UsbSubmitTransfer(Disk->Transfers.DataInTransfer);
- if (!KSUCCESS(Status)) {
- TransferSent = FALSE;
- }
- } else if (Disk->Transfers.DataOutTransfer->Length != 0) {
- TransferSent = TRUE;
- Status = UsbSubmitTransfer(Disk->Transfers.DataOutTransfer);
- if (!KSUCCESS(Status)) {
- TransferSent = FALSE;
- }
- //
- // Otherwise submit the transfer for the status word. If there is
- // data then the status transfer will be submitted when the data
- // portion is done.
- //
- } else {
- ASSERT((Disk->Transfers.DataInTransfer->Length == 0) &&
- (Disk->Transfers.DataOutTransfer->Length == 0));
- SubmitStatusTransfer = TRUE;
- }
- }
- //
- // If the data IN or data OUT portion completed, submit the status transfer.
- // The status transfer needs to be received even if the data transfer
- // failed (or was cancelled). If the submission fails, it will be handled
- // below with a reset. If a device I/O error occurred during the data
- // portion, just skip the status transfer; the endpoint will go through
- // reset recovery.
- //
- } else if ((Transfer != Transfers->StatusTransfer) &&
- (Transfer->Error != UsbErrorTransferDeviceIo)) {
- ASSERT((Transfer == Transfers->DataInTransfer) ||
- (Transfer == Transfers->DataOutTransfer));
- SubmitStatusTransfer = TRUE;
- }
- //
- // If the status transfer needs to be submitted or resubmitted, fire it off.
- //
- if (SubmitStatusTransfer != FALSE) {
- TransferSent = TRUE;
- Disk->StatusTransferAttempts += 1;
- Status = UsbSubmitTransfer(Disk->Transfers.StatusTransfer);
- if (!KSUCCESS(Status)) {
- Disk->StatusTransferAttempts -= 1;
- TransferSent = FALSE;
- }
- }
- //
- // Do not do any processing if another transfer was sent.
- //
- if (TransferSent != FALSE) {
- return;
- }
- //
- // If the IRP is NULL, this must have been a synchronous transfer. If so,
- // signal the event and let it handle the processing.
- //
- if (Irp == NULL) {
- KeSignalEvent(Disk->Event, SignalOptionSignalAll);
- return;
- }
- //
- // Evaluate the result of the transfer and continue the IRP.
- //
- Status = UsbMasspEvaluateCommandStatus(Disk,
- FALSE,
- FALSE,
- &BytesTransferred);
- Disk->CurrentFragmentOffset += BytesTransferred;
- Disk->CurrentBytesTransferred += BytesTransferred;
- ASSERT(Disk->CurrentBytesTransferred <= Irp->U.ReadWrite.IoSizeInBytes);
- //
- // If the command succeeded and all the bytes have been transferred, then
- // complete the IRP.
- //
- if (KSUCCESS(Status)) {
- if (Disk->CurrentBytesTransferred == Irp->U.ReadWrite.IoSizeInBytes) {
- CompleteIrp = TRUE;
- goto TransferCompletionCallbackEnd;
- }
- Disk->IoRequestAttempts = 0;
- //
- // If it failed, prep to try the command again, unless it has been
- // attempted too many times.
- //
- } else {
- Disk->IoRequestAttempts += 1;
- if (Disk->IoRequestAttempts > USB_MASS_IO_REQUEST_RETRY_COUNT) {
- CompleteIrp = TRUE;
- goto TransferCompletionCallbackEnd;
- }
- }
- //
- // Request the next batch of stuff (it could also be retry of the same
- // batch). If this fails, complete the IRP. Do not attempt any retries, as
- // failure here indicates a more serious failure (e.g. the command transfer
- // failed to even be submitted).
- //
- Status = UsbMasspSendNextIoRequest(Disk);
- if (!KSUCCESS(Status)) {
- CompleteIrp = TRUE;
- goto TransferCompletionCallbackEnd;
- }
- TransferCompletionCallbackEnd:
- if (CompleteIrp != FALSE) {
- ASSERT(Disk->Irp != NULL);
- Irp->U.ReadWrite.IoBytesCompleted = Disk->CurrentBytesTransferred;
- Irp->U.ReadWrite.NewIoOffset = Irp->U.ReadWrite.IoOffset +
- Irp->U.ReadWrite.IoBytesCompleted;
- IoCompleteIrp(UsbMassDriver, Irp, Status);
- }
- return;
- }
- KSTATUS
- UsbMasspEvaluateCommandStatus (
- PUSB_DISK Disk,
- BOOL PolledIo,
- BOOL DisableRecovery,
- PULONG BytesTransferred
- )
- /*++
- Routine Description:
- This routine evaluates a Command Status Wrapper. This follows the USB Mass
- Storage Class Bulk-Only Transport specification sections 6.5, 6.6, and 6.7.
- Arguments:
- Disk - Supplies a pointer to the disk that just completed a command.
- PolledIo - Supplies a boolean indicating if the polled I/O transfers should
- be evaluated (TRUE) or the default transfers (FALSE).
- DisableRecovery - Supplies a boolean indicating if reset recovery is
- disabled (TRUE) or enabled (FALSE).
- BytesTransferred - Supplies a pointer where the number of completed bytes
- will be returned.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if the SCSI status was unsuccessful or a phase error.
- STATUS_CHECKSUM_MISMATCH if the signature or tag values don't match.
- Other errors if the USB transfers themselves failed.
- --*/
- {
- PSCSI_COMMAND_BLOCK CommandBlock;
- PSCSI_COMMAND_STATUS CommandStatus;
- KSTATUS Status;
- PUSB_TRANSFER StatusTransfer;
- PUSB_MASS_STORAGE_TRANSFERS Transfers;
- *BytesTransferred = 0;
- if (PolledIo != FALSE) {
- ASSERT(Disk->Device->PolledIoState != NULL);
- Transfers = &(Disk->Device->PolledIoState->IoTransfers);
- } else {
- Transfers = &(Disk->Transfers);
- }
- //
- // If the command transfer failed, there is no guarantee about any of the
- // subsequent transfers. Just reset the device and exit.
- //
- if (!KSUCCESS(Transfers->CommandTransfer->Status)) {
- Status = Transfers->CommandTransfer->Status;
- goto EvaluateCommandStatusEnd;
- }
- ASSERT(Transfers->CommandTransfer->LengthTransferred ==
- Transfers->CommandTransfer->Length);
- if ((Transfers->DataInTransfer->Error != UsbErrorNone) ||
- (Transfers->DataOutTransfer->Error != UsbErrorNone)) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto EvaluateCommandStatusEnd;
- }
- //
- // First check to see if the command status transfer itself was successful.
- // If not, reset the device and return. The device will not receive another
- // command transfer until it sends a CSW or a reset occurred. Without a
- // successful status transfer, there is no guarantee the CSW was sent.
- //
- if (!KSUCCESS(Transfers->StatusTransfer->Status)) {
- Status = Transfers->StatusTransfer->Status;
- goto EvaluateCommandStatusEnd;
- }
- //
- // Check to see if the command status transfer is valid. The length
- // transferred has to match the length, the signature needs to match and
- // the tag needs to match that of the command block transfer.
- //
- StatusTransfer = Transfers->StatusTransfer;
- CommandBlock = (PSCSI_COMMAND_BLOCK)Transfers->CommandTransfer->Buffer;
- CommandStatus = (PSCSI_COMMAND_STATUS)StatusTransfer->Buffer;
- if ((StatusTransfer->LengthTransferred != StatusTransfer->Length) ||
- (CommandStatus->Signature != SCSI_COMMAND_STATUS_SIGNATURE) ||
- (CommandStatus->Tag != CommandBlock->Tag)) {
- RtlDebugPrint("USBMASS: CSW Signature and tag were 0x%x 0x%x. "
- "Possible USB or cache coherency issues.\n",
- CommandStatus->Signature,
- CommandStatus->Tag);
- Status = STATUS_DEVICE_IO_ERROR;
- goto EvaluateCommandStatusEnd;
- }
- //
- // Check to see if the status is meaningful. A meaningful status is
- // indicated in two ways. The first is when the status is either success or
- // failure and the residue is less than or equal the transfer length.
- //
- if (((CommandStatus->Status == SCSI_STATUS_SUCCESS) ||
- (CommandStatus->Status == SCSI_STATUS_FAILED)) &&
- (CommandStatus->DataResidue <= CommandBlock->DataTransferLength)) {
- *BytesTransferred = CommandBlock->DataTransferLength -
- CommandStatus->DataResidue;
- Status = STATUS_SUCCESS;
- goto EvaluateCommandStatusEnd;
- }
- //
- // The second is when the status indicates a phase error. A reset recovery
- // is required and the residue data is ignored.
- //
- if (CommandStatus->Status == SCSI_STATUS_PHASE_ERROR) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto EvaluateCommandStatusEnd;
- }
- //
- // The status is valid, but not meaningful. Section 6.5 of the USB mass
- // storage specification (bulk-only) indicates that a host "may" perform
- // a reset recovery in this case, but is not required. Well, why not? All
- // the other failures in this routine are doing it.
- //
- Status = STATUS_DEVICE_IO_ERROR;
- EvaluateCommandStatusEnd:
- if (!KSUCCESS(Status)) {
- if (DisableRecovery == FALSE) {
- UsbMasspResetRecovery(Disk->Device, PolledIo);
- }
- }
- return Status;
- }
- KSTATUS
- UsbMasspSendNextIoRequest (
- PUSB_DISK Disk
- )
- /*++
- Routine Description:
- This routine starts transmission of the next chunk of I/O in a data
- transfer request.
- Arguments:
- Disk - Supplies a pointer to the disk to transfer to or from.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG Block;
- UINTN BlockCount;
- UINTN BytesToTransfer;
- UCHAR Command;
- PUCHAR CommandBuffer;
- BOOL CommandIn;
- UCHAR CommandLength;
- PIO_BUFFER IoBuffer;
- PIRP Irp;
- PHYSICAL_ADDRESS PhysicalAddress;
- UINTN RequestSize;
- KSTATUS Status;
- PUSB_TRANSFER UsbDataTransfer;
- PVOID VirtualAddress;
- Irp = Disk->Irp;
- IoBuffer = Irp->U.ReadWrite.IoBuffer;
- ASSERT(Irp != NULL);
- ASSERT(IoBuffer != NULL);
- ASSERT(Disk->CurrentBytesTransferred < Irp->U.ReadWrite.IoSizeInBytes);
- ASSERT(Disk->CurrentFragment < IoBuffer->FragmentCount);
- ASSERT(Disk->CurrentFragmentOffset <=
- IoBuffer->Fragment[Disk->CurrentFragment].Size);
- //
- // Advance to the next fragment if the end of the previous one was reached.
- //
- if (Disk->CurrentFragmentOffset ==
- IoBuffer->Fragment[Disk->CurrentFragment].Size) {
- Disk->CurrentFragment += 1;
- Disk->CurrentFragmentOffset = 0;
- //
- // End if this was the last fragment.
- //
- if (Disk->CurrentFragment == IoBuffer->FragmentCount) {
- ASSERT(Disk->CurrentBytesTransferred ==
- Irp->U.ReadWrite.IoSizeInBytes);
- Status = STATUS_SUCCESS;
- goto SendNextIoRequestEnd;
- }
- }
- //
- // Transfer the rest of the fragment, but cap it to the max of what the
- // allocated USB transfer can do and on how many bytes have already been
- // transferred and/or need to be transferred.
- //
- RequestSize = IoBuffer->Fragment[Disk->CurrentFragment].Size -
- Disk->CurrentFragmentOffset;
- BytesToTransfer = Irp->U.ReadWrite.IoSizeInBytes -
- Disk->CurrentBytesTransferred;
- if (BytesToTransfer < RequestSize) {
- RequestSize = BytesToTransfer;
- }
- if (RequestSize > USB_MASS_MAX_DATA_TRANSFER) {
- RequestSize = USB_MASS_MAX_DATA_TRANSFER;
- }
- ASSERT(RequestSize != 0);
- ASSERT(IS_ALIGNED(RequestSize, MmGetIoBufferAlignment()) != FALSE);
- PhysicalAddress =
- IoBuffer->Fragment[Disk->CurrentFragment].PhysicalAddress +
- Disk->CurrentFragmentOffset;
- VirtualAddress = IoBuffer->Fragment[Disk->CurrentFragment].VirtualAddress +
- Disk->CurrentFragmentOffset;
- //
- // Compute the block offset and size.
- //
- Block = Irp->U.ReadWrite.IoOffset + Disk->CurrentBytesTransferred;
- ASSERT(IS_ALIGNED(Block, (1 << Disk->BlockShift)) != FALSE);
- Block >>= Disk->BlockShift;
- ASSERT(IS_ALIGNED(RequestSize, (1 << Disk->BlockShift)) != FALSE);
- ASSERT(Block == (ULONG)Block);
- BlockCount = RequestSize >> Disk->BlockShift;
- ASSERT(BlockCount == (USHORT)BlockCount);
- ASSERT(RequestSize == (ULONG)RequestSize);
- //
- // Watch for doing I/O off the end of the device.
- //
- if ((Block >= Disk->BlockCount) ||
- (Block + BlockCount > Disk->BlockCount)) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto SendNextIoRequestEnd;
- }
- //
- // Set up the transfer.
- //
- if (Irp->MinorCode == IrpMinorIoRead) {
- Command = SCSI_COMMAND_READ_10;
- CommandLength = SCSI_COMMAND_READ_10_SIZE;
- CommandIn = TRUE;
- UsbDataTransfer = Disk->Transfers.DataInTransfer;
- } else {
- ASSERT(Irp->MinorCode == IrpMinorIoWrite);
- Command = SCSI_COMMAND_WRITE_10;
- CommandLength = SCSI_COMMAND_WRITE_10_SIZE;
- CommandIn = FALSE;
- UsbDataTransfer = Disk->Transfers.DataOutTransfer;
- }
- CommandBuffer = UsbMasspSetupCommand(Disk,
- Command,
- (ULONG)RequestSize,
- CommandLength,
- CommandIn,
- FALSE,
- VirtualAddress,
- PhysicalAddress);
- *CommandBuffer = Command;
- *(CommandBuffer + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(CommandBuffer + 2) = (UCHAR)(Block >> 24);
- *(CommandBuffer + 3) = (UCHAR)(Block >> 16);
- *(CommandBuffer + 4) = (UCHAR)(Block >> 8);
- *(CommandBuffer + 5) = (UCHAR)Block;
- *(CommandBuffer + 7) = (UCHAR)(BlockCount >> 8);
- *(CommandBuffer + 8) = (UCHAR)BlockCount;
- UsbDataTransfer->Length = (ULONG)RequestSize;
- Status = UsbMasspSendCommand(Disk);
- if (!KSUCCESS(Status)) {
- goto SendNextIoRequestEnd;
- }
- Status = STATUS_SUCCESS;
- SendNextIoRequestEnd:
- return Status;
- }
- KSTATUS
- UsbMasspResetRecovery (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- )
- /*++
- Routine Description:
- This routine issues a reset recovery to the mass storage bulk-only device.
- Reset recovery consists of a bulk-only mass storage reset, clearing the
- HALT feature in the IN endpoint, and then clearing the HALT feature in the
- OUT endpoint.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device that needs to
- be reset.
- PolledIo - Supplies a boolean indicating if polled I/O should be used to
- perform the reset recovery (TRUE) or not (FALSE). The default is FALSE.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // Proceed according to Section 5.3.4 of the USB Mass Storage
- // Specification. First, reset the mass storage device and then clear the
- // halts on both the IN and OUT endpoints.
- //
- Status = UsbMasspReset(Device, PolledIo);
- if (!KSUCCESS(Status)) {
- goto ResetRecoveryEnd;
- }
- Status = UsbMasspClearHalts(Device, PolledIo);
- if (!KSUCCESS(Status)) {
- goto ResetRecoveryEnd;
- }
- ResetRecoveryEnd:
- //
- // If reset recovery fails, notify the system so that action can be taken.
- //
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("USB MASS: Failed reset recovery on device 0x%08x!\n",
- Device);
- if (PolledIo == FALSE) {
- IoSetDeviceDriverError(UsbGetDeviceToken(Device->UsbCoreHandle),
- UsbMassDriver,
- Status,
- USB_MASS_ERROR_FAILED_RESET_RECOVERY);
- }
- }
- return Status;
- }
- KSTATUS
- UsbMasspReset (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- )
- /*++
- Routine Description:
- This routine resets the given mass storage device. It assumes that the
- device lock is held or polled I/O mode is requested.
- Arguments:
- Device - Supplies a pointer to this mass storage device.
- PolledIo - Supplies a boolean indicating if the reset should be performed
- using polled I/O.
- Return Value:
- Status code.
- --*/
- {
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ASSERT((PolledIo != FALSE) || (KeIsQueuedLockHeld(Device->Lock) != FALSE));
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_TO_DEVICE |
- USB_SETUP_REQUEST_CLASS |
- USB_SETUP_REQUEST_INTERFACE_RECIPIENT;
- SetupPacket.Request = USB_MASS_REQUEST_RESET_DEVICE;
- SetupPacket.Value = 0;
- SetupPacket.Index = Device->InterfaceNumber;
- SetupPacket.Length = 0;
- //
- // If polled I/O is requested, then use a USB mass specific send command.
- //
- if (PolledIo != FALSE) {
- Status = UsbMasspSendPolledIoControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket);
- if (!KSUCCESS(Status)) {
- goto ResetEnd;
- }
- //
- // Otherwise, submit the transfer with the default command and wait for it
- // to complete.
- //
- } else {
- Status = UsbSendControlTransfer(Device->UsbCoreHandle,
- UsbTransferDirectionOut,
- &SetupPacket,
- NULL,
- 0,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ResetEnd;
- }
- }
- ResetEnd:
- return Status;
- }
- KSTATUS
- UsbMasspClearHalts (
- PUSB_MASS_STORAGE_DEVICE Device,
- BOOL PolledIo
- )
- /*++
- Routine Description:
- This routine clears the HALT feature on the bulk in and out endpoints. This
- routine assumes the device lock is held or polled I/O mode is requested.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device.
- PolledIo - Supplies a boolean indicating if the halt bits should be cleared
- using polled I/O.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- Status = UsbMasspClearEndpoint(Device, Device->InEndpoint, PolledIo);
- if (!KSUCCESS(Status)) {
- goto ClearHaltsEnd;
- }
- Status = UsbMasspClearEndpoint(Device, Device->OutEndpoint, PolledIo);
- if (!KSUCCESS(Status)) {
- goto ClearHaltsEnd;
- }
- ClearHaltsEnd:
- return Status;
- }
- KSTATUS
- UsbMasspClearEndpoint (
- PUSB_MASS_STORAGE_DEVICE Device,
- UCHAR Endpoint,
- BOOL PolledIo
- )
- /*++
- Routine Description:
- This routine clears the HALT feature on an endpoint. It assumes that the
- device lock is held or polled I/O mode is requested.
- Arguments:
- Device - Supplies a pointer to the device whose IN endpoint needs to be
- cleared.
- Endpoint - Supplies the endpoint that needs to be cleared of the HALT
- feature. It should either be IN or OUT.
- PolledIo - Supplies a boolean indicating if the endpoint should be cleared
- using polled I/O.
- Return Value:
- Status code.
- --*/
- {
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ASSERT((PolledIo != FALSE) || (KeIsQueuedLockHeld(Device->Lock) != FALSE) ||
- (Device->LunCount == 0));
- if (PolledIo != FALSE) {
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_ENDPOINT_RECIPIENT |
- USB_SETUP_REQUEST_TO_DEVICE;
- SetupPacket.Request = USB_REQUEST_CLEAR_FEATURE;
- SetupPacket.Value = USB_FEATURE_ENDPOINT_HALT;
- SetupPacket.Index = Endpoint;
- SetupPacket.Length = 0;
- Status = UsbMasspSendPolledIoControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket);
- if (!KSUCCESS(Status)) {
- goto ClearEndpointEnd;
- }
- //
- // The endpoint needs to be reset. The USB core conveniently does this
- // automatically in the clear feature routine. But do it manually here.
- //
- Status = UsbResetEndpoint(Device->UsbCoreHandle, Endpoint);
- if (!KSUCCESS(Status)) {
- goto ClearEndpointEnd;
- }
- //
- // Otherwise, attempt to clear the HALT feature from the endpoint using the
- // built-in clear feature routine.
- //
- } else {
- Status = UsbClearFeature(Device->UsbCoreHandle,
- USB_SETUP_REQUEST_ENDPOINT_RECIPIENT,
- USB_FEATURE_ENDPOINT_HALT,
- Endpoint);
- if (!KSUCCESS(Status)) {
- goto ClearEndpointEnd;
- }
- }
- ClearEndpointEnd:
- return Status;
- }
- KSTATUS
- UsbMasspBlockIoInitialize (
- PVOID DiskToken
- )
- /*++
- Routine Description:
- This routine must be called before using the block read and write routines
- in order to allow the disk to prepare for block I/O. This must be called at
- low level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- Return Value:
- Status code.
- --*/
- {
- PUSB_MASS_STORAGE_DEVICE Device;
- PUSB_DISK Disk;
- PVOID OriginalState;
- PUSB_MASS_STORAGE_POLLED_IO_STATE PolledIoState;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Disk = (PUSB_DISK)DiskToken;
- Device = Disk->Device;
- //
- // If the device's polled I/O state is already present, then block I/O is
- // ready to go.
- //
- if (Device->PolledIoState != NULL) {
- return STATUS_SUCCESS;
- }
- PolledIoState = UsbMasspCreatePolledIoState(Device);
- if (PolledIoState == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto BlockIoInitializeEnd;
- }
- //
- // Try to put this new polled I/O state into the device structure.
- //
- OriginalState= (PVOID)RtlAtomicCompareExchange(
- (PUINTN)&(Device->PolledIoState),
- (UINTN)PolledIoState,
- (UINTN)NULL);
- if (OriginalState == NULL) {
- PolledIoState = NULL;
- }
- Status = STATUS_SUCCESS;
- BlockIoInitializeEnd:
- if (PolledIoState != NULL) {
- UsbMasspDestroyPolledIoState(PolledIoState);
- }
- return Status;
- }
- KSTATUS
- UsbMasspBlockIoRead (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- )
- /*++
- Routine Description:
- This routine reads the block contents from the disk into the given I/O
- buffer using polled I/O. It does so without acquiring any locks or
- allocating any resources, as this routine is used for crash dump support
- when the system is in a very fragile state. This routine must be called at
- high level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- IoBuffer - Supplies a pointer to the I/O buffer where the data will be read.
- BlockAddress - Supplies the block index to read (for physical disk, this is
- the LBA).
- BlockCount - Supplies the number of blocks to read.
- BlocksCompleted - Supplies a pointer that receives the total number of
- blocks read.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DISK Disk;
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Disk = (PUSB_DISK)DiskToken;
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress << Disk->BlockShift;
- IrpReadWrite.IoSizeInBytes = BlockCount << Disk->BlockShift;
- Status = UsbMasspPerformPolledIo(&IrpReadWrite, Disk, FALSE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted >> Disk->BlockShift;
- return Status;
- }
- KSTATUS
- UsbMasspBlockIoWrite (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- )
- /*++
- Routine Description:
- This routine writes the contents of the given I/O buffer to the disk using
- polled I/O. It does so without acquiring any locks or allocating any
- resources, as this routine is used for crash dump support when the system
- is in a very fragile state. This routine must be called at high level.
- Arguments:
- DiskToken - Supplies an opaque token for the disk. The appropriate token is
- retrieved by querying the disk device information.
- IoBuffer - Supplies a pointer to the I/O buffer containing the data to
- write.
- BlockAddress - Supplies the block index to write to (for physical disk,
- this is the LBA).
- BlockCount - Supplies the number of blocks to write.
- BlocksCompleted - Supplies a pointer that receives the total number of
- blocks written.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DISK Disk;
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- Disk = (PUSB_DISK)DiskToken;
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress << Disk->BlockShift;
- IrpReadWrite.IoSizeInBytes = BlockCount << Disk->BlockShift;
- Status = UsbMasspPerformPolledIo(&IrpReadWrite, Disk, TRUE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted >> Disk->BlockShift;
- return Status;
- }
- KSTATUS
- UsbMasspPerformPolledIo (
- PIRP_READ_WRITE IrpReadWrite,
- PUSB_DISK Disk,
- BOOL Write
- )
- /*++
- Routine Description:
- This routine performs polled I/O data transfers to the given USB disk.
- Arguments:
- IrpReadWrite - Supplies a pointer to the IRP's read/write context.
- Disk - Supplies a pointer to a USB disk.
- Write - Supplies a boolean indicating if this is a read (FALSE) or write
- (TRUE) operation.
- Return Value:
- Status code.
- --*/
- {
- UINTN BlockCount;
- ULONGLONG BlockOffset;
- ULONG BytesCompleted;
- UINTN BytesRemaining;
- UINTN BytesThisRound;
- UCHAR Command;
- PUCHAR CommandBuffer;
- BOOL CommandIn;
- UCHAR CommandLength;
- KSTATUS CompletionStatus;
- PUSB_MASS_STORAGE_DEVICE Device;
- PIO_BUFFER_FRAGMENT Fragment;
- UINTN FragmentIndex;
- UINTN FragmentOffset;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- ULONG IrpReadWriteFlags;
- PHYSICAL_ADDRESS PhysicalAddress;
- BOOL ReadWriteIrpPrepared;
- KSTATUS Status;
- PUSB_TRANSFER UsbDataTransfer;
- PVOID VirtualAddress;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- ASSERT(IrpReadWrite->IoBuffer != NULL);
- IrpReadWrite->IoBytesCompleted = 0;
- Device = Disk->Device;
- ReadWriteIrpPrepared = FALSE;
- //
- // The polled I/O transfers better be initialized.
- //
- if (Device->PolledIoState == NULL) {
- ASSERT(Device->PolledIoState != NULL);
- Status = STATUS_NOT_INITIALIZED;
- goto PerformPolledIoEnd;
- }
- //
- // Perform a one-time reset of the I/O endpoints to prepare for the polled
- // I/O. This is necessary because there may be a CBW in flight and the
- // device won't like it if another CBW is sent before it has a chance to
- // finish with the CSW.
- //
- if (Device->PolledIoState->ResetRequired != FALSE) {
- Status = UsbMasspResetForPolledIo(Device);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- Device->PolledIoState->ResetRequired = FALSE;
- }
- //
- // Prepare for the I/O. This is not polled I/O in the normal sense, as
- // USB transfers are still handling the work. So do not note it as polled.
- //
- IrpReadWriteFlags = 0;
- if (Write != FALSE) {
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- Status = IoPrepareReadWriteIrp(IrpReadWrite,
- 1 << Disk->BlockShift,
- 0,
- MAX_ULONG,
- IrpReadWriteFlags);
- ASSERT(KSUCCESS(Status));
- ReadWriteIrpPrepared = TRUE;
- IoBuffer = IrpReadWrite->IoBuffer;
- Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE);
- ASSERT(KSUCCESS(Status));
- //
- // Find the starting fragment based on the current offset.
- //
- IoBufferOffset = MmGetIoBufferCurrentOffset(IoBuffer);
- FragmentIndex = 0;
- FragmentOffset = 0;
- while (IoBufferOffset != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = &(IoBuffer->Fragment[FragmentIndex]);
- if (IoBufferOffset < Fragment->Size) {
- FragmentOffset = IoBufferOffset;
- break;
- }
- IoBufferOffset -= Fragment->Size;
- FragmentIndex += 1;
- }
- //
- // Set up the transfer command.
- //
- if (Write == FALSE) {
- Command = SCSI_COMMAND_READ_10;
- CommandLength = SCSI_COMMAND_READ_10_SIZE;
- CommandIn = TRUE;
- UsbDataTransfer = Device->PolledIoState->IoTransfers.DataInTransfer;
- } else {
- Command = SCSI_COMMAND_WRITE_10;
- CommandLength = SCSI_COMMAND_WRITE_10_SIZE;
- CommandIn = FALSE;
- UsbDataTransfer = Device->PolledIoState->IoTransfers.DataOutTransfer;
- }
- //
- // Loop reading in or writing out each fragment in the I/O buffer.
- //
- BytesRemaining = IrpReadWrite->IoSizeInBytes;
- ASSERT(IS_ALIGNED(BytesRemaining, 1 << Disk->BlockShift) != FALSE);
- ASSERT(IS_ALIGNED(IrpReadWrite->IoOffset, 1 << Disk->BlockShift) != FALSE);
- BlockOffset = IrpReadWrite->IoOffset >> Disk->BlockShift;
- while (BytesRemaining != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = (PIO_BUFFER_FRAGMENT)&(IoBuffer->Fragment[FragmentIndex]);
- VirtualAddress = Fragment->VirtualAddress + FragmentOffset;
- PhysicalAddress = Fragment->PhysicalAddress + FragmentOffset;
- BytesThisRound = Fragment->Size - FragmentOffset;
- if (BytesRemaining < BytesThisRound) {
- BytesThisRound = BytesRemaining;
- }
- //
- // Transfer the rest of the fragment, but cap it to the max of what the
- // allocated USB transfer can do and on how many bytes have already been
- // transferred and/or need to be transferred.
- //
- if (BytesThisRound > USB_MASS_MAX_DATA_TRANSFER) {
- BytesThisRound = USB_MASS_MAX_DATA_TRANSFER;
- }
- ASSERT(BytesThisRound != 0);
- ASSERT(IS_ALIGNED(BytesThisRound, 1 << Disk->BlockShift) != FALSE);
- BlockCount = BytesThisRound >> Disk->BlockShift;
- ASSERT(BlockCount == (USHORT)BlockCount);
- ASSERT(BytesThisRound == (ULONG)BytesThisRound);
- //
- // Watch for doing I/O off the end of the device.
- //
- if ((BlockOffset >= Disk->BlockCount) ||
- ((BlockOffset + BlockCount) > Disk->BlockCount)) {
- Status = STATUS_OUT_OF_BOUNDS;
- goto PerformPolledIoEnd;
- }
- CommandBuffer = UsbMasspSetupCommand(Disk,
- Command,
- (ULONG)BytesThisRound,
- CommandLength,
- CommandIn,
- TRUE,
- VirtualAddress,
- PhysicalAddress);
- *CommandBuffer = Command;
- *(CommandBuffer + 1) = Disk->LunNumber << SCSI_COMMAND_LUN_SHIFT;
- *(CommandBuffer + 2) = (UCHAR)(BlockOffset >> 24);
- *(CommandBuffer + 3) = (UCHAR)(BlockOffset >> 16);
- *(CommandBuffer + 4) = (UCHAR)(BlockOffset >> 8);
- *(CommandBuffer + 5) = (UCHAR)BlockOffset;
- *(CommandBuffer + 7) = (UCHAR)(BlockCount >> 8);
- *(CommandBuffer + 8) = (UCHAR)BlockCount;
- UsbDataTransfer->Length = (ULONG)BytesThisRound;
- //
- // Send the command using polled I/O.
- //
- Status = UsbMasspSendPolledIoCommand(Disk, &BytesCompleted);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- if ((BytesCompleted >> Disk->BlockShift) != BlockCount) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto PerformPolledIoEnd;
- }
- FragmentOffset += BytesCompleted;
- if (FragmentOffset == Fragment->Size) {
- FragmentIndex += 1;
- FragmentOffset = 0;
- }
- BlockOffset += BlockCount;
- BytesRemaining -= BytesCompleted;
- IrpReadWrite->IoBytesCompleted += BytesCompleted;
- }
- Status = STATUS_SUCCESS;
- PerformPolledIoEnd:
- if (ReadWriteIrpPrepared != FALSE) {
- CompletionStatus = IoCompleteReadWriteIrp(IrpReadWrite,
- IrpReadWriteFlags);
- if (!KSUCCESS(CompletionStatus) && KSUCCESS(Status)) {
- Status = CompletionStatus;
- }
- }
- IrpReadWrite->NewIoOffset = IrpReadWrite->IoOffset +
- IrpReadWrite->IoBytesCompleted;
- return Status;
- }
- KSTATUS
- UsbMasspSendPolledIoCommand (
- PUSB_DISK Disk,
- PULONG BytesCompleted
- )
- /*++
- Routine Description:
- This routine sends the current polled I/O command to the USB mass storage
- device.
- Arguments:
- Disk - Supplies a pointer to a USB disk.
- BytesCompleted - Supplies a pointer where the number of completed bytes
- will be returned.
- Return Value:
- Status code.
- --*/
- {
- PUSB_TRANSFER DataTransfer;
- KSTATUS Status;
- PUSB_MASS_STORAGE_TRANSFERS Transfers;
- ASSERT(Disk->Device->PolledIoState != NULL);
- Transfers = &(Disk->Device->PolledIoState->IoTransfers);
- //
- // Submit the command transfer.
- //
- Status = UsbSubmitPolledTransfer(Transfers->CommandTransfer);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- //
- // Submit the data transfer if there is any data. Ignore failures here as
- // the command status transfer is expected given that command block
- // transfer succeeded.
- //
- DataTransfer = NULL;
- if (Transfers->DataInTransfer->Length != 0) {
- ASSERT(Transfers->DataOutTransfer->Length == 0);
- DataTransfer = Transfers->DataInTransfer;
- } else if (Transfers->DataOutTransfer->Length != 0) {
- DataTransfer = Transfers->DataOutTransfer;
- }
- if (DataTransfer != NULL) {
- UsbSubmitPolledTransfer(DataTransfer);
- }
- //
- // Always submit the command status transfer. Ignore status here too.
- //
- UsbSubmitPolledTransfer(Transfers->StatusTransfer);
- PerformPolledIoEnd:
- //
- // Now analyze the status from the transfer to see if it worked.
- //
- Status = UsbMasspEvaluateCommandStatus(Disk, TRUE, TRUE, BytesCompleted);
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("USBMASS: Polled I/O failed 0x%08x.\n", Status);
- }
- return Status;
- }
- KSTATUS
- UsbMasspResetForPolledIo (
- PUSB_MASS_STORAGE_DEVICE Device
- )
- /*++
- Routine Description:
- This routine resets the USB Mass storage device to which the given disk is
- attached in preparation for polled I/O operations. This includes halting
- any in-flight transfers and performing reset recovery.
- Arguments:
- Device - Supplies a pointer to the USB device to be reset.
- Return Value:
- Status code.
- --*/
- {
- ULONG ControlTransfers;
- ULONG DataInTransfers;
- ULONG DataOutTransfers;
- KSTATUS Status;
- Status = UsbFlushEndpoint(Device->UsbCoreHandle, 0, &ControlTransfers);
- if (!KSUCCESS(Status)) {
- goto ResetForPolledIoEnd;
- }
- Status = UsbFlushEndpoint(Device->UsbCoreHandle,
- Device->InEndpoint,
- &DataInTransfers);
- if (!KSUCCESS(Status)) {
- goto ResetForPolledIoEnd;
- }
- Status = UsbFlushEndpoint(Device->UsbCoreHandle,
- Device->OutEndpoint,
- &DataOutTransfers);
- if (!KSUCCESS(Status)) {
- goto ResetForPolledIoEnd;
- }
- Status = UsbMasspResetRecovery(Device, TRUE);
- if (!KSUCCESS(Status)) {
- goto ResetForPolledIoEnd;
- }
- ResetForPolledIoEnd:
- return Status;
- }
- KSTATUS
- UsbMasspSendPolledIoControlTransfer (
- PUSB_MASS_STORAGE_DEVICE Device,
- USB_TRANSFER_DIRECTION TransferDirection,
- PUSB_SETUP_PACKET SetupPacket
- )
- /*++
- Routine Description:
- This routine sends a control transfer to the given USB mass storage device
- using polled I/O.
- Arguments:
- Device - Supplies a pointer to the USB mass storage device to talk to.
- TransferDirection - Supplies whether or not the transfer is to the device
- or to the host.
- SetupPacket - Supplies a pointer to the setup packet.
- Return Value:
- Stats code.
- --*/
- {
- PIO_BUFFER IoBuffer;
- KSTATUS Status;
- PUSB_TRANSFER Transfer;
- PVOID TransferBuffer;
- //
- // This routine is only meant to be used at high run level.
- //
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- //
- // The polled I/O device state must be present.
- //
- if (Device->PolledIoState == NULL) {
- ASSERT(Device->PolledIoState != NULL);
- return STATUS_NOT_INITIALIZED;
- }
- Transfer = Device->PolledIoState->ControlTransfer;
- ASSERT(Transfer != NULL);
- ASSERT(TransferDirection != UsbTransferDirectionInvalid);
- //
- // Borrow the polled I/O state's command I/O buffer. It should not be in
- // use right now.
- //
- IoBuffer = Device->PolledIoState->IoTransfers.CommandBuffer;
- ASSERT(IoBuffer->FragmentCount == 1);
- TransferBuffer = IoBuffer->Fragment[0].VirtualAddress;
- RtlCopyMemory(TransferBuffer, SetupPacket, sizeof(USB_SETUP_PACKET));
- //
- // Initialize the USB transfer.
- //
- Transfer->Direction = TransferDirection;
- Transfer->Length = sizeof(USB_SETUP_PACKET);
- Transfer->Buffer = TransferBuffer;
- Transfer->BufferPhysicalAddress = IoBuffer->Fragment[0].PhysicalAddress;
- Transfer->BufferActualLength = IoBuffer->Fragment[0].Size;
- //
- // Submit the transfer via polled I/O and wait for it to complete.
- //
- Status = UsbSubmitPolledTransfer(Transfer);
- if (!KSUCCESS(Status)) {
- goto SendPolledIoControlTransferEnd;
- }
- ASSERT(KSUCCESS(Transfer->Status));
- //
- // Copy the results into the caller's buffer.
- //
- ASSERT(Transfer->LengthTransferred >= sizeof(USB_SETUP_PACKET));
- Status = STATUS_SUCCESS;
- SendPolledIoControlTransferEnd:
- return Status;
- }
|