1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- ata.c
- Abstract:
- This module implements the AT Attachment (ATA) driver.
- Author:
- Evan Green 4-Jun-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/intrface/disk.h>
- #include <minoca/intrface/pci.h>
- #include "ata.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro returns the correct time counter function depending on whether
- // the operation is occurring in critical mode or not.
- //
- #define ATA_GET_TIME_FUNCTION(_CriticalMode) \
- ((_CriticalMode) ? HlQueryTimeCounter : KeGetRecentTimeCounter)
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef
- ULONGLONG
- (*PATA_QUERY_TIME_COUNTER) (
- VOID
- );
- /*++
- Routine Description:
- This routine returns snap of the time counter.
- Arguments:
- None.
- Return Value:
- Returns a snap of the time counter.
- --*/
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- AtapServiceInterruptForChannel (
- PATA_CHANNEL Channel,
- ULONG PendingBits
- );
- KSTATUS
- AtaAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- AtaDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- AtaDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- AtaDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- AtaDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- AtaDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- INTERRUPT_STATUS
- AtaInterruptService (
- PVOID Context
- );
- INTERRUPT_STATUS
- AtaInterruptServiceDpc (
- PVOID Context
- );
- VOID
- AtapDispatchControllerStateChange (
- PIRP Irp,
- PATA_CONTROLLER Controller
- );
- VOID
- AtapDispatchChildStateChange (
- PIRP Irp,
- PATA_CHILD Child
- );
- VOID
- AtapDispatchChildSystemControl (
- PIRP Irp,
- PATA_CHILD Device
- );
- KSTATUS
- AtapProcessResourceRequirements (
- PIRP Irp,
- PATA_CONTROLLER Controller
- );
- KSTATUS
- AtapStartController (
- PIRP Irp,
- PATA_CONTROLLER Controller
- );
- KSTATUS
- AtapResetController (
- PATA_CONTROLLER Controller
- );
- VOID
- AtapEnumerateDrives (
- PIRP Irp,
- PATA_CONTROLLER Controller
- );
- KSTATUS
- AtapIdentifyDevice (
- PATA_CHILD Device
- );
- KSTATUS
- AtapPerformDmaIo (
- PIRP Irp,
- PATA_CHILD Device,
- BOOL HaveDpcLock
- );
- KSTATUS
- AtapPerformPolledIo (
- PIRP_READ_WRITE Irp,
- PATA_CHILD Device,
- BOOL Write,
- BOOL CriticalMode
- );
- KSTATUS
- AtapSynchronizeDevice (
- PATA_CHILD Device
- );
- KSTATUS
- AtapBlockRead (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- AtapBlockWrite (
- PVOID DiskToken,
- PIO_BUFFER IoBuffer,
- ULONGLONG BlockAddress,
- UINTN BlockCount,
- PUINTN BlocksCompleted
- );
- KSTATUS
- AtapReadWriteSectorsPio (
- PATA_CHILD AtaDevice,
- ULONGLONG BlockAddress,
- UINTN SectorCount,
- PVOID Buffer,
- BOOL Write,
- BOOL CriticalMode
- );
- KSTATUS
- AtapPioCommand (
- PATA_CHILD Device,
- ATA_COMMAND Command,
- BOOL Lba48,
- BOOL Write,
- ULONG Features,
- ULONGLONG Lba,
- PVOID Buffer,
- ULONG SectorCount,
- ULONG MultiCount,
- BOOL CriticalMode
- );
- KSTATUS
- AtapExecuteCacheFlush (
- PATA_CHILD Child,
- BOOL CriticalMode
- );
- KSTATUS
- AtapSelectDevice (
- PATA_CHILD Device,
- BOOL CriticalMode
- );
- VOID
- AtapSetupCommand (
- PATA_CHILD Device,
- BOOL Lba48,
- ULONG FeaturesRegister,
- ULONG SectorCountRegister,
- ULONGLONG Lba,
- ULONG DeviceControl
- );
- VOID
- AtapStall (
- PATA_CHANNEL Channel
- );
- UCHAR
- AtapReadRegister (
- PATA_CHANNEL Channel,
- ATA_REGISTER Register
- );
- VOID
- AtapWriteRegister (
- PATA_CHANNEL Channel,
- ATA_REGISTER Register,
- UCHAR Value
- );
- VOID
- AtapProcessPciConfigInterfaceChangeNotification (
- PVOID Context,
- PDEVICE Device,
- PVOID InterfaceBuffer,
- ULONG InterfaceBufferSize,
- BOOL Arrival
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER AtaDriver = NULL;
- UUID AtaPciConfigurationInterfaceUuid = UUID_PCI_CONFIG_ACCESS;
- UUID AtaDiskInterfaceUuid = UUID_DISK_INTERFACE;
- DISK_INTERFACE AtaDiskInterfaceTemplate = {
- DISK_INTERFACE_VERSION,
- NULL,
- ATA_SECTOR_SIZE,
- 0,
- NULL,
- NULL,
- AtapBlockRead,
- AtapBlockWrite
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the ATA driver. It registers its 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;
- AtaDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = AtaAddDevice;
- FunctionTable.DispatchStateChange = AtaDispatchStateChange;
- FunctionTable.DispatchOpen = AtaDispatchOpen;
- FunctionTable.DispatchClose = AtaDispatchClose;
- FunctionTable.DispatchIo = AtaDispatchIo;
- FunctionTable.DispatchSystemControl = AtaDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- AtaAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a device is detected for which the ATA device
- 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.
- --*/
- {
- PATA_CONTROLLER Controller;
- UINTN Index;
- ULONG IoBufferFlags;
- PVOID Prdt;
- PHYSICAL_ADDRESS PrdtPhysical;
- KSTATUS Status;
- Controller = MmAllocateNonPagedPool(sizeof(ATA_CONTROLLER),
- ATA_ALLOCATION_TAG);
- if (Controller == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- RtlZeroMemory(Controller, sizeof(ATA_CONTROLLER));
- KeInitializeSpinLock(&(Controller->DpcLock));
- Controller->Type = AtaControllerContext;
- Controller->PrimaryInterruptHandle = INVALID_HANDLE;
- Controller->SecondaryInterruptHandle = INVALID_HANDLE;
- //
- // Allocate a page for the PRDT.
- //
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS |
- IO_BUFFER_FLAG_MAP_NON_CACHED;
- Controller->PrdtIoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- ATA_PRDT_TOTAL_SIZE,
- ATA_PRDT_TOTAL_SIZE,
- IoBufferFlags);
- if (Controller->PrdtIoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- ASSERT(Controller->PrdtIoBuffer->FragmentCount == 1);
- Prdt = Controller->PrdtIoBuffer->Fragment[0].VirtualAddress;
- PrdtPhysical = Controller->PrdtIoBuffer->Fragment[0].PhysicalAddress;
- //
- // Initialize the two channels, and then the four child contexts.
- //
- for (Index = 0; Index < ATA_CABLE_COUNT; Index += 1) {
- Controller->Channel[Index].Lock = KeCreateQueuedLock();
- if (Controller->Channel[Index].Lock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- Controller->Channel[Index].SelectedDevice = 0xFF;
- Controller->Channel[Index].Prdt = Prdt;
- Controller->Channel[Index].PrdtPhysicalAddress = PrdtPhysical;
- Prdt += ATA_PRDT_DISK_SIZE;
- PrdtPhysical += ATA_PRDT_DISK_SIZE;
- }
- for (Index = 0; Index < ATA_CHILD_COUNT; Index += 1) {
- Controller->ChildContexts[Index].Type = AtaChildContext;
- Controller->ChildContexts[Index].Controller = Controller;
- Controller->ChildContexts[Index].Channel =
- &(Controller->Channel[Index >> 1]);
- if ((Index & 0x1) != 0) {
- Controller->ChildContexts[Index].Slave = ATA_DRIVE_SELECT_SLAVE;
- } else {
- Controller->ChildContexts[Index].Slave = ATA_DRIVE_SELECT_MASTER;
- }
- }
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Controller);
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- Status = STATUS_SUCCESS;
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Controller != NULL) {
- for (Index = 0; Index < ATA_CABLE_COUNT; Index += 1) {
- if (Controller->Channel[Index].Lock != NULL) {
- KeDestroyQueuedLock(Controller->Channel[Index].Lock);
- }
- }
- if (Controller->PrdtIoBuffer != NULL) {
- MmFreeIoBuffer(Controller->PrdtIoBuffer);
- }
- MmFreeNonPagedPool(Controller);
- }
- }
- return Status;
- }
- VOID
- AtaDispatchStateChange (
- 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.
- --*/
- {
- PATA_CONTROLLER Controller;
- Controller = DeviceContext;
- switch (Controller->Type) {
- case AtaControllerContext:
- AtapDispatchControllerStateChange(Irp, Controller);
- break;
- case AtaChildContext:
- AtapDispatchChildStateChange(Irp, (PATA_CHILD)Controller);
- break;
- default:
- ASSERT(FALSE);
- IoCompleteIrp(AtaDriver, Irp, STATUS_INVALID_CONFIGURATION);
- break;
- }
- return;
- }
- VOID
- AtaDispatchOpen (
- 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.
- --*/
- {
- PATA_CHILD Disk;
- //
- // Only the disk can be opened or closed.
- //
- Disk = (PATA_CHILD)DeviceContext;
- if (Disk->Type != AtaChildContext) {
- return;
- }
- Irp->U.Open.DeviceContext = Disk;
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- AtaDispatchClose (
- 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.
- --*/
- {
- PATA_CHILD Disk;
- //
- // Only the disk can be opened or closed.
- //
- Disk = (PATA_CHILD)DeviceContext;
- if (Disk->Type != AtaChildContext) {
- return;
- }
- Irp->U.Open.DeviceContext = Disk;
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- return;
- }
- VOID
- AtaDispatchIo (
- 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;
- PATA_CHILD Device;
- ULONG IrpReadWriteFlags;
- BOOL PmReferenceAdded;
- KSTATUS Status;
- BOOL Write;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- Device = (PATA_CHILD)Irp->U.ReadWrite.DeviceContext;
- if (Device->Type != AtaChildContext) {
- return;
- }
- CompleteIrp = TRUE;
- Write = FALSE;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- Write = TRUE;
- }
- //
- // If this IRP is on the way down, always add a power management reference.
- //
- PmReferenceAdded = FALSE;
- if (Irp->Direction == IrpDown) {
- Status = PmDeviceAddReference(Device->OsDevice);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- PmReferenceAdded = TRUE;
- }
- //
- // Polled I/O is shared by a few code paths and prepares the IRP for I/O
- // further down the stack. It should also only be hit in the down direction
- // path as it always completes the IRP.
- //
- if (Device->DmaSupported == FALSE) {
- ASSERT(Irp->Direction == IrpDown);
- Status = AtapPerformPolledIo(&(Irp->U.ReadWrite), Device, Write, FALSE);
- goto DispatchIoEnd;
- }
- //
- // Set the IRP read/write flags for the preparation and completion steps.
- //
- IrpReadWriteFlags = IRP_READ_WRITE_FLAG_DMA;
- if (Write != FALSE) {
- 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 == IrpUp) {
- CompleteIrp = FALSE;
- ASSERT(Irp == Device->Channel->Irp);
- ASSERT(Device == Device->Channel->OwningChild);
- ASSERT(KeIsQueuedLockHeld(Device->Channel->Lock) != FALSE);
- Device->Channel->OwningChild = NULL;
- Device->Channel->Irp = NULL;
- KeReleaseQueuedLock(Device->Channel->Lock);
- PmDeviceReleaseReference(Device->OsDevice);
- Status = IoCompleteReadWriteIrp(&(Irp->U.ReadWrite), IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- IoUpdateIrpStatus(Irp, Status);
- }
- //
- // Start the DMA on the way down.
- //
- } else {
- Irp->U.ReadWrite.NewIoOffset = Irp->U.ReadWrite.IoOffset;
- //
- // Before acquiring the channel's lock and starting the DMA, prepare
- // the I/O context for ATA (i.e. it must use physical addresses that
- // are less than 4GB and be sector size aligned).
- //
- Status = IoPrepareReadWriteIrp(&(Irp->U.ReadWrite),
- ATA_SECTOR_SIZE,
- 0,
- MAX_ULONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- //
- // Fire off the DMA. If this succeeds, it will have pended the IRP.
- // Return with the lock held.
- //
- KeAcquireQueuedLock(Device->Channel->Lock);
- Device->Channel->Irp = Irp;
- Device->Channel->OwningChild = Device;
- CompleteIrp = FALSE;
- Status = AtapPerformDmaIo(Irp, Device, FALSE);
- if (!KSUCCESS(Status)) {
- Device->Channel->OwningChild = NULL;
- Device->Channel->Irp = NULL;
- KeReleaseQueuedLock(Device->Channel->Lock);
- IoCompleteReadWriteIrp(&(Irp->U.ReadWrite), IrpReadWriteFlags);
- CompleteIrp = TRUE;
- }
- }
- DispatchIoEnd:
- if (CompleteIrp != FALSE) {
- if (PmReferenceAdded != FALSE) {
- PmDeviceReleaseReference(Device->OsDevice);
- }
- IoCompleteIrp(AtaDriver, Irp, Status);
- }
- return;
- }
- VOID
- AtaDispatchSystemControl (
- 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.
- --*/
- {
- PATA_CHILD Child;
- ASSERT(Irp->MajorCode == IrpMajorSystemControl);
- Child = (PATA_CHILD)DeviceContext;
- if (Child->Type == AtaChildContext) {
- AtapDispatchChildSystemControl(Irp, Child);
- }
- return;
- }
- INTERRUPT_STATUS
- AtaInterruptService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the ATA interrupt service routine.
- Arguments:
- Context - Supplies the context pointer given to the system when the
- interrupt was connected. In this case, this points to the ATA
- controller.
- Return Value:
- Interrupt status.
- --*/
- {
- ULONG BusMasterStatus;
- PATA_CONTROLLER Controller;
- INTERRUPT_STATUS InterruptStatus;
- InterruptStatus = InterruptStatusNotClaimed;
- Controller = (PATA_CONTROLLER)Context;
- //
- // Check the primary channel's bus master status.
- //
- BusMasterStatus = AtapReadRegister(&(Controller->Channel[0]),
- AtaRegisterBusMasterStatus);
- BusMasterStatus &= IDE_STATUS_INTERRUPT | IDE_STATUS_ERROR;
- if (BusMasterStatus != 0) {
- AtapWriteRegister(&(Controller->Channel[0]),
- AtaRegisterBusMasterStatus,
- BusMasterStatus);
- AtapWriteRegister(&(Controller->Channel[0]),
- AtaRegisterBusMasterCommand,
- 0);
- //
- // Try the secondary one.
- //
- } else {
- BusMasterStatus = AtapReadRegister(&(Controller->Channel[1]),
- AtaRegisterBusMasterStatus);
- BusMasterStatus &= IDE_STATUS_INTERRUPT | IDE_STATUS_ERROR;
- if (BusMasterStatus != 0) {
- AtapWriteRegister(&(Controller->Channel[1]),
- AtaRegisterBusMasterStatus,
- BusMasterStatus);
- AtapWriteRegister(&(Controller->Channel[1]),
- AtaRegisterBusMasterCommand,
- 0);
- BusMasterStatus <<= BITS_PER_BYTE;
- }
- }
- if (BusMasterStatus != 0) {
- RtlAtomicOr32(&(Controller->PendingStatusBits), BusMasterStatus);
- InterruptStatus = InterruptStatusClaimed;
- }
- return InterruptStatus;
- }
- INTERRUPT_STATUS
- AtaInterruptServiceDpc (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements the ATA dispatch-level interrupt service routine.
- Arguments:
- Context - Supplies the context pointer given to the system when the
- interrupt was connected. In this case, this points to the ATA
- controller.
- Return Value:
- Interrupt status.
- --*/
- {
- UCHAR BusMasterMask;
- PATA_CONTROLLER Device;
- ULONG PendingBits;
- Device = (PATA_CONTROLLER)Context;
- //
- // Clear out the pending bits.
- //
- PendingBits = RtlAtomicExchange32(&(Device->PendingStatusBits), 0);
- if (PendingBits == 0) {
- return InterruptStatusNotClaimed;
- }
- KeAcquireSpinLock(&(Device->DpcLock));
- //
- // Handle the primary controller.
- //
- BusMasterMask = IDE_STATUS_ERROR | IDE_STATUS_INTERRUPT;
- if ((PendingBits & BusMasterMask) != 0) {
- AtapServiceInterruptForChannel(&(Device->Channel[0]),
- PendingBits & BusMasterMask);
- }
- //
- // Handle the secondary controller.
- //
- PendingBits >>= 8;
- if ((PendingBits & BusMasterMask) != 0) {
- AtapServiceInterruptForChannel(&(Device->Channel[1]),
- PendingBits & BusMasterMask);
- }
- KeReleaseSpinLock(&(Device->DpcLock));
- return InterruptStatusClaimed;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- AtapServiceInterruptForChannel (
- PATA_CHANNEL Channel,
- ULONG PendingBits
- )
- /*++
- Routine Description:
- This routine services an interrupt for a given ATA channel.
- Arguments:
- Channel - Supplies a pointer to the channel.
- PendingBits - Supplies the pending bitmask.
- Return Value:
- None.
- --*/
- {
- BOOL CompleteIrp;
- UINTN IoSize;
- PIRP Irp;
- KSTATUS Status;
- UCHAR StatusRegister;
- Irp = Channel->Irp;
- if ((Irp != NULL) && (PendingBits != 0) && (Channel->IoSize != 0)) {
- IoSize = Channel->IoSize;
- Channel->IoSize = 0;
- Status = STATUS_SUCCESS;
- CompleteIrp = FALSE;
- StatusRegister = AtapReadRegister(Channel, AtaRegisterStatus);
- if (((PendingBits & IDE_STATUS_ERROR) != 0) ||
- ((StatusRegister & ATA_STATUS_ERROR_MASK) != 0)) {
- RtlDebugPrint("ATA: I/O Error: Status %x, BMStatus %x.\n",
- StatusRegister,
- PendingBits);
- Status = STATUS_DEVICE_IO_ERROR;
- CompleteIrp = FALSE;
- } else if ((PendingBits & IDE_STATUS_INTERRUPT) != 0) {
- CompleteIrp = TRUE;
- ASSERT(Irp->MajorCode == IrpMajorIo);
- Irp->U.ReadWrite.IoBytesCompleted += IoSize;
- Irp->U.ReadWrite.NewIoOffset += IoSize;
- ASSERT(Irp->U.ReadWrite.IoBytesCompleted <=
- Irp->U.ReadWrite.IoSizeInBytes);
- if (Irp->U.ReadWrite.IoBytesCompleted !=
- Irp->U.ReadWrite.IoSizeInBytes) {
- Status = AtapPerformDmaIo(Irp, Channel->OwningChild, TRUE);
- if (KSUCCESS(Status)) {
- CompleteIrp = FALSE;
- }
- }
- }
- if (CompleteIrp != FALSE) {
- //
- // If this is a synchronized write, then send a cache flush
- // command along with it.
- //
- if ((Status == STATUS_SUCCESS) &&
- (Irp->MinorCode == IrpMinorIoWrite) &&
- ((Irp->U.ReadWrite.IoFlags & IO_FLAG_DATA_SYNCHRONIZED) != 0)) {
- Status = AtapExecuteCacheFlush(Channel->OwningChild, FALSE);
- ASSERT(KSUCCESS(Status));
- }
- //
- // If successful, the I/O should be completed fully.
- //
- ASSERT((!KSUCCESS(Status)) ||
- (Irp->U.ReadWrite.IoBytesCompleted ==
- Irp->U.ReadWrite.IoSizeInBytes));
- //
- // Complete the IRP but do not release the lock as the channel is
- // cleaned up by this driver after the IRP is reversed to the up
- // direction. This allows it to perform said clean up at low level.
- //
- IoCompleteIrp(AtaDriver, Irp, Status);
- }
- }
- return;
- }
- VOID
- AtapDispatchControllerStateChange (
- PIRP Irp,
- PATA_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine handles state change IRPs for an ATA controller.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Controller - Supplies a pointer to the controller context.
- Return Value:
- None. The routine completes the IRP if appropriate.
- --*/
- {
- KSTATUS Status;
- if (Irp->Direction == IrpUp) {
- if (!KSUCCESS(IoGetIrpStatus(Irp))) {
- return;
- }
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- Status = AtapProcessResourceRequirements(Irp, Controller);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(AtaDriver, Irp, Status);
- }
- break;
- case IrpMinorStartDevice:
- Status = AtapStartController(Irp, Controller);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(AtaDriver, Irp, Status);
- }
- break;
- case IrpMinorQueryChildren:
- AtapEnumerateDrives(Irp, Controller);
- break;
- case IrpMinorIdle:
- case IrpMinorSuspend:
- case IrpMinorResume:
- default:
- break;
- }
- }
- return;
- }
- VOID
- AtapDispatchChildStateChange (
- PIRP Irp,
- PATA_CHILD Child
- )
- /*++
- Routine Description:
- This routine handles state change IRPs for an ATA child device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Child - Supplies a pointer to the child device.
- Return Value:
- None. The routine completes the IRP if appropriate.
- --*/
- {
- KSTATUS Status;
- if (Irp->Direction == IrpDown) {
- switch (Irp->MinorCode) {
- case IrpMinorStartDevice:
- Child->OsDevice = Irp->Device;
- Status = PmInitialize(Irp->Device);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(AtaDriver, Irp, Status);
- break;
- }
- //
- // Publish the disk interface.
- //
- RtlCopyMemory(&(Child->DiskInterface),
- &AtaDiskInterfaceTemplate,
- sizeof(DISK_INTERFACE));
- Status = STATUS_SUCCESS;
- if (Child->DiskInterface.DiskToken == NULL) {
- Child->DiskInterface.DiskToken = Child;
- Child->DiskInterface.BlockCount = Child->TotalSectors;
- Status = IoCreateInterface(&AtaDiskInterfaceUuid,
- Irp->Device,
- &(Child->DiskInterface),
- sizeof(DISK_INTERFACE));
- if (!KSUCCESS(Status)) {
- Child->DiskInterface.DiskToken = NULL;
- }
- }
- IoCompleteIrp(AtaDriver, Irp, Status);
- break;
- case IrpMinorQueryResources:
- case IrpMinorQueryChildren:
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorIdle:
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorSuspend:
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorResume:
- IoCompleteIrp(AtaDriver, Irp, STATUS_SUCCESS);
- break;
- default:
- break;
- }
- }
- return;
- }
- VOID
- AtapDispatchChildSystemControl (
- PIRP Irp,
- PATA_CHILD Device
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs for an ATA child device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- PVOID Context;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- 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;
- Properties->BlockSize = ATA_SECTOR_SIZE;
- Properties->BlockCount = Device->TotalSectors;
- WRITE_INT64_SYNC(&(Properties->FileSize),
- Device->TotalSectors * ATA_SECTOR_SIZE);
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(AtaDriver, 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);
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectBlockDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != ATA_SECTOR_SIZE) ||
- (Properties->BlockCount != Device->TotalSectors) ||
- (PropertiesFileSize != (Device->TotalSectors * ATA_SECTOR_SIZE))) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(AtaDriver, Irp, Status);
- break;
- //
- // Do not support hard disk device truncation.
- //
- case IrpMinorSystemControlTruncate:
- IoCompleteIrp(AtaDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- //
- // Gather and return device information.
- //
- case IrpMinorSystemControlDeviceInformation:
- break;
- //
- // Send a cache flush command to the device upon getting a synchronize
- // request.
- //
- case IrpMinorSystemControlSynchronize:
- Status = PmDeviceAddReference(Device->OsDevice);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(AtaDriver, Irp, Status);
- break;
- }
- Status = AtapSynchronizeDevice(Device);
- PmDeviceReleaseReference(Device->OsDevice);
- IoCompleteIrp(AtaDriver, Irp, Status);
- break;
- //
- // Ignore everything unrecognized.
- //
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- KSTATUS
- AtapProcessResourceRequirements (
- PIRP Irp,
- PATA_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine filters through the resource requirements presented by the
- bus for an ATA controller. It adds an interrupt vector requirement for
- any interrupt line requested.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Controller - Supplies a pointer to the ATA controller.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG Interface;
- RESOURCE_REQUIREMENT LegacyRequirement;
- ULONGLONG LineCharacteristics;
- PRESOURCE_REQUIREMENT NewRequirement;
- BOOL PrimaryLegacy;
- PRESOURCE_REQUIREMENT Requirement;
- PRESOURCE_REQUIREMENT_LIST RequirementList;
- PRESOURCE_CONFIGURATION_LIST Requirements;
- BOOL SecondaryLegacy;
- KSTATUS Status;
- ULONGLONG VectorCharacteristics;
- RESOURCE_REQUIREMENT VectorRequirement;
- ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
- (Irp->MinorCode == IrpMinorQueryResources));
- Requirements = Irp->U.QueryResources.ResourceRequirements;
- if (Requirements == NULL) {
- Status = STATUS_NOT_CONFIGURED;
- goto ProcessResourceRequirementsEnd;
- }
- RequirementList = IoGetNextResourceConfiguration(Requirements, NULL);
- //
- // Start listening for a PCI config interface.
- //
- if (Controller->RegisteredForPciConfigInterfaces == FALSE) {
- Status = IoRegisterForInterfaceNotifications(
- &AtaPciConfigurationInterfaceUuid,
- AtapProcessPciConfigInterfaceChangeNotification,
- Irp->Device,
- Controller,
- TRUE);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- Controller->RegisteredForPciConfigInterfaces = TRUE;
- }
- //
- // Try to read the interface from PCI.
- //
- if (Controller->PciConfigInterfaceAvailable == FALSE) {
- Status = STATUS_NOT_CONFIGURED;
- goto ProcessResourceRequirementsEnd;
- }
- Status = Controller->PciConfigInterface.ReadPciConfig(
- Controller->PciConfigInterface.DeviceToken,
- IDE_INTERFACE_OFFSET,
- IDE_INTERFACE_SIZE,
- &Interface);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- Controller->Interface = Interface;
- //
- // Look to see if the interface is in native or legacy mode.
- //
- PrimaryLegacy = TRUE;
- SecondaryLegacy = TRUE;
- if ((Interface & IDE_INTERFACE_PRIMARY_NATIVE_SUPPORTED) != 0) {
- if ((Interface & IDE_INTERFACE_PRIMARY_NATIVE_ENABLED) != 0) {
- PrimaryLegacy = FALSE;
- }
- }
- if ((Interface & IDE_INTERFACE_SECONDARY_NATIVE_SUPPORTED) != 0) {
- if ((Interface & IDE_INTERFACE_SECONDARY_NATIVE_ENABLED) != 0) {
- SecondaryLegacy = FALSE;
- }
- }
- //
- // Add the primary legacy region if this controller is using that.
- //
- if (PrimaryLegacy != FALSE) {
- RtlZeroMemory(&LegacyRequirement, sizeof(RESOURCE_REQUIREMENT));
- LegacyRequirement.Type = ResourceTypeIoPort;
- LegacyRequirement.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- LegacyRequirement.Minimum = ATA_LEGACY_PRIMARY_IO_BASE;
- LegacyRequirement.Length = ATA_LEGACY_IO_SIZE;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum +
- LegacyRequirement.Length;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- LegacyRequirement.Minimum = ATA_LEGACY_PRIMARY_CONTROL_BASE;
- LegacyRequirement.Length = ATA_LEGACY_CONTROL_SIZE;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum +
- LegacyRequirement.Length;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- }
- //
- // Add the secondary legacy region if this controller is using that.
- //
- if (SecondaryLegacy != FALSE) {
- RtlZeroMemory(&LegacyRequirement, sizeof(RESOURCE_REQUIREMENT));
- LegacyRequirement.Type = ResourceTypeIoPort;
- LegacyRequirement.Flags = RESOURCE_FLAG_NOT_SHAREABLE;
- LegacyRequirement.Minimum = ATA_LEGACY_SECONDARY_IO_BASE;
- LegacyRequirement.Length = ATA_LEGACY_IO_SIZE;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum +
- LegacyRequirement.Length;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- LegacyRequirement.Minimum = ATA_LEGACY_SECONDARY_CONTROL_BASE;
- LegacyRequirement.Length = ATA_LEGACY_CONTROL_SIZE;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum +
- LegacyRequirement.Length;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- }
- //
- // Initialize a nice interrupt vector requirement in preparation.
- //
- RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
- VectorRequirement.Type = ResourceTypeInterruptVector;
- VectorRequirement.Minimum = 0;
- VectorRequirement.Maximum = -1;
- VectorRequirement.Length = 1;
- //
- // Loop through all configuration lists adding a vector for each line.
- //
- while (RequirementList != NULL) {
- //
- // Loop through every requirement in the list.
- //
- Requirement = IoGetNextResourceRequirement(RequirementList, NULL);
- while (Requirement != NULL) {
- //
- // If the requirement is an interrupt line, then add a requirement
- // for a vector as well. If legacy vectors are going to be added,
- // then just remember there's an extra interrupt line there.
- //
- if (Requirement->Type == ResourceTypeInterruptLine) {
- if ((PrimaryLegacy == FALSE) || (SecondaryLegacy == FALSE)) {
- VectorCharacteristics = 0;
- LineCharacteristics = Requirement->Characteristics;
- if ((LineCharacteristics &
- INTERRUPT_LINE_ACTIVE_LOW) != 0) {
- VectorCharacteristics |= INTERRUPT_VECTOR_ACTIVE_LOW;
- }
- if ((LineCharacteristics &
- INTERRUPT_LINE_EDGE_TRIGGERED) != 0) {
- VectorCharacteristics |=
- INTERRUPT_VECTOR_EDGE_TRIGGERED;
- }
- VectorRequirement.Characteristics = VectorCharacteristics;
- VectorRequirement.OwningRequirement = Requirement;
- Status = IoCreateAndAddResourceRequirement(
- &VectorRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- } else {
- Controller->SkipFirstInterrupt = TRUE;
- }
- }
- //
- // Get the next resource requirement.
- //
- Requirement = IoGetNextResourceRequirement(RequirementList,
- Requirement);
- }
- //
- // Get the next possible resource configuration.
- //
- RequirementList = IoGetNextResourceConfiguration(Requirements,
- RequirementList);
- }
- //
- // If in legacy mode, add the legacy interrupts.
- //
- if ((SecondaryLegacy != FALSE) && (PrimaryLegacy != FALSE)) {
- RequirementList = IoGetNextResourceConfiguration(Requirements, NULL);
- ASSERT(RequirementList != NULL);
- LegacyRequirement.Type = ResourceTypeInterruptLine;
- LegacyRequirement.Minimum = ATA_LEGACY_PRIMARY_INTERRUPT;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum + 1;
- LegacyRequirement.Length = 1;
- LegacyRequirement.Characteristics =
- ATA_LEGACY_INTERRUPT_CHARACTERISTICS;
- LegacyRequirement.Flags = 0;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- &NewRequirement);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- VectorRequirement.Flags |= RESOURCE_FLAG_NOT_SHAREABLE;
- VectorRequirement.Characteristics = ATA_LEGACY_VECTOR_CHARACTERISTICS;
- VectorRequirement.OwningRequirement = NewRequirement;
- Status = IoCreateAndAddResourceRequirement(&VectorRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- LegacyRequirement.Minimum = ATA_LEGACY_SECONDARY_INTERRUPT;
- LegacyRequirement.Maximum = LegacyRequirement.Minimum + 1;
- Status = IoCreateAndAddResourceRequirement(&LegacyRequirement,
- RequirementList,
- &NewRequirement);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- VectorRequirement.OwningRequirement = NewRequirement;
- Status = IoCreateAndAddResourceRequirement(&VectorRequirement,
- RequirementList,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ProcessResourceRequirementsEnd;
- }
- }
- Status = STATUS_SUCCESS;
- ProcessResourceRequirementsEnd:
- return Status;
- }
- KSTATUS
- AtapStartController (
- PIRP Irp,
- PATA_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine starts an ATA controller device.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Controller - Supplies a pointer to the ATA controller.
- Return Value:
- Status code.
- --*/
- {
- PRESOURCE_ALLOCATION Allocation;
- PRESOURCE_ALLOCATION_LIST AllocationList;
- IO_CONNECT_INTERRUPT_PARAMETERS Connect;
- UINTN Index;
- BOOL LineSkipped;
- BOOL PrimaryInterruptConnected;
- BOOL SecondaryInterruptConnected;
- KSTATUS Status;
- PRESOURCE_ALLOCATION VectorAllocation;
- PrimaryInterruptConnected = Controller->PrimaryInterruptFound;
- SecondaryInterruptConnected = Controller->SecondaryInterruptFound;
- for (Index = 0; Index < ATA_CABLE_COUNT; Index += 1) {
- Controller->Channel[Index].IoBase = -1;
- Controller->Channel[Index].ControlBase = -1;
- Controller->Channel[Index].BusMasterBase = -1;
- }
- Index = 0;
- LineSkipped = FALSE;
- Status = PmInitialize(Irp->Device);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- Status = PmDeviceAddReference(Irp->Device);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- //
- // Loop through the allocated resources to get the controller base and the
- // interrupt.
- //
- VectorAllocation = NULL;
- AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
- Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
- while (Allocation != NULL) {
- //
- // If the resource is an interrupt line, search for the next interrupt
- // vector.
- //
- if (Allocation->Type == ResourceTypeInterruptLine) {
- if ((LineSkipped == FALSE) &&
- (Controller->SkipFirstInterrupt != FALSE)) {
- LineSkipped = TRUE;
- } else {
- VectorAllocation = IoGetNextResourceAllocation(
- AllocationList,
- VectorAllocation);
- while (VectorAllocation != NULL) {
- if (VectorAllocation->Type == ResourceTypeInterruptVector) {
- ASSERT(VectorAllocation->OwningAllocation ==
- Allocation);
- if (Controller->PrimaryInterruptFound == FALSE) {
- Controller->PrimaryInterruptLine =
- Allocation->Allocation;
- Controller->PrimaryInterruptVector =
- VectorAllocation->Allocation;
- Controller->PrimaryInterruptFound = TRUE;
- } else if (Controller->SecondaryInterruptFound ==
- FALSE) {
- Controller->SecondaryInterruptLine =
- Allocation->Allocation;
- Controller->SecondaryInterruptVector =
- VectorAllocation->Allocation;
- Controller->SecondaryInterruptFound = TRUE;
- } else {
- //
- // There shouldn't be more than two interrupts to
- // connect.
- //
- ASSERT(FALSE);
- }
- break;
- }
- VectorAllocation = IoGetNextResourceAllocation(
- AllocationList,
- VectorAllocation);
- }
- }
- } else if (Allocation->Type == ResourceTypeIoPort) {
- ASSERT(Allocation->Allocation < MAX_USHORT);
- switch (Index) {
- case 0:
- if (Allocation->Length >= 8) {
- Controller->Channel[0].IoBase = Allocation->Allocation;
- }
- break;
- case 1:
- if (Allocation->Length >= 4) {
- Controller->Channel[0].ControlBase =
- Allocation->Allocation + 2;
- }
- break;
- case 2:
- if (Allocation->Length >= 8) {
- Controller->Channel[1].IoBase = Allocation->Allocation;
- }
- break;
- case 3:
- if (Allocation->Length >= 4) {
- Controller->Channel[1].ControlBase =
- Allocation->Allocation + 2;
- }
- break;
- case 4:
- if (Allocation->Length >= 16) {
- Controller->Channel[0].BusMasterBase =
- Allocation->Allocation;
- Controller->Channel[1].BusMasterBase =
- Allocation->Allocation + 8;
- }
- break;
- }
- Index += 1;
- } else if (Allocation->Type == ResourceTypePhysicalAddressSpace) {
- Index += 1;
- }
- //
- // Get the next allocation in the list.
- //
- Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
- }
- //
- // Assign the legacy register locations if needed.
- //
- if ((Controller->Interface & IDE_INTERFACE_PRIMARY_NATIVE_ENABLED) == 0) {
- Controller->Channel[0].IoBase = ATA_LEGACY_PRIMARY_IO_BASE;
- Controller->Channel[0].ControlBase = ATA_LEGACY_PRIMARY_CONTROL_BASE;
- }
- if ((Controller->Interface & IDE_INTERFACE_SECONDARY_NATIVE_ENABLED) == 0) {
- Controller->Channel[1].IoBase = ATA_LEGACY_SECONDARY_IO_BASE;
- Controller->Channel[1].ControlBase = ATA_LEGACY_SECONDARY_CONTROL_BASE;
- }
- //
- // Put the controller into a known state.
- //
- Status = AtapResetController(Controller);
- if (!KSUCCESS(Status)) {
- goto StartControllerEnd;
- }
- RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
- Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
- Connect.Device = Irp->Device;
- Connect.InterruptServiceRoutine = AtaInterruptService;
- Connect.DispatchServiceRoutine = AtaInterruptServiceDpc;
- Connect.Context = Controller;
- if ((PrimaryInterruptConnected == FALSE) &&
- (Controller->PrimaryInterruptFound != FALSE) &&
- (Controller->Channel[0].BusMasterBase != (USHORT)-1)) {
- Connect.LineNumber = Controller->PrimaryInterruptLine;
- Connect.Vector = Controller->PrimaryInterruptVector;
- Connect.Interrupt = &(Controller->PrimaryInterruptHandle);
- Status = IoConnectInterrupt(&Connect);
- if (!KSUCCESS(Status)) {
- goto StartControllerEnd;
- }
- }
- if ((SecondaryInterruptConnected == FALSE) &&
- (Controller->SecondaryInterruptFound != FALSE) &&
- (Controller->Channel[1].BusMasterBase != (USHORT)-1)) {
- Connect.LineNumber = Controller->SecondaryInterruptLine;
- Connect.Vector = Controller->SecondaryInterruptVector;
- Connect.Interrupt = &(Controller->SecondaryInterruptHandle);
- Status = IoConnectInterrupt(&Connect);
- if (!KSUCCESS(Status)) {
- goto StartControllerEnd;
- }
- }
- Status = STATUS_SUCCESS;
- StartControllerEnd:
- PmDeviceReleaseReference(Irp->Device);
- return Status;
- }
- KSTATUS
- AtapResetController (
- PATA_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine resets an ATA controller device.
- Arguments:
- Controller - Supplies a pointer to the ATA controller.
- Return Value:
- Status code.
- --*/
- {
- //
- // Disable interrupts.
- //
- Controller->Channel[0].InterruptDisable = ATA_CONTROL_INTERRUPT_DISABLE;
- Controller->Channel[1].InterruptDisable = ATA_CONTROL_INTERRUPT_DISABLE;
- HlBusySpin(2 * MICROSECONDS_PER_MILLISECOND);
- AtapWriteRegister(&(Controller->Channel[0]),
- AtaRegisterControl,
- Controller->Channel[0].InterruptDisable);
- AtapReadRegister(&(Controller->Channel[0]), AtaRegisterStatus);
- if (Controller->Channel[0].BusMasterBase != (USHORT)-1) {
- AtapWriteRegister(&(Controller->Channel[0]),
- AtaRegisterBusMasterStatus,
- IDE_STATUS_INTERRUPT | IDE_STATUS_ERROR);
- AtapWriteRegister(&(Controller->Channel[0]),
- AtaRegisterBusMasterCommand,
- 0);
- }
- if (Controller->Channel[1].IoBase != (USHORT)-1) {
- HlBusySpin(2 * MICROSECONDS_PER_MILLISECOND);
- AtapWriteRegister(&(Controller->Channel[1]),
- AtaRegisterControl,
- Controller->Channel[1].InterruptDisable);
- AtapReadRegister(&(Controller->Channel[1]), AtaRegisterStatus);
- if (Controller->Channel[1].BusMasterBase != (USHORT)-1) {
- AtapWriteRegister(&(Controller->Channel[1]),
- AtaRegisterBusMasterStatus,
- IDE_STATUS_INTERRUPT | IDE_STATUS_ERROR);
- AtapWriteRegister(&(Controller->Channel[1]),
- AtaRegisterBusMasterCommand,
- 0);
- }
- }
- return STATUS_SUCCESS;
- }
- VOID
- AtapEnumerateDrives (
- PIRP Irp,
- PATA_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine enumerates all drives on an ATA controller.
- Arguments:
- Irp - Supplies a pointer to the query children IRP.
- Controller - Supplies a pointer to the ATA controller.
- Return Value:
- None.
- --*/
- {
- PATA_CHILD Child;
- ULONG ChildCount;
- UINTN ChildIndex;
- PDEVICE Children[4];
- KSTATUS Status;
- Status = PmDeviceAddReference(Irp->Device);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(AtaDriver, Irp, Status);
- return;
- }
- ChildCount = 0;
- for (ChildIndex = 0; ChildIndex < ATA_CHILD_COUNT; ChildIndex += 1) {
- Child = &(Controller->ChildContexts[ChildIndex]);
- Status = AtapIdentifyDevice(Child);
- if (!KSUCCESS(Status)) {
- Controller->ChildDevices[ChildIndex] = NULL;
- } else {
- if (Controller->ChildDevices[ChildIndex] == NULL) {
- Status = IoCreateDevice(
- AtaDriver,
- Child,
- Irp->Device,
- "Disk",
- DISK_CLASS_ID,
- NULL,
- &(Controller->ChildDevices[ChildIndex]));
- if (!KSUCCESS(Status)) {
- Controller->ChildDevices[ChildIndex] = NULL;
- }
- }
- }
- if (Controller->ChildDevices[ChildIndex] != NULL) {
- Children[ChildCount] = Controller->ChildDevices[ChildIndex];
- ChildCount += 1;
- }
- }
- if (ChildCount != 0) {
- Status = IoMergeChildArrays(Irp,
- Children,
- ChildCount,
- ATA_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto EnumerateDrivesEnd;
- }
- }
- Status = STATUS_SUCCESS;
- EnumerateDrivesEnd:
- PmDeviceReleaseReference(Irp->Device);
- IoCompleteIrp(AtaDriver, Irp, Status);
- return;
- }
- KSTATUS
- AtapIdentifyDevice (
- PATA_CHILD Device
- )
- /*++
- Routine Description:
- This routine attempts to send the IDENTIFY packet command and process the
- results.
- Arguments:
- Device - Supplies a pointer to the child device to query.
- Return Value:
- Status code.
- --*/
- {
- ATA_IDENTIFY_PACKET Identify;
- UCHAR Lba1;
- UCHAR Lba2;
- KSTATUS Status;
- if (Device->Channel->IoBase == (USHORT)-1) {
- return STATUS_NO_SUCH_DEVICE;
- }
- Device->DmaSupported = FALSE;
- Status = AtapPioCommand(Device,
- AtaCommandIdentify,
- FALSE,
- FALSE,
- 0,
- 0,
- &Identify,
- 0,
- 0,
- FALSE);
- if (!KSUCCESS(Status)) {
- //
- // If the identify command failed, check out LBA1 and LBA2 to see if
- // they're responding like an ATAPI device.
- //
- Lba1 = AtapReadRegister(Device->Channel, AtaRegisterLba1);
- Lba2 = AtapReadRegister(Device->Channel, AtaRegisterLba2);
- if (((Lba1 == ATA_PATAPI_LBA1) && (Lba2 == ATA_PATAPI_LBA2)) ||
- ((Lba1 == ATA_PATAPI_LBA1) && (Lba2 == ATA_PATAPI_LBA2))) {
- //
- // TODO: ATAPI devices.
- //
- } else if ((Lba1 == ATA_SATA_LBA1) && (Lba2 == ATA_SATA_LBA2)) {
- RtlDebugPrint("TODO: SATA\n");
- }
- goto IdentifyDeviceEnd;
- }
- //
- // Get the total capacity of the disk.
- //
- if ((Identify.CommandSetSupported & ATA_SUPPORTED_COMMAND_LBA48) != 0) {
- Device->TotalSectors = Identify.TotalSectorsLba48;
- } else {
- Device->TotalSectors = Identify.TotalSectors;
- }
- //
- // Determine whether or not to do DMA to this device.
- //
- if ((Device->Channel->BusMasterBase != (USHORT)-1) &&
- (Identify.UltraDmaSettings != 0)) {
- Device->DmaSupported = TRUE;
- }
- IdentifyDeviceEnd:
- return Status;
- }
- KSTATUS
- AtapPerformDmaIo (
- PIRP Irp,
- PATA_CHILD Device,
- BOOL HaveDpcLock
- )
- /*++
- Routine Description:
- This routine starts a DMA-based I/O transfer. This routine assumes the
- channel lock is already held.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- Device - Supplies a pointer to the ATA child device.
- HaveDpcLock - Supplies a boolean indicating if the caller already has the
- DPC lock acquired.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG BlockAddress;
- UINTN BytesPreviouslyCompleted;
- UINTN BytesToComplete;
- ATA_COMMAND Command;
- UCHAR DmaCommand;
- PHYSICAL_ADDRESS EndBoundary;
- ULONG EntrySize;
- PIO_BUFFER_FRAGMENT Fragment;
- UINTN FragmentIndex;
- UINTN FragmentOffset;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- IO_OFFSET IoOffset;
- BOOL Lba48;
- UINTN MaxTransferSize;
- RUNLEVEL OldRunLevel;
- PHYSICAL_ADDRESS PhysicalAddress;
- PATA_PRDT Prdt;
- USHORT PrdtAddressRegister;
- UINTN PrdtIndex;
- UINTN SectorCount;
- KSTATUS Status;
- UINTN TransferSize;
- UINTN TransferSizeRemaining;
- BOOL Write;
- ASSERT(Device->Channel->Irp == Irp);
- ASSERT(Device->Channel->OwningChild == Device);
- ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
- IoBuffer = Irp->U.ReadWrite.IoBuffer;
- BytesPreviouslyCompleted = Irp->U.ReadWrite.IoBytesCompleted;
- BytesToComplete = Irp->U.ReadWrite.IoSizeInBytes;
- IoOffset = Irp->U.ReadWrite.NewIoOffset;
- ASSERT(BytesPreviouslyCompleted < BytesToComplete);
- ASSERT(IoOffset == (Irp->U.ReadWrite.IoOffset + BytesPreviouslyCompleted));
- ASSERT(Device->Channel->BusMasterBase != (USHORT)-1);
- ASSERT(IS_ALIGNED(IoOffset, ATA_SECTOR_SIZE) != FALSE);
- ASSERT(IS_ALIGNED(BytesToComplete, ATA_SECTOR_SIZE) != FALSE);
- Write = FALSE;
- if (Irp->MinorCode == IrpMinorIoWrite) {
- Write = TRUE;
- }
- //
- // Determine the bytes to complete this round.
- //
- MaxTransferSize = ATA_MAX_LBA48_SECTOR_COUNT * ATA_SECTOR_SIZE;
- if (Device->Lba48Supported == FALSE) {
- MaxTransferSize = ATA_MAX_LBA28_SECTOR_COUNT * ATA_SECTOR_SIZE;
- }
- TransferSize = BytesToComplete - BytesPreviouslyCompleted;
- if (TransferSize > MaxTransferSize) {
- TransferSize = MaxTransferSize;
- }
- //
- // Get to the currect spot in the I/O buffer.
- //
- IoBufferOffset = MmGetIoBufferCurrentOffset(IoBuffer);
- IoBufferOffset += BytesPreviouslyCompleted;
- 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;
- }
- //
- // Loop over every fragment in the I/O buffer setting up PRDT entries.
- //
- Prdt = Device->Channel->Prdt;
- PrdtIndex = 0;
- TransferSizeRemaining = TransferSize;
- while ((TransferSizeRemaining != 0) &&
- (PrdtIndex < (ATA_PRDT_DISK_SIZE / sizeof(ATA_PRDT)))) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = &(IoBuffer->Fragment[FragmentIndex]);
- ASSERT(IS_ALIGNED(Fragment->Size, ATA_SECTOR_SIZE) != FALSE);
- ASSERT(IS_ALIGNED(FragmentOffset, ATA_SECTOR_SIZE) != FALSE);
- //
- // Determine the size of the PRDT entry.
- //
- EntrySize = TransferSizeRemaining;
- if (EntrySize > (Fragment->Size - FragmentOffset)) {
- EntrySize = Fragment->Size - FragmentOffset;
- }
- PhysicalAddress = Fragment->PhysicalAddress + FragmentOffset;
- EndBoundary = ALIGN_RANGE_DOWN(PhysicalAddress + EntrySize - 1,
- ATA_DMA_BOUNDARY);
- if (ALIGN_RANGE_DOWN(PhysicalAddress, ATA_DMA_BOUNDARY) !=
- EndBoundary) {
- EntrySize =
- ALIGN_RANGE_UP(PhysicalAddress + 1, ATA_DMA_BOUNDARY) -
- PhysicalAddress;
- }
- TransferSizeRemaining -= EntrySize;
- //
- // ATA can only DMA to lower 4GB addresses.
- //
- ASSERT(IS_ALIGNED(PhysicalAddress, ATA_SECTOR_SIZE) != FALSE);
- ASSERT(PhysicalAddress == (ULONG)PhysicalAddress);
- ASSERT((PhysicalAddress + EntrySize) ==
- (ULONG)(PhysicalAddress + EntrySize));
- Prdt->PhysicalAddress = PhysicalAddress;
- if (EntrySize == ATA_DMA_BOUNDARY) {
- Prdt->Size = 0;
- } else {
- Prdt->Size = EntrySize;
- }
- Prdt->Flags = 0;
- Prdt += 1;
- PrdtIndex += 1;
- FragmentOffset += EntrySize;
- if (FragmentOffset >= Fragment->Size) {
- FragmentIndex += 1;
- FragmentOffset = 0;
- }
- }
- ASSERT(PrdtIndex != 0);
- Prdt -= 1;
- Prdt->Flags |= ATA_DMA_LAST_DESCRIPTOR;
- TransferSize -= TransferSizeRemaining;
- BlockAddress = IoOffset / ATA_SECTOR_SIZE;
- SectorCount = TransferSize / ATA_SECTOR_SIZE;
- ASSERT(SectorCount == (ULONG)SectorCount);
- //
- // Use LBA48 if the block address is too high or the sector size is too
- // large.
- //
- if ((BlockAddress > ATA_MAX_LBA28) ||
- (SectorCount > ATA_MAX_LBA28_SECTOR_COUNT)) {
- Lba48 = TRUE;
- if (Write != FALSE) {
- Command = AtaCommandWriteDma48;
- } else {
- Command = AtaCommandReadDma48;
- }
- } else {
- Lba48 = FALSE;
- if (Write != FALSE) {
- Command = AtaCommandWriteDma28;
- } else {
- Command = AtaCommandReadDma28;
- }
- if (SectorCount == ATA_MAX_LBA28_SECTOR_COUNT) {
- SectorCount = 0;
- }
- }
- Status = AtapSelectDevice(Device, FALSE);
- if (!KSUCCESS(Status)) {
- goto PerformDmaIoEnd;
- }
- //
- // Set up the usual registers for a command.
- //
- AtapSetupCommand(Device, Lba48, 0, (ULONG)SectorCount, BlockAddress, 0);
- if (HaveDpcLock == FALSE) {
- OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
- KeAcquireSpinLock(&(Device->Controller->DpcLock));
- }
- //
- // Enable interrupts and start the command.
- //
- Device->Channel->IoSize = TransferSize;
- Device->Channel->InterruptDisable = 0;
- AtapWriteRegister(Device->Channel, AtaRegisterControl, 0);
- AtapWriteRegister(Device->Channel, AtaRegisterCommand, Command);
- //
- // Write the PRDT base address.
- //
- PrdtAddressRegister = Device->Channel->BusMasterBase +
- ATA_BUS_MASTER_TABLE_REGISTER;
- HlIoPortOutLong(PrdtAddressRegister,
- Device->Channel->PrdtPhysicalAddress);
- //
- // Start the DMA.
- //
- DmaCommand = ATA_BUS_MASTER_COMMAND_DMA_ENABLE;
- if (Write == FALSE) {
- DmaCommand |= ATA_BUS_MASTER_COMMAND_DMA_READ;
- }
- //
- // If this is the first set of DMA for the IRP, pend it.
- //
- if (BytesPreviouslyCompleted == 0) {
- IoPendIrp(AtaDriver, Irp);
- }
- AtapWriteRegister(Device->Channel,
- AtaRegisterBusMasterStatus,
- IDE_STATUS_INTERRUPT | IDE_STATUS_ERROR);
- AtapWriteRegister(Device->Channel, AtaRegisterBusMasterCommand, DmaCommand);
- if (HaveDpcLock == FALSE) {
- KeReleaseSpinLock(&(Device->Controller->DpcLock));
- KeLowerRunLevel(OldRunLevel);
- }
- Status = STATUS_SUCCESS;
- PerformDmaIoEnd:
- return Status;
- }
- KSTATUS
- AtapPerformPolledIo (
- PIRP_READ_WRITE IrpReadWrite,
- PATA_CHILD Device,
- BOOL Write,
- BOOL CriticalMode
- )
- /*++
- Routine Description:
- This routine performs polled I/O data transfers.
- Arguments:
- IrpReadWrite - Supplies a pointer to the I/O request read/write packet.
- Device - Supplies a pointer to the ATA child device.
- Write - Supplies a boolean indicating if this is a read operation (TRUE) or
- a write operation (FALSE).
- CriticalMode - Supplies a boolean indicating if this I/O operation is in
- a critical code path (TRUE), such as a crash dump I/O request, or in
- the default code path.
- Return Value:
- Status code.
- --*/
- {
- UINTN BlockCount;
- ULONGLONG BlockOffset;
- UINTN BytesRemaining;
- UINTN BytesThisRound;
- KSTATUS CompletionStatus;
- PIO_BUFFER_FRAGMENT Fragment;
- UINTN FragmentIndex;
- UINTN FragmentOffset;
- PIO_BUFFER IoBuffer;
- UINTN IoBufferOffset;
- ULONG IrpReadWriteFlags;
- BOOL ReadWriteIrpPrepared;
- KSTATUS Status;
- PVOID VirtualAddress;
- IrpReadWrite->IoBytesCompleted = 0;
- ReadWriteIrpPrepared = FALSE;
- //
- // All requests should be block aligned.
- //
- ASSERT(IrpReadWrite->IoBuffer != NULL);
- ASSERT(IS_ALIGNED(IrpReadWrite->IoSizeInBytes, ATA_SECTOR_SIZE) != FALSE);
- ASSERT(IS_ALIGNED(IrpReadWrite->IoOffset, ATA_SECTOR_SIZE) != FALSE);
- //
- // Prepare the I/O buffer for the polled I/O operation.
- //
- IrpReadWriteFlags = IRP_READ_WRITE_FLAG_POLLED;
- if (Write != FALSE) {
- IrpReadWriteFlags |= IRP_READ_WRITE_FLAG_WRITE;
- }
- Status = IoPrepareReadWriteIrp(IrpReadWrite,
- ATA_SECTOR_SIZE,
- 0,
- MAX_ULONGLONG,
- IrpReadWriteFlags);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- ReadWriteIrpPrepared = TRUE;
- //
- // Make sure the I/O buffer is mapped before use. ATA currently depends on
- // the buffer being mapped.
- //
- IoBuffer = IrpReadWrite->IoBuffer;
- Status = MmMapIoBuffer(IoBuffer, FALSE, FALSE, FALSE);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- //
- // 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;
- }
- //
- // Loop reading in or writing out each fragment in the I/O buffer.
- //
- BlockOffset = IrpReadWrite->IoOffset / ATA_SECTOR_SIZE;
- BytesRemaining = IrpReadWrite->IoSizeInBytes;
- while (BytesRemaining != 0) {
- ASSERT(FragmentIndex < IoBuffer->FragmentCount);
- Fragment = (PIO_BUFFER_FRAGMENT)&(IoBuffer->Fragment[FragmentIndex]);
- VirtualAddress = Fragment->VirtualAddress + FragmentOffset;
- BytesThisRound = Fragment->Size - FragmentOffset;
- if (BytesRemaining < BytesThisRound) {
- BytesThisRound = BytesRemaining;
- }
- ASSERT(IS_ALIGNED(BytesThisRound, ATA_SECTOR_SIZE) != FALSE);
- BlockCount = BytesThisRound / ATA_SECTOR_SIZE;
- //
- // Make sure the system isn't trying to do I/O off the end of the disk.
- //
- ASSERT(BlockOffset < Device->TotalSectors);
- ASSERT(BlockCount >= 1);
- Status = AtapReadWriteSectorsPio(Device,
- BlockOffset,
- BlockCount,
- VirtualAddress,
- Write,
- CriticalMode);
- if (!KSUCCESS(Status)) {
- goto PerformPolledIoEnd;
- }
- BlockOffset += BlockCount;
- BytesRemaining -= BytesThisRound;
- FragmentOffset += BytesThisRound;
- IrpReadWrite->IoBytesCompleted += BytesThisRound;
- if (FragmentOffset >= Fragment->Size) {
- FragmentIndex += 1;
- FragmentOffset = 0;
- }
- }
- 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
- AtapSynchronizeDevice (
- PATA_CHILD Device
- )
- /*++
- Routine Description:
- This routine synchronizes the device by sending a cache flush command.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- KeAcquireQueuedLock(Device->Channel->Lock);
- Status = AtapSelectDevice(Device, FALSE);
- if (KSUCCESS(Status)) {
- Status = AtapExecuteCacheFlush(Device, FALSE);
- }
- KeReleaseQueuedLock(Device->Channel->Lock);
- return Status;
- }
- KSTATUS
- AtapBlockRead (
- 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.
- --*/
- {
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- //
- // As this read routine is meant for critical code paths (crash dump),
- // indicate that the channel should not be locked when performing the I/O.
- // It may be that some other thread holds the lock, which would cause a
- // dead lock as all other processors and threads are likely frozen.
- //
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress * ATA_SECTOR_SIZE;
- IrpReadWrite.IoSizeInBytes = BlockCount * ATA_SECTOR_SIZE;
- Status = AtapPerformPolledIo(&IrpReadWrite, DiskToken, FALSE, TRUE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted / ATA_SECTOR_SIZE;
- return Status;
- }
- KSTATUS
- AtapBlockWrite (
- 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.
- --*/
- {
- IRP_READ_WRITE IrpReadWrite;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelHigh);
- //
- // As this write routine is meant for critical code paths (crash dump),
- // indicate that the channel should not be locked when performing the I/O.
- // It may be that some other thread holds the lock, which would cause a
- // dead lock as all other processors and threads are likely frozen.
- //
- IrpReadWrite.IoBuffer = IoBuffer;
- IrpReadWrite.IoOffset = BlockAddress * ATA_SECTOR_SIZE;
- IrpReadWrite.IoSizeInBytes = BlockCount * ATA_SECTOR_SIZE;
- Status = AtapPerformPolledIo(&IrpReadWrite, DiskToken, TRUE, TRUE);
- *BlocksCompleted = IrpReadWrite.IoBytesCompleted / ATA_SECTOR_SIZE;
- return Status;
- }
- KSTATUS
- AtapReadWriteSectorsPio (
- PATA_CHILD AtaDevice,
- ULONGLONG BlockAddress,
- UINTN SectorCount,
- PVOID Buffer,
- BOOL Write,
- BOOL CriticalMode
- )
- /*++
- Routine Description:
- This routine reads or writes a given number of sectors from the ATA disk
- using polled I/O.
- Arguments:
- AtaDevice - Supplies a pointer to the ATA disk's context.
- BlockAddress - Supplies the block number to read from or write to (LBA).
- SectorCount - Supplies the number of blocks (sectors) to read from or write
- to the device.
- Buffer - Supplies the data buffer where the data will be read or written.
- Write - Supplies a boolean indicating if this is a read operation (FALSE)
- or a write operation (TRUE).
- CriticalMode - Supplies a boolean indicating if this I/O operation is in
- a critical code path (TRUE), such as a crash dump I/O request, or in
- the default code path.
- Return Value:
- Status code.
- --*/
- {
- ATA_COMMAND Command;
- BOOL Lba48;
- UINTN SectorCountThisRound;
- KSTATUS Status;
- if (BlockAddress > ATA_MAX_LBA28) {
- Lba48 = TRUE;
- if (Write != FALSE) {
- Command = AtaCommandWritePio48;
- } else {
- Command = AtaCommandReadPio48;
- }
- } else {
- Lba48 = FALSE;
- if (Write != FALSE) {
- Command = AtaCommandWritePio28;
- } else {
- Command = AtaCommandReadPio28;
- }
- }
- Status = STATUS_SUCCESS;
- while (SectorCount != 0) {
- SectorCountThisRound = SectorCount;
- if (SectorCountThisRound > ATA_MAX_LBA28_SECTOR_COUNT) {
- SectorCountThisRound = ATA_MAX_LBA28_SECTOR_COUNT;
- }
- ASSERT(SectorCountThisRound == (ULONG)SectorCountThisRound);
- Status = AtapPioCommand(AtaDevice,
- Command,
- Lba48,
- Write,
- 0,
- BlockAddress,
- Buffer,
- (ULONG)SectorCountThisRound,
- 0,
- CriticalMode);
- if (!KSUCCESS(Status)) {
- goto ReadWriteSectorsPioEnd;
- }
- BlockAddress += SectorCountThisRound;
- Buffer += SectorCountThisRound * ATA_SECTOR_SIZE;
- SectorCount -= SectorCountThisRound;
- }
- ReadWriteSectorsPioEnd:
- return Status;
- }
- KSTATUS
- AtapPioCommand (
- PATA_CHILD Device,
- ATA_COMMAND Command,
- BOOL Lba48,
- BOOL Write,
- ULONG Features,
- ULONGLONG Lba,
- PVOID Buffer,
- ULONG SectorCount,
- ULONG MultiCount,
- BOOL CriticalMode
- )
- /*++
- Routine Description:
- This routine executes a data transfer using polled I/O.
- Arguments:
- Device - Supplies a pointer to the device to read from.
- Command - Supplies the ATA command to execute.
- Lba48 - Supplies a boolean indicating if LBA48 mode is in use.
- Write - Supplies a boolean indicating if this is a read PIO command (FALSE)
- or a write data PIO command (TRUE).
- Features - Supplies the contents of the feature register.
- Lba - Supplies the logical block address to read from.
- Buffer - Supplies a pointer to the buffer where the data will be returned.
- SectorCount - Supplies the sector count to program in to the command.
- The IDENTIFY and PACKET IDENTIFY commands have a known sector count of
- one, zero should be passed in for those.
- MultiCount - Supplies the value of the multicount register.
- CriticalMode - Supplies a boolean indicating if this I/O operation is in
- a critical code path (TRUE), such as a crash dump I/O request, or in
- the default code path.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_DEVICE_IO_ERROR if the device is unresponsive or has a failure.
- --*/
- {
- ULONG BusMasterStatus;
- ULONG ByteCount;
- ULONG BytesTransferred;
- PATA_CHANNEL Channel;
- PUSHORT CurrentBuffer;
- UCHAR DeviceStatus;
- PATA_QUERY_TIME_COUNTER QueryTimeCounter;
- KSTATUS Status;
- ULONGLONG Timeout;
- ASSERT(SectorCount <= ATA_MAX_LBA28_SECTOR_COUNT);
- CurrentBuffer = (PUSHORT)Buffer;
- Channel = Device->Channel;
- //
- // Lock the other device out.
- //
- QueryTimeCounter = ATA_GET_TIME_FUNCTION(CriticalMode);
- if (CriticalMode == FALSE) {
- KeAcquireQueuedLock(Channel->Lock);
- }
- //
- // Clear the error bit of the bus master status.
- //
- if (Channel->BusMasterBase != -1) {
- AtapWriteRegister(Channel,
- AtaRegisterBusMasterStatus,
- IDE_STATUS_ERROR);
- }
- //
- // Select the device.
- //
- Status = AtapSelectDevice(Device, CriticalMode);
- if (!KSUCCESS(Status)) {
- goto PioCommandEnd;
- }
- //
- // Set up all registers of the command except the command register itself.
- //
- AtapSetupCommand(Device,
- Lba48,
- Features,
- SectorCount,
- Lba,
- 0);
- //
- // Disable interrupts.
- //
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- ATA_CONTROL_INTERRUPT_DISABLE);
- if ((Command == AtaCommandIdentify) ||
- (Command == AtaCommandIdentifyPacket)) {
- SectorCount = 1;
- }
- //
- // Execute the command.
- //
- AtapWriteRegister(Channel, AtaRegisterCommand, (UCHAR)Command);
- AtapStall(Channel);
- //
- // This is the main read loop. The primary status register must not be read
- // more than once for each sector transferred, as reading the status
- // register clears the IRQ status. The alternate status register can be
- // read any number of times.
- //
- Timeout = QueryTimeCounter() +
- (HlQueryTimeCounterFrequency() * ATA_TIMEOUT);
- while (SectorCount != 0) {
- //
- // Read the status register once.
- //
- DeviceStatus = AtapReadRegister(Channel, AtaRegisterStatus);
- if ((Command == AtaCommandIdentify) && (DeviceStatus == 0)) {
- Status = STATUS_NO_SUCH_DEVICE;
- goto PioCommandEnd;
- }
- //
- // Fail if an error occurred.
- //
- if ((DeviceStatus & ATA_STATUS_ERROR_MASK) != 0) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto PioCommandEnd;
- }
- if (((DeviceStatus & ATA_STATUS_BUSY) != 0) ||
- ((DeviceStatus & ATA_STATUS_DATA_REQUEST) == 0)) {
- if (QueryTimeCounter() > Timeout) {
- Status = STATUS_TIMEOUT;
- goto PioCommandEnd;
- }
- continue;
- }
- //
- // If the device is ready, read or write the data.
- //
- if ((DeviceStatus & ATA_STATUS_BUSY_MASK) == ATA_STATUS_DATA_REQUEST) {
- ByteCount = ATA_SECTOR_SIZE;
- if (MultiCount != 0) {
- ByteCount = MultiCount * ATA_SECTOR_SIZE;
- }
- if (Write != FALSE) {
- for (BytesTransferred = 0;
- BytesTransferred < ByteCount;
- BytesTransferred += sizeof(USHORT)) {
- HlIoPortOutShort(Channel->IoBase + AtaRegisterData,
- *CurrentBuffer);
- CurrentBuffer += 1;
- }
- } else {
- for (BytesTransferred = 0;
- BytesTransferred < ByteCount;
- BytesTransferred += sizeof(USHORT)) {
- *CurrentBuffer =
- HlIoPortInShort(Channel->IoBase + AtaRegisterData);
- CurrentBuffer += 1;
- }
- }
- //
- // Stall to give the device a chance to settle.
- //
- AtapStall(Channel);
- if (MultiCount != 0) {
- ASSERT(SectorCount >= MultiCount);
- SectorCount -= MultiCount;
- } else {
- SectorCount -= 1;
- }
- }
- //
- // If this was the last sector, read the status register one more time.
- // If the error bits or data request is set, fail.
- //
- if (SectorCount == 0) {
- DeviceStatus = AtapReadRegister(Channel, AtaRegisterStatus);
- DeviceStatus &= ATA_STATUS_ERROR_MASK | ATA_STATUS_DATA_REQUEST;
- if (DeviceStatus != 0) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto PioCommandEnd;
- }
- }
- }
- //
- // Check the bus master status register.
- //
- if (Channel->BusMasterBase != -1) {
- BusMasterStatus = AtapReadRegister(Channel, AtaRegisterBusMasterStatus);
- if ((BusMasterStatus & IDE_STATUS_ERROR) != 0) {
- Status = STATUS_DEVICE_IO_ERROR;
- goto PioCommandEnd;
- }
- }
- //
- // Send a clean cache command if this was a polled I/O write.
- //
- Status = STATUS_SUCCESS;
- if (Write != FALSE) {
- Status = AtapExecuteCacheFlush(Device, CriticalMode);
- }
- PioCommandEnd:
- if (CriticalMode == FALSE) {
- KeReleaseQueuedLock(Channel->Lock);
- }
- return Status;
- }
- KSTATUS
- AtapExecuteCacheFlush (
- PATA_CHILD Child,
- BOOL CriticalMode
- )
- /*++
- Routine Description:
- This routine sends a cache flush command to the device. This routine
- assumes the lock is held and the device is selected.
- Arguments:
- Child - Supplies a pointer to the ATA child device.
- CriticalMode - Supplies a boolean indicating that the operation is
- operating in hostile conditions.
- Return Value:
- Status code.
- --*/
- {
- PATA_CHANNEL Channel;
- ATA_COMMAND Command;
- PATA_QUERY_TIME_COUNTER QueryTimeCounter;
- KSTATUS Status;
- UCHAR StatusRegister;
- ULONGLONG Timeout;
- Channel = Child->Channel;
- Command = AtaCommandCacheFlush28;
- QueryTimeCounter = ATA_GET_TIME_FUNCTION(CriticalMode);
- Timeout = QueryTimeCounter() +
- (HlQueryTimeCounterFrequency() * ATA_TIMEOUT);
- Status = STATUS_SUCCESS;
- AtapWriteRegister(Channel, AtaRegisterCommand, Command);
- AtapStall(Channel);
- while (TRUE) {
- StatusRegister = AtapReadRegister(Channel, AtaRegisterStatus);
- if ((StatusRegister & ATA_STATUS_ERROR_MASK) != 0) {
- Status = STATUS_DEVICE_IO_ERROR;
- break;
- }
- if ((StatusRegister & ATA_STATUS_BUSY_MASK) == 0) {
- break;
- }
- if (QueryTimeCounter() > Timeout) {
- Status = STATUS_TIMEOUT;
- break;
- }
- }
- if (!KSUCCESS(Status)) {
- RtlDebugPrint("ATA_CHILD %x failed cache flush: %x\n", Child, Status);
- }
- return Status;
- }
- KSTATUS
- AtapSelectDevice (
- PATA_CHILD Device,
- BOOL CriticalMode
- )
- /*++
- Routine Description:
- This routine selects the given ATA device in the hardware.
- Arguments:
- Device - Supplies a pointer to the device to select. The interface needs to
- be valid.
- CriticalMode - Supplies a boolean indicating if this I/O operation is in
- a critical code path (TRUE), such as a crash dump I/O request, or in
- the default code path.
- Return Value:
- Status code.
- --*/
- {
- PATA_CHANNEL Channel;
- UCHAR DeviceStatus;
- PATA_QUERY_TIME_COUNTER QueryTimeCounter;
- ULONGLONG Timeout;
- ULONGLONG TimeoutDuration;
- Channel = Device->Channel;
- if (Channel->SelectedDevice == Device->Slave) {
- return STATUS_SUCCESS;
- }
- //
- // Get the appropriate time counter routine. The recent time counter
- // requests do not work in critical mode, as interrupts are likely disabled.
- //
- if (CriticalMode != FALSE) {
- QueryTimeCounter = HlQueryTimeCounter;
- } else {
- QueryTimeCounter = KeGetRecentTimeCounter;
- }
- TimeoutDuration = KeConvertMicrosecondsToTimeTicks(ATA_SELECT_TIMEOUT);
- Timeout = QueryTimeCounter() + TimeoutDuration;
- //
- // Wait until whichever drive is currently selected to become not busy.
- //
- do {
- DeviceStatus = AtapReadRegister(Channel, AtaRegisterStatus);
- if ((DeviceStatus & ATA_STATUS_BUSY) == 0) {
- break;
- }
- } while (QueryTimeCounter() <= Timeout);
- if ((DeviceStatus & ATA_STATUS_BUSY) != 0) {
- return STATUS_TIMEOUT;
- }
- //
- // Select the device.
- //
- AtapWriteRegister(Channel, AtaRegisterDeviceSelect, Device->Slave);
- //
- // Wait for the device to become ready.
- //
- do {
- DeviceStatus = AtapReadRegister(Channel, AtaRegisterStatus);
- if (((DeviceStatus & ATA_STATUS_BUSY_MASK) == 0) &&
- ((DeviceStatus & ATA_STATUS_DRIVE_READY) != 0)) {
- break;
- }
- if ((DeviceStatus & ATA_STATUS_ERROR_MASK) != 0) {
- return STATUS_DEVICE_IO_ERROR;
- }
- } while (QueryTimeCounter() <= Timeout);
- if (((DeviceStatus & ATA_STATUS_BUSY_MASK) != 0) ||
- ((DeviceStatus & ATA_STATUS_DRIVE_READY) == 0)) {
- return STATUS_TIMEOUT;
- }
- Channel->SelectedDevice = Device->Slave;
- return STATUS_SUCCESS;
- }
- VOID
- AtapSetupCommand (
- PATA_CHILD Device,
- BOOL Lba48,
- ULONG FeaturesRegister,
- ULONG SectorCountRegister,
- ULONGLONG Lba,
- ULONG DeviceControl
- )
- /*++
- Routine Description:
- This routine writes all registers to the ATA interface, preparing it to
- execute a command. It does not write the command register, so the command
- is not executed.
- Arguments:
- Device - Supplies a pointer to the device.
- Lba48 - Supplies a boolean indicating if LBA48 mode is to be used.
- FeaturesRegister - Supplies the features register to write in.
- SectorCountRegister - Supplies the sector count register value to write.
- Lba - Supplies the logical block address value to write in the registers.
- DeviceControl - Supplies the device control value to write.
- Return Value:
- None.
- --*/
- {
- PATA_CHANNEL Channel;
- UCHAR DeviceSelect;
- Channel = Device->Channel;
- DeviceSelect = Device->Slave | ATA_DRIVE_SELECT_LBA;
- //
- // Device control is written the same way in all cases. All other registers
- // are written slightly differently depending on the LBA mode.
- //
- AtapWriteRegister(Channel, AtaRegisterControl, DeviceControl);
- //
- // Write LBA48 mode.
- //
- if (Lba48 != FALSE) {
- //
- // Gain access to the high order bytes. The register access functions
- // will also do this when writing to registers like LBA3, etc, but
- // doing this directly allows these registers to be written in a batch.
- //
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- ATA_CONTROL_HIGH_ORDER | Channel->InterruptDisable);
- AtapWriteRegister(Channel,
- AtaRegisterSectorCountLow,
- (UCHAR)(SectorCountRegister >> 8));
- AtapWriteRegister(Channel,
- AtaRegisterLba0,
- (UCHAR)(Lba >> 24));
- AtapWriteRegister(Channel,
- AtaRegisterLba1,
- (UCHAR)(Lba >> 32));
- AtapWriteRegister(Channel,
- AtaRegisterLba2,
- (UCHAR)(Lba >> 40));
- //
- // Back to the low registers.
- //
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- Channel->InterruptDisable);
- //
- // Use LBA28 mode.
- //
- } else {
- DeviceSelect |= (UCHAR)((Lba >> 24) & 0x0F);
- }
- AtapWriteRegister(Channel, AtaRegisterFeatures, FeaturesRegister);
- AtapWriteRegister(Channel,
- AtaRegisterSectorCountLow,
- (UCHAR)SectorCountRegister);
- AtapWriteRegister(Channel,
- AtaRegisterLba0,
- (UCHAR)(Lba & 0xFF));
- AtapWriteRegister(Channel,
- AtaRegisterLba1,
- (UCHAR)(Lba >> 8));
- AtapWriteRegister(Channel,
- AtaRegisterLba2,
- (UCHAR)(Lba >> 16));
- AtapWriteRegister(Channel,
- AtaRegisterDeviceSelect,
- DeviceSelect);
- return;
- }
- VOID
- AtapStall (
- PATA_CHANNEL Channel
- )
- /*++
- Routine Description:
- This routine stalls to give the ATA device time to settle.
- Arguments:
- Channel - Supplies a pointer to the channel.
- Return Value:
- None.
- --*/
- {
- AtapReadRegister(Channel, AtaRegisterAlternateStatus);
- AtapReadRegister(Channel, AtaRegisterAlternateStatus);
- AtapReadRegister(Channel, AtaRegisterAlternateStatus);
- AtapReadRegister(Channel, AtaRegisterAlternateStatus);
- return;
- }
- UCHAR
- AtapReadRegister (
- PATA_CHANNEL Channel,
- ATA_REGISTER Register
- )
- /*++
- Routine Description:
- This routine reads an ATA register.
- Arguments:
- Channel - Supplies a pointer to the channel information.
- Register - Supplies the register to read.
- Return Value:
- Returns the value at the given register.
- --*/
- {
- UCHAR Result;
- //
- // If writing the high order bytes, flip into that mode.
- //
- if ((Register > AtaRegisterCommand) && (Register < AtaRegisterControl)) {
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- ATA_CONTROL_HIGH_ORDER | Channel->InterruptDisable);
- }
- if (Register < AtaRegisterSectorCountHigh) {
- Result = HlIoPortInByte(Channel->IoBase + Register);
- } else if (Register < AtaRegisterControl) {
- Register -= ATA_HIGH_ADDRESSING_OFFSET;
- Result = HlIoPortInByte(Channel->IoBase + Register);
- } else if (Register < AtaRegisterBusMasterCommand) {
- Register -= ATA_CONTROL_REGISTER_OFFSET;
- Result = HlIoPortInByte(Channel->ControlBase + Register);
- } else {
- Register -= ATA_BUS_MASTER_REGISTER_OFFSET;
- Result = HlIoPortInByte(Channel->BusMasterBase + Register);
- }
- if ((Register > AtaRegisterCommand) && (Register < AtaRegisterControl)) {
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- Channel->InterruptDisable);
- }
- return Result;
- }
- VOID
- AtapWriteRegister (
- PATA_CHANNEL Channel,
- ATA_REGISTER Register,
- UCHAR Value
- )
- /*++
- Routine Description:
- This routine writes an ATA register.
- Arguments:
- Channel - Supplies a pointer to the channel information.
- Register - Supplies the register to write.
- Value - Supplies the value to write.
- Return Value:
- None.
- --*/
- {
- //
- // If writing the high order bytes, flip into that mode.
- //
- if ((Register > AtaRegisterCommand) && (Register < AtaRegisterControl)) {
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- ATA_CONTROL_HIGH_ORDER | Channel->InterruptDisable);
- }
- if (Register < AtaRegisterSectorCountHigh) {
- HlIoPortOutByte(Channel->IoBase + Register, Value);
- } else if (Register < AtaRegisterControl) {
- Register -= ATA_HIGH_ADDRESSING_OFFSET;
- HlIoPortOutByte(Channel->IoBase + Register, Value);
- } else if (Register < AtaRegisterBusMasterCommand) {
- Register -= ATA_CONTROL_REGISTER_OFFSET;
- HlIoPortOutByte(Channel->ControlBase + Register, Value);
- } else {
- Register -= ATA_BUS_MASTER_REGISTER_OFFSET;
- HlIoPortOutByte(Channel->BusMasterBase + Register, Value);
- }
- if ((Register > AtaRegisterCommand) && (Register < AtaRegisterControl)) {
- AtapWriteRegister(Channel,
- AtaRegisterControl,
- Channel->InterruptDisable);
- }
- return;
- }
- VOID
- AtapProcessPciConfigInterfaceChangeNotification (
- PVOID Context,
- PDEVICE Device,
- PVOID InterfaceBuffer,
- ULONG InterfaceBufferSize,
- BOOL Arrival
- )
- /*++
- Routine Description:
- This routine is called when a PCI configuration space access interface
- changes in availability.
- Arguments:
- Context - Supplies the caller's context pointer, supplied when the caller
- requested interface notifications.
- Device - Supplies a pointer to the device exposing or deleting the
- interface.
- InterfaceBuffer - Supplies a pointer to the interface buffer of the
- interface.
- InterfaceBufferSize - Supplies the buffer size.
- Arrival - Supplies TRUE if a new interface is arriving, or FALSE if an
- interface is departing.
- Return Value:
- None.
- --*/
- {
- PATA_CONTROLLER ControllerContext;
- ControllerContext = (PATA_CONTROLLER)Context;
- if (Arrival != FALSE) {
- if (InterfaceBufferSize >= sizeof(INTERFACE_PCI_CONFIG_ACCESS)) {
- ASSERT(ControllerContext->PciConfigInterfaceAvailable == FALSE);
- RtlCopyMemory(&(ControllerContext->PciConfigInterface),
- InterfaceBuffer,
- sizeof(INTERFACE_PCI_CONFIG_ACCESS));
- ControllerContext->PciConfigInterfaceAvailable = TRUE;
- }
- } else {
- ControllerContext->PciConfigInterfaceAvailable = FALSE;
- }
- return;
- }
|