BIOS.AMD64.ATADisks.Mod 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421
  1. MODULE ATADisks; (** AUTHOR "ml"; PURPOSE "ATA/ATAPI disk driver"; *)
  2. (*
  3. * Version based on Disks and ATADisks
  4. *
  5. * Aos ATA/ATAPI-6 disk driver with Busmaster suppport.
  6. *
  7. * Boot string parameters:
  8. *
  9. * ATADetect:
  10. *
  11. * Default -> Searches for PCI devices with classcodes for IDE, SATA
  12. * "legacy" -> Uses controller at addrss 1F0 and 170. No busmaster support.
  13. * "default" -> Searches for PCI devices with spezial vendor and device ID
  14. * "raid" -> Searches for PCI devices with classcodes for IDE, SATA, RAID
  15. * "other" -> Searches for PCI devices with classcodes for IDE, SATA, OTHER
  16. * "raid+other" -> Searches for PCI devices with classcodes for IDE, SATA, RAID, OTHER
  17. *
  18. * ATAForcePIO: Forces PIO mode for ATA devices if set to "1"
  19. * ATAPIForcePIO: Forces PIO mode for ATAPI devices if set to "1"
  20. *
  21. * ATATrace: Enable particular trace options, e.g. ATATrace=5 enables TraceInit, ATATrace=012345 enables all trace options
  22. * See TraceXXX constants below.
  23. *
  24. * dev=nodma Disable DMA transfers for the specified device, e.g. IDE0=nodma
  25. *
  26. * History:
  27. *
  28. * 05.04.2006 Made trace options accessible using config strings (staubesv)
  29. * 02.06.2006 Adapted to CD recorder software
  30. * 26.03.2007 Added NnofReads, NnofWrites, NnofOthers and NnofErrors statistics (staubesv)
  31. *)
  32. IMPORT SYSTEM, Machine, KernelLog, Modules, Kernel, Objects, Plugins, Disks, PCI;
  33. CONST
  34. Name = "IDE";
  35. MaxControllers = 10;
  36. MaxDevicesC = 2;
  37. MaxDevices = MaxDevicesC*MaxControllers;
  38. MaxTries = 5;
  39. MaxTriesDMA = 3;
  40. (* Enable compilation of trace/debug code? *)
  41. TraceVerbose = TRUE;
  42. (* Caution: If changing the constants value, adapt procedure GetOptions *)
  43. TraceCommands = {0}; (* trace commands *)
  44. TraceErrors = {1}; (* show error details *)
  45. TraceAtapi = {2}; (* trace atapi commands *)
  46. TraceSense = {3}; (* show atapi sense results *)
  47. TraceBuffer = {4};
  48. TraceInit = {5};
  49. TryReset = TRUE;
  50. InitDevices = TRUE; (* used for ATA-4 or older *)
  51. AllowManualEject = TRUE; (* Should manual media eject be allowed for devices that are open? *)
  52. SelectTimeout = 500; (* ms *)
  53. IOTimeout* = 10000; (* ms *)
  54. IdentifyTimeout = 2000; (* ms *)
  55. ResetTimeout = 30000; (* ms *)
  56. ATAPITimeout* = 5000; (* ms *)
  57. BS = 512;
  58. DMABufferSize = 256 * 2048; (* 512 kB *)
  59. MaxPRD = 32; (* <= 32 *)
  60. (* According "CF+ and CompactFlash Specification Version 1.4" by CompactFlash Association*)
  61. CompactFlashSignature = 848AH; (*CF*)
  62. PageSize = 4096;
  63. AtapiBit = 0; RemovableBit = 1; DMABit* = 2; LBABit = 3; RMSNBit = 4; Packet16Bit = 5; LBA48Bit = 6; FlushBit = 7;
  64. CompactFlash = 9; (*CF*)
  65. ATAPI_DirectAccess = 0; ATAPI_SequentialAccess = 1; ATAPI_Printer = 2; ATAPI_Processor = 3; ATAPI_WriteOnce = 4;
  66. ATAPI_CDRom = 5; ATAPI_Scanner = 6; ATAPI_OpticalMemory = 7; ATAPI_MediumChanger = 8; ATAPI_Communications = 9;
  67. Protocol_DMABit = 7; Protocol_No = {}; Protocol_NonData = {1}; Protocol_PIO = {2}; Protocol_PacketPIO* = {3}; Protocol_DeviceReset = {6};
  68. Protocol_DMA = Protocol_PIO + {Protocol_DMABit};
  69. Protocol_PacketDMA* = Protocol_PacketPIO + {Protocol_DMABit};
  70. Device_DEV = 4; Device_LBA = 6;
  71. Status_ERR = 0; Status_DRQ = 3; Status_DRDY = 6; Status_BSY = 7;
  72. Control_nIEN = 1; Control_SRST = 2;
  73. DMA_Start = 0; DMA_Read = 3; DMA_ERR = 1; DMA_IRQ = 2; DMA_Busy = 0;
  74. Ofs_Features = 1; Ofs_Error = 1; Ofs_Device = 6; Ofs_Status = 7; Ofs_Cmd = 7;
  75. Ofs_SectorCount = 2; Ofs_SectorNumber = 3; Ofs_CylinderLow = 4; Ofs_CylinderHigh = 5;
  76. Ofs_LBALow = 3; Ofs_LBAMid = 4; Ofs_LBAHigh = 5;
  77. Ofs_CountLow = 4; Ofs_CountHigh = 5;
  78. Ofs_AltStatus = 6; Ofs_Control = 6;
  79. Ofs_BMCmd = 0; Ofs_BMStatus = 2; Ofs_BMPRDT = 4;
  80. ATAPI_DMA* = 0;
  81. ATAPISig = 0EBX;
  82. Res_OK = 0; Res_Err = 1; Res_Timeout = 2;
  83. WriteAndVerify* = 3; (* Disks.Read = 1, Disks.Read = 2 *)
  84. TYPE
  85. LoadMsg* = RECORD (Disks.Message) END; (** load the media *)
  86. GetSenseMsg* = RECORD (Disks.Message) sense*, asc*, ascq*: LONGINT; fieldPointer*: ARRAY 3 OF CHAR; END;
  87. TestUnitReadyMsg* = RECORD (Disks.Message) enable*: BOOLEAN; END;
  88. WriteCacheMsg* = RECORD (Disks.Message) enable*: BOOLEAN; END;
  89. CHS = RECORD
  90. cyls, hds, spt: LONGINT
  91. END;
  92. ID* = RECORD
  93. type*: SET;
  94. ver, devtype: LONGINT;
  95. model: ARRAY 44 OF CHAR;
  96. dmamode, maxdmamode: LONGINT;
  97. majorVersion: LONGINT;
  98. END;
  99. PRDT = POINTER TO RECORD
  100. prd: ARRAY MaxPRD OF RECORD (* aligned on 32-byte boundary, see Intel 290550-002 sec. 2.7.3 *)
  101. physAdr, size: LONGINT
  102. END
  103. END;
  104. Command = POINTER TO CommandDesc;
  105. CommandDesc = RECORD
  106. dev, cmd, count*, size*, features: LONGINT;
  107. bufAdr*: ADDRESS;
  108. read*, buffered: BOOLEAN;
  109. protocol*: SET;
  110. prdtPhysAdr: LONGINT;
  111. prdt: PRDT;
  112. getResult: BOOLEAN;
  113. END;
  114. CommandCHS = POINTER TO CommandCHSDesc;
  115. CommandCHSDesc = RECORD (CommandDesc)
  116. sector, head, cylinder: LONGINT;
  117. END;
  118. CommandLBA = POINTER TO CommandLBADesc;
  119. CommandLBADesc = RECORD (CommandDesc)
  120. lba: LONGINT;
  121. END;
  122. CommandLBA48 = POINTER TO CommandLBA48Desc;
  123. CommandLBA48Desc = RECORD (CommandDesc)
  124. lbaHigh, lbaLow: LONGINT;
  125. END;
  126. CommandPacket = POINTER TO CommandPacketDesc;
  127. CommandPacketDesc = RECORD (CommandDesc)
  128. packet*: Packet;
  129. features*: SET;
  130. sense, packetLen: LONGINT;
  131. END;
  132. Packet = ARRAY 16 OF CHAR;
  133. TYPE
  134. Interrupt = OBJECT
  135. VAR
  136. int: LONGINT;
  137. interrupt, timeout: BOOLEAN;
  138. clock: Objects.Timer;
  139. PROCEDURE HandleInterrupt;
  140. BEGIN {EXCLUSIVE}
  141. interrupt := TRUE;
  142. INC(irqCount);
  143. END HandleInterrupt;
  144. PROCEDURE HandleTimeout;
  145. BEGIN {EXCLUSIVE}
  146. timeout := TRUE;
  147. END HandleTimeout;
  148. PROCEDURE Wait(ms: LONGINT): BOOLEAN;
  149. BEGIN {EXCLUSIVE}
  150. timeout := FALSE;
  151. Objects.SetTimeout(clock, SELF.HandleTimeout, ms); (* set or reset timeout *)
  152. AWAIT(interrupt OR timeout);
  153. Objects.CancelTimeout(clock);
  154. INC(expectedCount);
  155. interrupt := FALSE;
  156. RETURN ~timeout
  157. END Wait;
  158. PROCEDURE Reset;
  159. BEGIN
  160. interrupt := FALSE
  161. END Reset;
  162. PROCEDURE &Init*(irq: LONGINT);
  163. BEGIN
  164. interrupt := FALSE; int := Machine.IRQ0 + irq;
  165. NEW(clock);
  166. Objects.InstallHandler(SELF.HandleInterrupt, int)
  167. END Init;
  168. PROCEDURE Finalize;
  169. BEGIN
  170. Objects.RemoveHandler(HandleInterrupt, int);
  171. Objects.CancelTimeout(clock);
  172. END Finalize;
  173. END Interrupt;
  174. Controller = OBJECT
  175. VAR
  176. cmdbase, cnlbase, bmbase, irq: LONGINT;
  177. interrupt: Interrupt;
  178. ctrlID, state: LONGINT;
  179. nIEN: LONGINT;
  180. prdtPhysAdr: LONGINT;
  181. prdt: PRDT;
  182. buffer: POINTER TO ARRAY OF CHAR;
  183. bufferAdr: ADDRESS;
  184. PROCEDURE ExecuteCommand*(command: Command; ms: LONGINT; VAR status: SET): LONGINT;
  185. CONST
  186. PIO = SYSTEM.VAL(LONGINT, Protocol_PIO);
  187. DMA = SYSTEM.VAL(LONGINT, Protocol_DMA);
  188. PacketPIO = SYSTEM.VAL(LONGINT, Protocol_PacketPIO);
  189. PacketDMA = SYSTEM.VAL(LONGINT, Protocol_PacketDMA);
  190. DeviceReset = SYSTEM.VAL(LONGINT, Protocol_DeviceReset);
  191. NonData = SYSTEM.VAL(LONGINT, Protocol_NonData);
  192. VAR
  193. res: WORD;
  194. ch: CHAR;
  195. dma: BOOLEAN;
  196. BEGIN {EXCLUSIVE}
  197. IF state = 1 THEN
  198. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  199. IF ~(Status_BSY IN status) THEN
  200. state := 0;
  201. ELSE
  202. RETURN Res_Err;
  203. END;
  204. END;
  205. dma := Protocol_DMABit IN command.protocol;
  206. IF TraceVerbose & (trace * TraceCommands # {}) THEN
  207. KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
  208. KernelLog.String(" Issue: "); KernelLog.Hex(command.cmd, -3);
  209. IF command IS CommandPacket THEN
  210. KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
  211. END;
  212. KernelLog.Ln;
  213. END;
  214. IF interrupt # NIL THEN
  215. interrupt.Reset;
  216. END;
  217. res := ProtIssueCommand(command, ms);
  218. IF res # Res_OK THEN
  219. (*IF dma THEN
  220. StopDMA();
  221. END;*)
  222. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  223. IF TraceVerbose & (trace * TraceErrors # {}) THEN
  224. KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
  225. KernelLog.String(" Error (issue): Command "); KernelLog.Hex(command.cmd, -2);
  226. IF command IS CommandPacket THEN
  227. KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
  228. END;
  229. KernelLog.String(", Status = "); KernelLog.Hex(ORD(ch), -2); KernelLog.Ln;
  230. END;
  231. (*IF status * {Status_BSY, Status_DRQ} # {} THEN
  232. ignore := ProtSwReset(ResetTimeout);
  233. END;*)
  234. RETURN res;
  235. END;
  236. IF dma THEN
  237. res := SetupDMA(command);
  238. IF res # Res_OK THEN RETURN res; END;
  239. StartDMA();
  240. END;
  241. CASE SYSTEM.VAL(LONGINT, command.protocol) OF
  242. | NonData: res := ProtNonData(ms, status);
  243. | PIO: IF command.read THEN res := ProtPIOIn(command.bufAdr, command.count, ms, status);
  244. ELSE res := ProtPIOOut(command.bufAdr, command.count, ms, status); END;
  245. | DMA: res := ProtDMA(ms, status);
  246. | DeviceReset: res := ProtDeviceReset(ms, status);
  247. | PacketPIO: res := ProtPacketPIO(command(CommandPacket), command.read, command.bufAdr, command.size, ms, status);
  248. | PacketDMA: res := ProtPacketDMA(command(CommandPacket), ms, status);
  249. ELSE
  250. Show("Error invalid protocol"); KernelLog.Int(res, 0); KernelLog.Ln;
  251. END;
  252. IF dma THEN
  253. StopDMA();
  254. END;
  255. IF command.getResult THEN
  256. Show("Returning results not yet implemented"); KernelLog.Ln;
  257. HALT(Disks.Unsupported);
  258. END;
  259. IF res # Res_OK THEN
  260. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  261. IF TraceVerbose & (trace * TraceErrors # {}) THEN
  262. KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + command.dev, 1);
  263. KernelLog.String(" Error (protocol): Command "); KernelLog.Hex(command.cmd, -2);
  264. IF command IS CommandPacket THEN
  265. KernelLog.String(", "); KernelLog.Hex(ORD(command(CommandPacket).packet[0]), -2);
  266. END;
  267. KernelLog.String(", Protocol = "); KernelLog.Hex(SYSTEM.VAL(LONGINT, command.protocol), -2);
  268. KernelLog.String(", Result = ");KernelLog.Int(res, 0);
  269. KernelLog.String(", Status = "); KernelLog.Hex(ORD(ch), -2);
  270. IF Status_ERR IN status THEN
  271. Machine.Portin8(cmdbase+Ofs_Error, ch);
  272. KernelLog.String(", Error = "); KernelLog.Hex(ORD(ch), -2);
  273. END;
  274. KernelLog.Ln;
  275. END;
  276. (*IF status * {Status_BSY, Status_DRQ} # {} THEN
  277. ignore := ProtSwReset(ResetTimeout);
  278. END;*)
  279. END;
  280. IF command.buffered THEN
  281. SYSTEM.MOVE(bufferAdr, command.bufAdr, command.size);
  282. END;
  283. RETURN res;
  284. END ExecuteCommand;
  285. PROCEDURE Reset(): LONGINT;
  286. BEGIN {EXCLUSIVE}
  287. RETURN ProtSwReset(ResetTimeout);
  288. END Reset;
  289. PROCEDURE SetupPRD(command: Command): LONGINT;
  290. VAR
  291. i, size, left: LONGINT; bufAdr, physAdr, tmp: ADDRESS;
  292. BEGIN
  293. IF TraceVerbose & (trace * TraceBuffer # {}) THEN
  294. KernelLog.String("bufAdr = "); KernelLog.Hex(command.bufAdr, 0);
  295. IF ~GetPhysAdr(command.bufAdr, command.size, tmp) THEN
  296. KernelLog.String(", Split buffer");
  297. END;
  298. KernelLog.Ln;
  299. END;
  300. (* create prdt *)
  301. command.prdt := prdt;
  302. command.prdtPhysAdr := prdtPhysAdr;
  303. (*IF ~GetPRDAdr(command) THEN KernelLog.String("Create PRD failed (GetPRDAdr)"); KernelLog.Ln; RETURN Res_Err; END;*)
  304. IF ODD(command.bufAdr) THEN
  305. command.buffered := TRUE;
  306. bufAdr := bufferAdr;
  307. ELSE
  308. bufAdr := command.bufAdr;
  309. END;
  310. size := command.size;
  311. i := 0;
  312. LOOP
  313. IF TraceVerbose & (trace * TraceBuffer # {}) THEN KernelLog.String(" "); KernelLog.Hex(bufAdr, 0); END;
  314. IF ~GetPhysAdr(bufAdr, 1, physAdr) THEN Show("Setup PRD failed (GetPhysAdr)"); KernelLog.Ln; RETURN Res_Err; END;
  315. command.prdt.prd[i].physAdr := Machine.Ensure32BitAddress (physAdr);
  316. IF TraceVerbose & (trace * TraceBuffer # {}) THEN KernelLog.String(", "); KernelLog.Hex(physAdr, 0); END;
  317. left := 65536 - Machine.Ensure32BitAddress (physAdr MOD 65536); (* should not cross 64k boundary (sec. 3.5.3) *)
  318. IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", ("); KernelLog.Hex(left, 0); END;
  319. (* Calculate the max. contiguous physical memory *)
  320. WHILE ~GetPhysAdr(bufAdr, left, tmp) & (left > 0) DO
  321. (*left := (left-1) - ((left-1) MOD PageSize);*)
  322. DEC(left, PageSize);
  323. IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", "); KernelLog.Hex(left, 0); END;
  324. END;
  325. IF TraceVerbose & (trace * TraceBuffer # {})THEN
  326. IF GetPhysAdr(bufAdr, left+1, tmp) THEN
  327. KernelLog.String("+");
  328. END;
  329. KernelLog.String("), "); KernelLog.Hex(left, 0);
  330. END;
  331. IF (left = 0) & (size > 0) THEN Show("Setup PRD failed"); KernelLog.Ln; RETURN Res_Err; END;
  332. IF left > size THEN left := size END;
  333. IF TraceVerbose & (trace * TraceBuffer # {})THEN KernelLog.String(", "); KernelLog.Hex(left, 0); KernelLog.Ln; END;
  334. DEC(size, left);
  335. IF size = 0 THEN
  336. command.prdt.prd[i].size := LONGINT(80000000H) + left; (* end marker *)
  337. EXIT
  338. END;
  339. command.prdt.prd[i].size := left;
  340. INC(bufAdr, left);
  341. INC(physAdr, left); INC(i);
  342. IF i = LEN(command.prdt.prd) THEN Show("Setup PRD failed (out of bounds)"); KernelLog.Ln; RETURN Res_Err; END;
  343. END;
  344. RETURN Res_OK;
  345. END SetupPRD;
  346. PROCEDURE SetupDMA(command: Command): LONGINT;
  347. VAR
  348. ch: CHAR;
  349. s: SET;
  350. res: WORD;
  351. BEGIN
  352. (* Clear Interrupt & Errror *)
  353. Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
  354. s := s * {1..7};
  355. Machine.Portout8(bmbase + Ofs_BMStatus, CHR(SYSTEM.VAL(LONGINT, s)));
  356. res := SetupPRD(command);
  357. IF res # Res_OK THEN RETURN res; END;
  358. (* Write address of PRDT *)
  359. Machine.Portout32(bmbase + Ofs_BMPRDT, command.prdtPhysAdr);
  360. (* Set direction *)
  361. IF command.read THEN
  362. ch := CHR(ASH(1, DMA_Read));
  363. ELSE
  364. ch := 0X;
  365. END;
  366. Machine.Portout8(bmbase + Ofs_BMCmd, ch);
  367. RETURN Res_OK;
  368. END SetupDMA;
  369. PROCEDURE StartDMA;
  370. VAR ch: CHAR; s: SET;
  371. BEGIN
  372. (* START DMA *)
  373. Machine.Portin8(bmbase + Ofs_BMCmd, ch);
  374. s := SYSTEM.VAL(SET, ORD(ch));
  375. INCL(s, DMA_Start);
  376. Machine.Portout8(bmbase + Ofs_BMCmd, CHR(SYSTEM.VAL(LONGINT, s)));
  377. END StartDMA;
  378. PROCEDURE StopDMA;
  379. VAR ch: CHAR; s: SET;
  380. BEGIN
  381. (* Stop DMA *)
  382. Machine.Portin8(bmbase + Ofs_BMCmd, ch);
  383. s := SYSTEM.VAL(SET, ORD(ch));
  384. EXCL(s, DMA_Start);
  385. Machine.Portout8(bmbase + Ofs_BMCmd, CHR(SYSTEM.VAL(LONGINT, s)));
  386. (* Clear Interrupt & Errror *)
  387. Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
  388. s := s * {1..7};
  389. Machine.Portout8(bmbase + Ofs_BMStatus, CHR(SYSTEM.VAL(LONGINT, s)));
  390. END StopDMA;
  391. PROCEDURE WaitStatus(mask, expect, bad: SET; ms: LONGINT; VAR status: SET): LONGINT;
  392. VAR t: Kernel.MilliTimer; ch: CHAR;
  393. BEGIN
  394. ASSERT(Status_BSY IN mask);
  395. Kernel.SetTimer(t, ms);
  396. LOOP
  397. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  398. IF ~(Status_BSY IN status) THEN
  399. IF status * mask = expect THEN EXIT; END;
  400. END;
  401. IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;
  402. END;
  403. IF status * bad # {} THEN RETURN Res_Err; END;
  404. RETURN Res_OK;
  405. END WaitStatus;
  406. (* Software reset protocol
  407. States: HSR0(ISet_SRST), HSR1 (Clear_wait), HSR2 (Check_Status) *)
  408. PROCEDURE ProtSwReset(ms: LONGINT): LONGINT;
  409. VAR
  410. t: Kernel.MilliTimer;
  411. status: SET;
  412. res: WORD;
  413. BEGIN
  414. IF state = 1 THEN RETURN Res_Err; END;
  415. (* HSR0 *)
  416. Machine.Portout8(cnlbase+Ofs_Control, CHR(ASH(1, Control_SRST))); (* reset controller *)
  417. Kernel.SetTimer(t, 1); REPEAT UNTIL Kernel.Expired(t); (* wait > 4.8us *)
  418. (* HSR1 *)
  419. Machine.Portout8(cnlbase+Ofs_Control, 0X);
  420. Kernel.SetTimer(t, 3); REPEAT UNTIL Kernel.Expired(t); (* wait ~2ms *)
  421. (* HSR0 *)
  422. res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  423. IF res # Res_OK THEN state := 1; END;
  424. RETURN res;
  425. END ProtSwReset;
  426. (* Bus idle protocol
  427. States: HI0(Host_Idle), HI1 (Check_Status), HI2 (Device_Select), HI3 (Write_parameters), HI4(Write_command) *)
  428. PROCEDURE ProtIssueCommand(cmd: Command; ms: LONGINT): LONGINT;
  429. VAR
  430. cmdCHS: CommandCHS;
  431. cmdLBA: CommandLBA;
  432. cmdLBA48: CommandLBA48;
  433. cmdPacket: CommandPacket;
  434. ch: CHAR;
  435. status, devReg: SET;
  436. res: WORD;
  437. BEGIN
  438. (* HI1 *)
  439. res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, ms, status);
  440. (*res := WaitStatus({Status_BSY}, {}, {}, ms, status);*)
  441. (*IF res # Res_OK THEN RETURN res; END;*)
  442. res := Res_OK;
  443. IF cmd.dev = 1 THEN devReg := {Device_DEV} ELSE devReg := {}; END;
  444. Machine.Portin8(cmdbase+Ofs_Device, ch);
  445. (* Change device? *)
  446. IF ((SYSTEM.VAL(SET, ORD(ch)) * {Device_DEV}) # devReg)
  447. (* OR (Status_BSY IN status)*) THEN
  448. IF TraceVerbose & (trace * TraceCommands # {}) THEN
  449. KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC + cmd.dev, 1);
  450. KernelLog.String(" Select device"); KernelLog.Ln;
  451. END;
  452. SetInterrupt(FALSE);
  453. (* HI2 *)
  454. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  455. (* HI1 *)
  456. res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
  457. IF res # Res_OK THEN RETURN res; END;
  458. SetInterrupt(TRUE);
  459. END;
  460. (* HI3 *)
  461. IF cmd IS CommandCHS THEN
  462. cmdCHS := cmd(CommandCHS);
  463. Machine.Portout8(cmdbase+Ofs_Features, CHR(cmdCHS.features));
  464. Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdCHS.count));
  465. Machine.Portout8(cmdbase+Ofs_SectorNumber, CHR(cmdCHS.sector));
  466. Machine.Portout8(cmdbase+Ofs_CylinderLow, CHR(cmdCHS.cylinder MOD 100H));
  467. Machine.Portout8(cmdbase+Ofs_CylinderHigh, CHR(cmdCHS.cylinder DIV 100H));
  468. devReg := devReg + SYSTEM.VAL(SET, cmdCHS.head MOD 10H);
  469. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  470. ELSIF cmd IS CommandLBA THEN
  471. cmdLBA := cmd(CommandLBA);
  472. Machine.Portout8(cmdbase+Ofs_Features, CHR(cmdLBA.features));
  473. Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdLBA.count));
  474. Machine.Portout8(cmdbase+Ofs_LBALow, CHR(cmdLBA.lba MOD 100H));
  475. Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((ASH(cmdLBA.lba, -8) MOD 100H)));
  476. Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA.lba, -16) MOD 100H)));
  477. INCL(devReg, Device_LBA);
  478. devReg := devReg + SYSTEM.VAL(SET, ASH(cmdLBA.lba, -24) MOD 10H);
  479. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  480. ELSIF cmd IS CommandLBA48 THEN
  481. cmdLBA48 := cmd(CommandLBA48);
  482. (* Previous *)
  483. Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(ASH(cmdLBA48.count, -8) MOD 100H));
  484. Machine.Portout8(cmdbase+Ofs_LBALow, CHR((ASH(cmdLBA48.lbaLow, -24) MOD 100H)));
  485. Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((cmdLBA48.lbaHigh MOD 100H)));
  486. Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA48.lbaHigh, -8) MOD 100H)));
  487. (* Current *)
  488. Machine.Portout8(cmdbase+Ofs_SectorCount, CHR(cmdLBA48.count));
  489. Machine.Portout8(cmdbase+Ofs_LBALow, CHR(cmdLBA48.lbaLow MOD 100H));
  490. Machine.Portout8(cmdbase+Ofs_LBAMid, CHR((ASH(cmdLBA48.lbaLow, -8) MOD 100H)));
  491. Machine.Portout8(cmdbase+Ofs_LBAHigh, CHR((ASH(cmdLBA48.lbaLow, -16) MOD 100H)));
  492. INCL(devReg, Device_LBA);
  493. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  494. ELSIF cmd IS CommandPacket THEN
  495. cmdPacket := cmd(CommandPacket);
  496. Machine.Portout8(cmdbase+Ofs_Features, CHR(SYSTEM.VAL(LONGINT, cmdPacket.features))); (* OVL, DMA *)
  497. Machine.Portout8(cmdbase+Ofs_SectorCount, 0X); (* tag 0 *)
  498. Machine.Portout8(cmdbase+Ofs_CountLow, 0FEX); (* byte count limit *)
  499. Machine.Portout8(cmdbase+Ofs_CountHigh, 0FFX);
  500. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  501. END;
  502. (* HI4 *)
  503. Machine.Portout8(cmdbase+Ofs_Cmd, CHR(cmd.cmd));
  504. RETURN res;
  505. END ProtIssueCommand;
  506. (* Non-data protocol
  507. States: HND0 (INTRQ_wait), HND1 (Check_Status) *)
  508. PROCEDURE ProtNonData(ms: LONGINT; VAR status: SET): LONGINT;
  509. BEGIN
  510. IF nIEN = 0 THEN
  511. (* HND0 *)
  512. IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
  513. ELSE
  514. (* Wait 400ns when entering HND1 form state other than HND0 *)
  515. NanoDelay(400);
  516. END;
  517. (* HND1 *)
  518. RETURN WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  519. END ProtNonData;
  520. (* PIO data-in protocol
  521. States: HPIOI0 (INTRQ_wait), HPIOI1 (Check_Status), HPIOI2 (Transfer_Data) *)
  522. PROCEDURE ProtPIOIn(bufAdr: ADDRESS; num: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
  523. VAR state, res: LONGINT; ch: CHAR;
  524. BEGIN
  525. res := Res_OK;
  526. IF nIEN = 1 THEN
  527. state := 1;
  528. (* Wait 400ns when entering HPIOI1 *)
  529. NanoDelay(400);
  530. END;
  531. REPEAT
  532. CASE state OF
  533. (* HPIOI0 *)
  534. | 0: BEGIN
  535. IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
  536. state := 1;
  537. END;
  538. (* HPIOI1 *)
  539. | 1: BEGIN
  540. res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  541. IF res # Res_OK THEN RETURN res; END;
  542. IF Status_DRQ IN status THEN
  543. state:= 2;
  544. ELSE
  545. RETURN Res_Err;
  546. END;
  547. END;
  548. (* HPIOI2 *)
  549. | 2: BEGIN
  550. RepInWord(cmdbase, bufAdr, BS DIV 2);
  551. INC(bufAdr, BS); DEC(num);
  552. IF num <= 0 THEN
  553. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  554. IF Status_ERR IN status THEN res := Res_Err; END;
  555. state := -1;
  556. ELSIF nIEN = 0 THEN
  557. state := 0;
  558. ELSE
  559. state := 1;
  560. (* Wait 1 PIO transfer cycle when entering HPIOI1 from HPIOI2 *)
  561. Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
  562. END;
  563. END;
  564. END;
  565. UNTIL state = -1;
  566. RETURN res;
  567. END ProtPIOIn;
  568. (* PIO data-out Protocol
  569. States: HPIOO0 (Check_Status), HPIOO1 (Transfer_Data), HPIOO2 (INTRQ_wait) *)
  570. PROCEDURE ProtPIOOut(bufAdr: ADDRESS; num: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
  571. VAR
  572. state, res: LONGINT;
  573. ch: CHAR;
  574. BEGIN
  575. state := 0;
  576. REPEAT
  577. CASE state OF
  578. (* HPIOO0 *)
  579. | 0: BEGIN
  580. res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  581. IF res # Res_OK THEN RETURN res; END;
  582. IF Status_DRQ IN status THEN
  583. state:= 1;
  584. ELSE
  585. state := -1;
  586. END;
  587. END;
  588. (* HPIOO1 *)
  589. | 1: BEGIN
  590. RepOutWord(cmdbase, bufAdr, BS DIV 2);
  591. INC(bufAdr, BS); DEC(num);
  592. IF nIEN = 0 THEN
  593. state := 2;
  594. ELSE
  595. state := 0;
  596. (* Wait 1 PIO transfer cycle when entering HPIOI1 from HPIOI2 *)
  597. Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
  598. END;
  599. END;
  600. (* HPIOO2 *)
  601. | 2: BEGIN
  602. IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
  603. state := 0;
  604. END;
  605. END;
  606. UNTIL state = -1;
  607. RETURN res;
  608. END ProtPIOOut;
  609. (* DMA Protocol
  610. States: HDMA0 (Check_Status), HDMA1 (Transfer_Data), HDMA2 (INTRQ_wait) *)
  611. PROCEDURE ProtDMA(ms: LONGINT; VAR status: SET): LONGINT;
  612. VAR
  613. ch: CHAR;
  614. t: Kernel.MilliTimer;
  615. s: SET;
  616. BEGIN
  617. (* Wait 400ns when entering HDMA0 *)
  618. NanoDelay(400);
  619. Kernel.SetTimer(t, ms);
  620. REPEAT
  621. IF nIEN = 0 THEN
  622. IF ~interrupt.Wait(ms) THEN (*RETURN Res_Timeout;*) END;
  623. END;
  624. Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
  625. (*UNTIL (s * {DMA_ERR, DMA_IRQ} # {}) OR Kernel.Expired(t);*)
  626. UNTIL ~(DMA_Busy IN s) OR Kernel.Expired(t);
  627. IF DMA_ERR IN s THEN RETURN Res_Err; END;
  628. (*IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;*)
  629. REPEAT
  630. Machine.Portin8(cmdbase+Ofs_Status, ch); status := SYSTEM.VAL(SET, ORD(ch));
  631. IF ~(Status_BSY IN status) THEN
  632. IF Status_ERR IN status THEN RETURN Res_Err; END;
  633. IF ~(Status_DRQ IN status) THEN RETURN Res_OK; END;
  634. END;
  635. (* Wait 1 PIO transfer cycle when entering HDMA0 *)
  636. Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
  637. UNTIL Kernel.Expired(t);
  638. RETURN Res_Timeout;
  639. END ProtDMA;
  640. (* Packet PIO Protocol
  641. States: HP0(Check_Status_A), HP1 (Send_Packet), HP2 (Check_Status_B), HP3 (INTRQ_wait), HP4 (Transfer_Data) *)
  642. PROCEDURE ProtPacketPIO(command: CommandPacket; read: BOOLEAN; bufAdr: ADDRESS; size: LONGINT; ms: LONGINT; VAR status: SET): LONGINT;
  643. VAR
  644. res, count: LONGINT;
  645. ch: CHAR;
  646. BEGIN
  647. (* Wait 400ns *)
  648. NanoDelay(400);
  649. (* HP0 *)
  650. res := WaitStatus({Status_BSY, Status_DRQ}, {Status_DRQ}, {Status_ERR}, ms, status);
  651. IF res # Res_OK THEN RETURN res; END;
  652. (* HP1 *)
  653. RepOutWord(cmdbase, ADDRESSOF(command.packet[0]), command.packetLen DIV 2);
  654. IF nIEN = 0 THEN
  655. (* HP3 *)
  656. (*IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;*)
  657. ELSE
  658. (* Wait 1 PIO transfer cycle when entering HP2 from HP1 *)
  659. Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
  660. END;
  661. LOOP
  662. (* HP2 *)
  663. res := WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  664. IF res # Res_OK THEN EXIT; END;
  665. IF ~(Status_DRQ IN status) THEN EXIT; END;
  666. IF size = 0 THEN EXIT; END;
  667. (* HP4 *)
  668. Machine.Portin8(cmdbase+Ofs_CountLow, ch);
  669. count := ORD(ch);
  670. Machine.Portin8(cmdbase+Ofs_CountHigh, ch);
  671. INC(count, ASH(ORD(ch), 8));
  672. IF count > size THEN count := size END;
  673. (* IF count <= 0 THEN KernelLog.String("count <= 0, size = "); KernelLog.Int(size, 0); KernelLog.Ln; EXIT; END; *)
  674. IF read THEN
  675. RepInWord(cmdbase, bufAdr, count DIV 2);
  676. ELSE
  677. RepOutWord(cmdbase, bufAdr, count DIV 2);
  678. END;
  679. INC(bufAdr, count); DEC(size, count);
  680. IF nIEN = 0 THEN
  681. (* HP3 *)
  682. IF ~interrupt.Wait(ms) THEN RETURN Res_Timeout; END;
  683. END;
  684. END;
  685. IF (res = Res_OK) & (size > 0) THEN res := Res_Err; END;
  686. RETURN res;
  687. END ProtPacketPIO;
  688. (* Packet DMA Protocol
  689. States: HPD0(Check_Status_A), HPD1 (Send_Packet), HPD2 (Check_Status_B), HPD3 (INTRQ_wait), HPD4 (Transfer_Data) *)
  690. PROCEDURE ProtPacketDMA(command: CommandPacket; ms: LONGINT; VAR status: SET): LONGINT;
  691. VAR
  692. res: WORD;
  693. ch: CHAR;
  694. s: SET;
  695. t: Kernel.MilliTimer;
  696. BEGIN
  697. (* Wait 400ns *)
  698. NanoDelay(400);
  699. (* HPD0 *)
  700. res := WaitStatus({Status_BSY, Status_DRQ}, {Status_DRQ}, {Status_ERR}, ms, status);
  701. IF res # Res_OK THEN RETURN res; END;
  702. (* HPD1 *)
  703. RepOutWord(cmdbase, ADDRESSOF(command.packet[0]), command.packetLen DIV 2);
  704. IF nIEN = 0 THEN
  705. (* HPD3 *)
  706. Kernel.SetTimer(t, ms+2);
  707. REPEAT
  708. IF ~interrupt.Wait(ms) THEN (*KernelLog.String("***");*) (*RETURN Res_Timeout;*) END;
  709. Machine.Portin8(bmbase + Ofs_BMStatus, ch); s := SYSTEM.VAL(SET, ORD(ch));
  710. UNTIL (s * {DMA_ERR, DMA_IRQ} # {}) OR Kernel.Expired(t);
  711. (* UNTIL ~(DMA_Busy IN s) OR Kernel.Expired(t); *)
  712. IF DMA_ERR IN s THEN RETURN Res_Err; END;
  713. IF Kernel.Expired(t) THEN RETURN Res_Timeout; END;
  714. ELSE
  715. (* Wait 1 PIO transfer cycle when entering HPD2 from HPD1 *)
  716. Machine.Portin8(cnlbase+Ofs_AltStatus, ch);
  717. END;
  718. (* HPD2 *)
  719. res := WaitStatus({Status_BSY, Status_DRQ}, {}, {Status_ERR}, ms, status);
  720. RETURN res;
  721. END ProtPacketDMA;
  722. (* Device reset protocol
  723. States: HDR0 (Wait), HDR1 (Check_Status) *)
  724. PROCEDURE ProtDeviceReset(ms: LONGINT; VAR status: SET): LONGINT;
  725. BEGIN
  726. (* HDR0 *)
  727. NanoDelay(400);
  728. (* HDR1 *)
  729. RETURN WaitStatus({Status_BSY}, {}, {Status_ERR}, ms, status);
  730. END ProtDeviceReset;
  731. PROCEDURE SetInterrupt(enable: BOOLEAN);
  732. VAR i : LONGINT;
  733. BEGIN
  734. (* Set nIEN *)
  735. IF enable & (interrupt # NIL) THEN nIEN := 0; ELSE nIEN := 1; END;
  736. i := ASH(nIEN, Control_nIEN);
  737. Machine.Portout8(cnlbase+Ofs_Control, CHR(i));
  738. END SetInterrupt;
  739. PROCEDURE CreateDevice(devNum: LONGINT): LONGINT;
  740. VAR status: SET;
  741. res: WORD; dev, devATA: Device; devATAPI: DeviceATAPI; ch: CHAR;
  742. buf: ARRAY BS DIV 2 OF INTEGER;
  743. command: Command;
  744. devReg: SET;
  745. c1, c2: CHAR;
  746. BEGIN
  747. (* Select device *)
  748. IF devNum = 1 THEN devReg := {Device_DEV} ELSE devReg := {}; END;
  749. Machine.Portout8(cmdbase+Ofs_Device, CHR(SYSTEM.VAL(LONGINT, devReg)));
  750. res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
  751. IF res # Res_OK THEN
  752. (* Most likely, there is no device .... Show("Could not select device"); KernelLog.Ln; *)
  753. END;
  754. (* Check if registers are valid. FAST DETECTION *)
  755. Machine.Portout8(cmdbase+Ofs_CountLow, 055X);
  756. NanoDelay(400);
  757. Machine.Portin8(cmdbase+Ofs_CountLow, c1);
  758. Machine.Portout8(cmdbase+Ofs_CountLow, 0AAX);
  759. NanoDelay(400);
  760. Machine.Portin8(cmdbase+Ofs_CountLow, c2);
  761. IF (c1 # 055X) OR (c2 # 0AAX) THEN
  762. IF TraceVerbose & (trace * (TraceErrors + TraceInit) # {}) THEN
  763. KernelLog.String(", device "); KernelLog.Int(devNum, 0); KernelLog.String(" not present");
  764. KernelLog.String(" "); KernelLog.Hex(ORD(c1), -2); KernelLog.Hex(ORD(c2), -3);
  765. END;
  766. RETURN Res_Err;
  767. END;
  768. IF TraceVerbose & (trace * TraceInit # {}) THEN
  769. KernelLog.String("Identify Device "); KernelLog.Int(devNum,1); KernelLog.Ln;
  770. END;
  771. NEW(command);
  772. command.dev := devNum; command.cmd := 0ECH; (* identify device *)
  773. command.protocol := Protocol_PIO; command.read := TRUE;
  774. command.bufAdr := ADDRESSOF(buf[0]); command.count := 1;
  775. res := ExecuteCommand(command, IdentifyTimeout, status);
  776. IF TraceVerbose & (trace * TraceInit # {}) THEN
  777. KernelLog.Ln;
  778. Show("Identify device commands, res: "); KernelLog.Int(res, 0); KernelLog.String(", status: "); KernelLog.Bits(status, 0, 32);
  779. KernelLog.Ln;
  780. END;
  781. (*IF ~(Status_DRDY IN status) THEN RETURN Res_Err; END;*)
  782. IF ~(Status_ERR IN status) THEN
  783. IF res # Res_OK THEN RETURN res; END;
  784. (* ATA device *)
  785. NEW(devATA, SELF, devNum, buf);
  786. dev := devATA;
  787. ELSE
  788. Machine.Portin8(cmdbase+Ofs_LBAHigh, ch); (* signature byte *)
  789. IF ch # ATAPISig THEN RETURN Res_Err; END;
  790. (* ATAPI device *)
  791. NEW(command);
  792. command.dev := devNum; command.cmd := 0A1H; (* identify packet device *)
  793. command.protocol := Protocol_PIO; command.read := TRUE;
  794. command.bufAdr := ADDRESSOF(buf[0]); command.count := 1;
  795. res := ExecuteCommand(command, IdentifyTimeout, status);
  796. IF TraceVerbose & (trace * TraceInit # {}) THEN
  797. Show("Identify packet device command, res: "); KernelLog.Int(res, 0); KernelLog.String(", status: "); KernelLog.Bits(status, 0, 32);
  798. END;
  799. IF res # Res_OK THEN RETURN res; END;
  800. NEW(devATAPI, SELF, devNum, buf);
  801. dev := devATAPI;
  802. END;
  803. RETURN res;
  804. END CreateDevice;
  805. PROCEDURE InitController;
  806. VAR p, res: LONGINT; status: SET;
  807. BEGIN
  808. res := ProtSwReset(IdentifyTimeout);
  809. (*IF res # Res_OK THEN
  810. KernelLog.String(", reset failed");
  811. SetInterrupt(FALSE);
  812. RETURN;
  813. END;*)
  814. IF bmbase # 0 THEN KernelLog.String(", Bus-master enabled"); END;
  815. (* Identify Devices *)
  816. FOR p:=0 TO MaxDevicesC-1 DO
  817. SetInterrupt(TRUE);
  818. res := CreateDevice(p);
  819. SetInterrupt(res = Res_OK);
  820. END;
  821. (* Select drive 0 if drive 1 is not present *)
  822. IF (device[ctrlID*MaxDevicesC] # NIL) & (device[ctrlID*MaxDevicesC + 1] = NIL) THEN
  823. IF TraceVerbose & (trace * TraceCommands # {}) THEN
  824. KernelLog.String(Name); KernelLog.Int(ctrlID*MaxDevicesC, 1);
  825. KernelLog.String(".."); KernelLog.Int((ctrlID+1)*MaxDevicesC-1, 1);
  826. KernelLog.String(" Select device 0"); KernelLog.Ln;
  827. END;
  828. Machine.Portout8(cmdbase+Ofs_Device, 0X);
  829. res := WaitStatus({Status_BSY, Status_DRQ}, {}, {}, SelectTimeout, status);
  830. IF res # Res_OK THEN KernelLog.String("Select device 0 failed"); KernelLog.Ln; END;
  831. SetInterrupt(TRUE);
  832. END;
  833. END InitController;
  834. PROCEDURE &Create*(cmd_ba, cnl_ba, bm_ba, airq: LONGINT);
  835. VAR
  836. try: LONGINT;
  837. BEGIN
  838. cmdbase := cmd_ba; cnlbase := cnl_ba; bmbase := bm_ba; irq := airq;
  839. state := 0;
  840. (* init interrupt *)
  841. interrupt := NIL;
  842. IF (irq > 0) & (irq <= 15) THEN
  843. NEW(interrupt, irq);
  844. ELSE
  845. KernelLog.Ln; Show("Invalid IRQ assigned"); KernelLog.Ln;
  846. END;
  847. SetInterrupt(TRUE);
  848. (* create buffer *)
  849. NEW(buffer, DMABufferSize + 1);
  850. bufferAdr := ADDRESSOF(buffer[0]);
  851. INC(bufferAdr, 1-(bufferAdr+1) MOD 2);
  852. (* create PRDT *)
  853. try := 3;
  854. REPEAT
  855. NEW(prdt); (* must not cross page boundary, see Intel 290550-002 sec. 2.7.3 *)
  856. prdtPhysAdr := Machine.Ensure32BitAddress (Machine.PhysicalAdr(ADDRESSOF(prdt.prd[0]), MaxPRD*8));
  857. DEC(try);
  858. UNTIL (try = 0) OR ((prdtPhysAdr # Machine.NilAdr) &
  859. (prdtPhysAdr DIV PageSize = (prdtPhysAdr+MaxPRD*8-1) DIV PageSize));
  860. IF ~((prdtPhysAdr # Machine.NilAdr) & (prdtPhysAdr DIV PageSize = (prdtPhysAdr+MaxPRD*8-1) DIV PageSize)) THEN
  861. KernelLog.Ln; Show("Create PRD failed (GetPRDAdr)"); KernelLog.Ln;
  862. bmbase := 0;
  863. END;
  864. END Create;
  865. PROCEDURE Finalize;
  866. VAR i: LONGINT;
  867. BEGIN
  868. FOR i := 0 TO MaxDevices-1 DO
  869. IF (device[i] # NIL) & (device[i].controller = SELF) THEN
  870. device[i].Finalize;
  871. device[i] := NIL;
  872. END
  873. END;
  874. IF interrupt # NIL THEN
  875. interrupt.Finalize;
  876. END;
  877. END Finalize;
  878. END Controller;
  879. Device* = OBJECT (Disks.Device)
  880. VAR
  881. controller*: Controller;
  882. dev: LONGINT; (* 0 or 1 *)
  883. size: LONGINT; (* total size *)
  884. maxTransfer: LONGINT;
  885. chs: CHS; (* for conversion LBA -> CHS *)
  886. getpar: CHS; (* for GetParams *)
  887. id*: ID;
  888. init: BOOLEAN; (* initialized? *)
  889. cmdCHS: CommandCHS;
  890. cmdLBA: CommandLBA;
  891. cmdLBA48: CommandLBA48;
  892. PROCEDURE Transfer*(op, block, num: LONGINT; VAR data: ARRAY OF CHAR; ofs: LONGINT; VAR res: WORD);
  893. VAR
  894. num1, try, ignore: LONGINT; bufAdr: ADDRESS;
  895. dma: BOOLEAN;
  896. BEGIN
  897. bufAdr := ADDRESSOF(data[ofs]);
  898. IF (block >= 0) & (num >= 0) & (block < size) & (block+num <= size) THEN
  899. ASSERT(num*blockSize <= LEN(data)-ofs); (* range check *)
  900. WHILE (res = Res_OK) & (num > 0) DO
  901. try := MaxTries;
  902. dma := DMABit IN id.type;
  903. num1 := maxTransfer;
  904. IF num1 > num THEN num1 := num; END;
  905. REPEAT
  906. res := TransferEx(op, block, num1, bufAdr, dma);
  907. DEC(try);
  908. IF (res = Disks.WriteProtected) OR (res = Disks.MediaMissing) OR (res = Disks.Unsupported) THEN
  909. try := 0;
  910. ELSIF (res # Res_OK) & (try = MaxTriesDMA) & dma THEN
  911. dma := FALSE;
  912. Show(name); KernelLog.String(" PIO fallback"); KernelLog.Ln;
  913. ELSIF (res # Res_OK) & (try = 0) & TryReset THEN
  914. ignore := Reset();
  915. END;
  916. UNTIL (res = Res_OK) OR (try = 0);
  917. IF Disks.Stats THEN
  918. BEGIN {EXCLUSIVE}
  919. IF op = Disks.Read THEN
  920. INC (NnofReads);
  921. IF (res = Res_OK) THEN INC (NbytesRead, num1 * blockSize);
  922. ELSE INC (NnofErrors);
  923. END;
  924. ELSIF op = Disks.Write THEN
  925. INC (NnofWrites);
  926. IF (res = Res_OK) THEN INC (NbytesWritten, num1 * blockSize);
  927. ELSE INC (NnofErrors);
  928. END;
  929. ELSE
  930. INC (NnofOthers);
  931. END;
  932. END;
  933. END;
  934. INC(block, num1); DEC(num, num1); INC(bufAdr, num1*blockSize);
  935. END;
  936. ELSE
  937. Show("ATA: out of range ");
  938. KernelLog.Address(block); KernelLog.Char(" "); KernelLog.Int(num, 1); KernelLog.Char(" ");
  939. KernelLog.Int(size, 1); KernelLog.Char(" "); KernelLog.String(name);
  940. res := 2826 (* transfer out of range *)
  941. END;
  942. END Transfer;
  943. PROCEDURE GetSize*(VAR size, res: LONGINT);
  944. BEGIN
  945. size := SELF.size;
  946. res := Disks.Ok;
  947. END GetSize;
  948. PROCEDURE Handle*(VAR msg: Disks.Message; VAR res: WORD);
  949. BEGIN
  950. res := Disks.Unsupported;
  951. IF msg IS Disks.GetGeometryMsg THEN
  952. WITH msg: Disks.GetGeometryMsg DO
  953. msg.cyls := getpar.cyls; msg.hds := getpar.hds; msg.spt := getpar.spt
  954. END;
  955. res := Disks.Ok
  956. ELSIF msg IS Disks.LockMsg THEN
  957. IF (RemovableBit IN id.type) & ~AllowManualEject THEN
  958. IF MediaLock(TRUE) = Res_OK THEN res := Res_OK; END;
  959. END;
  960. ELSIF (msg IS Disks.UnlockMsg) THEN
  961. IF (RemovableBit IN id.type) THEN
  962. IF MediaLock(FALSE) = Res_OK THEN res := Res_OK; END;
  963. END
  964. ELSIF (msg IS Disks.EjectMsg) THEN
  965. IF (RemovableBit IN id.type) THEN
  966. IF MediaEject(TRUE, FALSE) = Res_OK THEN res := Res_OK; END;
  967. END
  968. ELSIF (msg IS LoadMsg) THEN
  969. IF (RemovableBit IN id.type) THEN
  970. IF MediaEject(TRUE, TRUE) = Res_OK THEN res := Res_OK; END;
  971. END
  972. ELSIF (msg IS Disks.SavePowerMsg) THEN
  973. IF Powersave() = Res_OK THEN res := Res_OK; END;
  974. ELSIF (msg IS WriteCacheMsg) THEN
  975. IF SetWriteCache(msg(WriteCacheMsg).enable) THEN res := Res_OK; END;
  976. END;
  977. END Handle;
  978. PROCEDURE SetWriteCache(enable: BOOLEAN): BOOLEAN;
  979. VAR cmd: Command; status: SET;
  980. BEGIN {EXCLUSIVE}
  981. cmd := NewCommand(0EFH, Protocol_NonData);
  982. IF enable THEN
  983. cmd.features := 2;
  984. ELSE
  985. cmd.features := 82H;
  986. END;
  987. RETURN controller.ExecuteCommand(cmd, IOTimeout, status) = Res_OK;
  988. END SetWriteCache;
  989. PROCEDURE TransferEx(op: LONGINT; lba: HUGEINT; num: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): LONGINT;
  990. VAR command: Command; status: SET;
  991. BEGIN {EXCLUSIVE}
  992. IF (op # Disks.Read) & (op # Disks.Write) THEN RETURN Disks.Unsupported; END;
  993. IF (op = Disks.Write) & (Disks.ReadOnly IN flags) THEN RETURN Disks.WriteProtected; END;
  994. command := NewCommandTransfer(op, lba, num, bufAdr, dma);
  995. RETURN controller.ExecuteCommand(command, IOTimeout, status);
  996. END TransferEx;
  997. PROCEDURE Reset(): LONGINT;
  998. VAR res: WORD;
  999. BEGIN
  1000. IF TraceVerbose & (trace * TraceCommands # {}) THEN Show(name); KernelLog.String(" reset controller"); KernelLog.Ln; END;
  1001. res := controller.Reset();
  1002. IF (TraceVerbose & (trace * TraceErrors # {})) & (res # Res_OK) THEN
  1003. KernelLog.String(name); KernelLog.String(" reset failed"); KernelLog.Ln;
  1004. ELSIF TraceVerbose THEN
  1005. KernelLog.String(name); KernelLog.String(" reset done"); KernelLog.Ln;
  1006. END;
  1007. RETURN res;
  1008. END Reset;
  1009. (* Only for ATA 4 or older *)
  1010. PROCEDURE InitDevice(): LONGINT;
  1011. VAR command: CommandCHS; status: SET;
  1012. BEGIN
  1013. command := cmdCHS;
  1014. command.dev := dev; command.cmd := 91H; command.protocol := Protocol_NonData;
  1015. command.sector := chs.spt;
  1016. command.head := chs.hds;
  1017. RETURN controller.ExecuteCommand(command, IOTimeout, status);
  1018. END InitDevice;
  1019. PROCEDURE Flush(): LONGINT;
  1020. VAR res: WORD;
  1021. BEGIN
  1022. res := Disks.Unsupported;
  1023. IF FlushBit IN id.type THEN
  1024. res := SendATACommand(0E7H, IOTimeout);
  1025. END;
  1026. RETURN res;
  1027. END Flush;
  1028. PROCEDURE MediaEject(immediate, load: BOOLEAN): LONGINT;
  1029. BEGIN {EXCLUSIVE}
  1030. IF ~(RemovableBit IN id.type) THEN RETURN Disks.Unsupported; END;
  1031. RETURN SendATACommand(0EDH, IOTimeout); (* media eject *)
  1032. END MediaEject;
  1033. PROCEDURE MediaLock(lock: BOOLEAN): LONGINT;
  1034. VAR
  1035. command: CommandLBA;
  1036. res: WORD;
  1037. status: SET;
  1038. BEGIN {EXCLUSIVE}
  1039. IF RMSNBit IN id.type THEN
  1040. command := NewCommandLBA(0EFH, 0, 0); (* set features *)
  1041. IF lock THEN
  1042. command.features := 95H; (* enable RMSN *)
  1043. ELSE
  1044. command.features := 31H; (* disable RMSN *)
  1045. END;
  1046. res := controller.ExecuteCommand(command, IOTimeout, status);
  1047. ELSE
  1048. IF lock THEN
  1049. res := SendATACommand(0DEH, IOTimeout); (* media lock *)
  1050. ELSE
  1051. res := SendATACommand(0DFH, IOTimeout); (* media unlock *)
  1052. END;
  1053. END;
  1054. RETURN res;
  1055. END MediaLock;
  1056. PROCEDURE Powersave(): LONGINT;
  1057. BEGIN
  1058. RETURN SendATACommand(0E0H, IOTimeout); (* standby immediate *)
  1059. END Powersave;
  1060. PROCEDURE SendATACommand(cmd, ms: LONGINT): LONGINT;
  1061. VAR command: Command; status: SET;
  1062. BEGIN {EXCLUSIVE}
  1063. command := NewCommand(cmd, Protocol_NonData);
  1064. RETURN controller.ExecuteCommand(command, ms, status);
  1065. END SendATACommand;
  1066. PROCEDURE NewCommand(cmd: LONGINT; protocol: SET): Command;
  1067. VAR command: Command;
  1068. BEGIN
  1069. command := cmdLBA;
  1070. ResetCommand(command, SIZEOF(CommandDesc));
  1071. command.dev := dev; command.cmd := cmd; command.protocol := protocol;
  1072. RETURN command;
  1073. END NewCommand;
  1074. PROCEDURE NewCommandTransfer(op: LONGINT; lba: HUGEINT; count: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): Command;
  1075. VAR
  1076. CMD: ARRAY 8 OF LONGINT;
  1077. idx: LONGINT;
  1078. command: Command;
  1079. BEGIN
  1080. (* mode std ext dma dma ext
  1081. write 30 34 CA 35
  1082. read 20 24 C8 25
  1083. *)
  1084. CMD[0] := 30H; CMD[1] := 34H; CMD[2] := 0CAH; CMD[3] := 35H;
  1085. CMD[4] := 20H; CMD[5] := 24H; CMD[6] := 0C8H; CMD[7] := 25H;
  1086. IF op = Disks.Read THEN
  1087. INC(idx, 4);
  1088. ELSIF op = Disks.Write THEN
  1089. ELSE
  1090. HALT(Disks.Unsupported);
  1091. END;
  1092. IF dma THEN
  1093. INC(idx, 2);
  1094. END;
  1095. IF LBA48Bit IN id.type THEN
  1096. INC(idx, 1);
  1097. command := NewCommandLBA48(CMD[idx], lba, count);
  1098. ELSIF LBABit IN id.type THEN
  1099. command := NewCommandLBA(CMD[idx], SHORT(lba), count);
  1100. ELSE
  1101. command := NewCommandCHS(CMD[idx], SHORT(lba), count);
  1102. END;
  1103. command.read := op = Disks.Read;
  1104. command.bufAdr := bufAdr;
  1105. command.size := count*blockSize;
  1106. IF dma THEN
  1107. command.protocol := Protocol_DMA;
  1108. ELSE
  1109. command.protocol := Protocol_PIO;
  1110. END;
  1111. RETURN command;
  1112. END NewCommandTransfer;
  1113. PROCEDURE NewCommandCHS(cmd, lba, count: LONGINT): CommandCHS;
  1114. VAR x: LONGINT; command: CommandCHS;
  1115. BEGIN
  1116. command := cmdCHS;
  1117. ResetCommand(command, SIZEOF(CommandCHSDesc));
  1118. command.dev := dev; command.cmd := cmd;
  1119. command.count := count;
  1120. command.sector := lba MOD chs.spt + 1; x := lba DIV chs.spt;
  1121. command.head := x MOD chs.hds; command.cylinder := x DIV chs.hds;
  1122. ASSERT((command.sector < 100H) & (command.cylinder < 10000H) & (command.head < 10H));
  1123. RETURN command;
  1124. END NewCommandCHS;
  1125. PROCEDURE NewCommandLBA(cmd, lba, count: LONGINT): CommandLBA;
  1126. VAR command: CommandLBA;
  1127. BEGIN
  1128. command := cmdLBA;
  1129. ResetCommand(command, SIZEOF(CommandLBADesc));
  1130. command.dev := dev; command.cmd := cmd;
  1131. command.lba := lba; command.count := count;
  1132. RETURN command;
  1133. END NewCommandLBA;
  1134. PROCEDURE NewCommandLBA48(cmd: LONGINT; lba: HUGEINT; count: LONGINT): CommandLBA48;
  1135. VAR command: CommandLBA48;
  1136. BEGIN
  1137. command := cmdLBA48;
  1138. ResetCommand(command, SIZEOF(CommandLBA48Desc));
  1139. command.dev := dev; command.cmd := cmd;
  1140. command.lbaHigh := SHORT(ASH(lba, -32));command.lbaLow := SHORT(lba); command.count := count;
  1141. RETURN command;
  1142. END NewCommandLBA48;
  1143. (* Identify an ATA device. *)
  1144. PROCEDURE IdentifyDevice(buf: ARRAY OF INTEGER): LONGINT;
  1145. VAR res, size1, hsize: LONGINT;
  1146. BEGIN
  1147. (* ATA 4 or older *)
  1148. chs.cyls := LONG(buf[1]) MOD 10000H;
  1149. chs.hds := LONG(buf[3]) MOD 10000H;
  1150. chs.spt := LONG(buf[6]) MOD 10000H;
  1151. size := chs.cyls * chs.hds * chs.spt;
  1152. maxTransfer := 256;
  1153. IF IdentifyMajorVersion(buf, id) # Res_OK THEN RETURN Res_Err; END;
  1154. (* LBA *)
  1155. IF 9 IN SYSTEM.VAL(SET, buf[49]) THEN
  1156. size1 := ASH(LONG(buf[61]) MOD 10000H, 16) + LONG(buf[60]) MOD 10000H;
  1157. IF size < size1 THEN size := size1 END;
  1158. INCL(id.type, LBABit);
  1159. ELSE
  1160. KernelLog.String(", LBA not supported");
  1161. END;
  1162. (* LBA 48 *)
  1163. IF 10 IN SYSTEM.VAL(SET, buf[83]) THEN
  1164. hsize := ASH(LONG(buf[103]) MOD 10000H, 16) + LONG(buf[102]) MOD 10000H;
  1165. size1 := ASH(LONG(buf[101]) MOD 10000H, 16) + LONG(buf[100]) MOD 10000H;
  1166. IF hsize > 0 THEN res := 2826; END; (* size only 32-bit *)
  1167. IF size < size1 THEN size := size1 END;
  1168. maxTransfer := 65536;
  1169. INCL(id.type, LBA48Bit);
  1170. END;
  1171. getpar := chs;
  1172. IF size > 16383*16*63 THEN
  1173. getpar.cyls := size DIV (getpar.hds*getpar.spt);
  1174. END;
  1175. (* DMA support mandatory since ATA 4 except for CF *)
  1176. IF ~ataForcePio & (8 IN SYSTEM.VAL(SET, buf[49])) THEN
  1177. INCL(id.type, DMABit);
  1178. res := IdentifyDMA(buf, id);
  1179. ELSE
  1180. KernelLog.String(", DMA not supported");
  1181. END;
  1182. IF SYSTEM.VAL(SET, LONG(buf[0])) * {6,7} = {7} THEN
  1183. INCL(id.type, RemovableBit);
  1184. IF (4 IN SYSTEM.VAL(SET, LONG(buf[83]))) OR (0 IN SYSTEM.VAL(SET, LONG(buf[127]))) THEN INCL(id.type, RMSNBit) END;
  1185. END;
  1186. (* flush cache *)
  1187. IF 12 IN SYSTEM.VAL(SET, buf[83]) THEN
  1188. INCL(id.type, FlushBit);
  1189. END;
  1190. IF LONG(buf[0]) MOD 10000H = CompactFlashSignature THEN (*CF*)
  1191. INCL(id.type, CompactFlash);
  1192. KernelLog.String(", Compact Flash"); KernelLog.Ln;
  1193. END;
  1194. GetATAString(buf, 27, 46, id.model);
  1195. IF (buf[80] # -1) & (buf[81] # -1) THEN
  1196. id.ver := ASH(LONG(buf[80]) MOD 10000H, 16) + LONG(buf[81]) MOD 10000H
  1197. END;
  1198. IF ~(LBABit IN id.type) & ~((chs.hds <= 16) & (chs.spt <= 255)) THEN
  1199. KernelLog.String("2825 identify ata geometry bad"); KernelLog.Ln;
  1200. res := 2825;
  1201. END;
  1202. IF maxTransfer > DMABufferSize DIV BS THEN maxTransfer := DMABufferSize DIV BS; END;
  1203. RETURN res
  1204. END IdentifyDevice;
  1205. PROCEDURE ShowDevice;
  1206. VAR
  1207. i: LONGINT;
  1208. BEGIN
  1209. KernelLog.String(name); KernelLog.String(": ");
  1210. KernelLog.Int(size DIV (1024*1024 DIV blockSize), 1); KernelLog.String("MB");
  1211. IF LBABit IN id.type THEN
  1212. IF LBA48Bit IN id.type THEN KernelLog.String(", LBA48") ELSE KernelLog.String(", LBA") END;
  1213. ELSE
  1214. KernelLog.String(", "); ShowCHS(chs);
  1215. IF (getpar.cyls # chs.cyls) OR (getpar.hds # chs.hds) OR (getpar.spt # chs.spt) THEN
  1216. KernelLog.String(", ("); ShowCHS(getpar); KernelLog.Char(")")
  1217. END
  1218. END;
  1219. IF CompactFlash IN id.type THEN KernelLog.String(", CompactFlash") END; (*CF*)
  1220. IF RemovableBit IN id.type THEN KernelLog.String(", removable") END;
  1221. IF RMSNBit IN id.type THEN KernelLog.String(" (RMSN)") END;
  1222. IF id.majorVersion > 0 THEN KernelLog.String(", ATA/ATAPI-"); KernelLog.Int(id.majorVersion, 0); END;
  1223. IF DMABit IN id.type THEN
  1224. (*IF id.maxdmamode < 10 THEN
  1225. KernelLog.String(", MW DMA "); KernelLog.Int(id.maxdmamode, 1);
  1226. ELSE
  1227. KernelLog.String(", Ultra DMA "); KernelLog.Int(id.maxdmamode-10, 1);
  1228. END;*)
  1229. IF id.dmamode < 10 THEN
  1230. KernelLog.String(", MW DMA "); KernelLog.Int(id.dmamode, 1);
  1231. ELSE
  1232. KernelLog.String(", Ultra DMA "); KernelLog.Int(id.dmamode-10, 1);
  1233. END;
  1234. ELSE
  1235. KernelLog.String(", no DMA")
  1236. END;
  1237. KernelLog.String(", "); KernelLog.String(id.model);
  1238. IF id.ver # 0 THEN
  1239. KernelLog.String(", ver ");
  1240. i := 30; WHILE (i # 16) & ~ODD(ASH(id.ver, -i)) DO DEC(i) END;
  1241. KernelLog.Int(i-16, 1);KernelLog.Char(".");
  1242. KernelLog.Int(id.ver MOD 10000H, 1)
  1243. END;
  1244. KernelLog.Ln;
  1245. END ShowDevice;
  1246. PROCEDURE &Create*(acontroller: Controller; adev: LONGINT; identifyDevice: ARRAY OF INTEGER);
  1247. VAR
  1248. name: Plugins.Name;
  1249. str: ARRAY 32 OF CHAR;
  1250. i, res: LONGINT;
  1251. BEGIN
  1252. name := Name;
  1253. i := 0; WHILE name[i] # 0X DO INC(i) END;
  1254. name[i] := CHR(48 + acontroller.ctrlID*MaxDevicesC + adev); name[i+1] := 0X;
  1255. SetName(name);
  1256. controller := acontroller; dev := adev; init := FALSE;
  1257. NEW(cmdCHS); NEW(cmdLBA); NEW(cmdLBA48);
  1258. blockSize := BS;
  1259. res := IdentifyDevice(identifyDevice);
  1260. COPY(id.model, desc);
  1261. Machine.GetConfig(name, str);
  1262. IF (controller.bmbase = 0) OR (str="nodma") THEN
  1263. EXCL(id.type, DMABit);
  1264. END;
  1265. IF str="CHS" THEN
  1266. EXCL(id.type, LBABit);
  1267. EXCL(id.type, LBA48Bit);
  1268. END;
  1269. IF InitDevices & (res = Res_OK) & (id.type * {LBABit, AtapiBit} = {}) (*& (id.majorVersion > 0)*) & (id.majorVersion <= 4) THEN
  1270. res := InitDevice();
  1271. KernelLog.Ln; Show("InitDevice, res: "); KernelLog.Int(res, 0);
  1272. END;
  1273. device[acontroller.ctrlID*MaxDevicesC + adev] := SELF;
  1274. (* register device *)
  1275. flags := {};
  1276. IF RemovableBit IN id.type THEN INCL(flags, Disks.Removable) END;
  1277. IF str="ro" THEN INCL(flags, Disks.ReadOnly); END;
  1278. IF res # Res_OK THEN INCL(flags, Disks.ReadOnly); KernelLog.Ln; Show("Error RO"); END;
  1279. Disks.registry.Add(SELF, res);
  1280. ASSERT(res = Plugins.Ok);
  1281. END Create;
  1282. PROCEDURE Finalize;
  1283. VAR res: WORD;
  1284. BEGIN
  1285. (* unregister device *)
  1286. Disks.registry.Remove(SELF);
  1287. res := Flush();
  1288. device[controller.ctrlID*MaxDevicesC + dev] := NIL;
  1289. END Finalize;
  1290. END Device;
  1291. TYPE
  1292. DeviceATAPI* = OBJECT (Device)
  1293. VAR
  1294. sense, asc, ascq: LONGINT;
  1295. fieldPointer: ARRAY 3 OF CHAR;
  1296. cmdPacket: CommandPacket;
  1297. (* for writing audio tracks block size needs being set explicitely to 2352 *)
  1298. PROCEDURE SetBlockSize*(size: LONGINT);
  1299. BEGIN
  1300. blockSize := size;
  1301. END SetBlockSize;
  1302. (* ReadCapacity returns 1 for empty disks *)
  1303. PROCEDURE SetCapacity*(cap: LONGINT);
  1304. BEGIN
  1305. size := cap;
  1306. END SetCapacity;
  1307. PROCEDURE GetSize*(VAR asize, res: LONGINT);
  1308. BEGIN
  1309. res := Res_OK;
  1310. IF RemovableBit IN id.type THEN
  1311. BEGIN {EXCLUSIVE}
  1312. res := WaitUntilReady();
  1313. (*IF res # Res_OK THEN ProcessSense(res); RETURN; END;*)
  1314. res := ReadCapacity(blockSize, size);
  1315. IF (res = Res_OK) & (id.devtype = ATAPI_CDRom) & (blockSize # 2048) THEN blockSize := 2048 END; (* user data field only *)
  1316. ProcessSense(res);
  1317. END;
  1318. END;
  1319. IF res = Res_OK THEN
  1320. GetSize^(asize, res);
  1321. END;
  1322. END GetSize;
  1323. PROCEDURE Handle*(VAR msg: Disks.Message; VAR res: WORD);
  1324. BEGIN
  1325. res := Disks.Unsupported;
  1326. IF msg IS Disks.GetGeometryMsg THEN
  1327. ELSIF msg IS GetSenseMsg THEN
  1328. ProcessSense(res);
  1329. WITH msg: GetSenseMsg DO
  1330. msg.sense := sense; msg.asc := asc; msg.ascq := ascq;
  1331. COPY(fieldPointer, msg.fieldPointer);
  1332. END;
  1333. sense := -1;
  1334. ELSIF msg IS TestUnitReadyMsg THEN
  1335. res := TestUnitReady();
  1336. ProcessSense(res);
  1337. ELSE
  1338. Handle^(msg, res);
  1339. END
  1340. END Handle;
  1341. PROCEDURE ExecuteCommand*(read: BOOLEAN; VAR packet, data: ARRAY OF CHAR; ofs, size: LONGINT; dma: BOOLEAN): LONGINT;
  1342. VAR
  1343. command: CommandPacket;
  1344. i, res: LONGINT;
  1345. status: SET;
  1346. BEGIN {EXCLUSIVE}
  1347. ASSERT(LEN(packet) <= LEN(command.packet));
  1348. ASSERT(size <= LEN(data)-ofs); (* range check *)
  1349. command := cmdPacket;
  1350. command.packetLen := LEN(packet);
  1351. command.dev := dev; command.cmd := 0A0H;
  1352. IF dma THEN
  1353. command.protocol := Protocol_PacketDMA;
  1354. ELSE
  1355. command.protocol := Protocol_PacketPIO;
  1356. END;
  1357. command.read := read;
  1358. command.bufAdr := ADDRESSOF(data[ofs]);
  1359. command.size := size;
  1360. FOR i:= 0 TO LEN(command.packet)-1 DO
  1361. command.packet[i] := packet[i];
  1362. END;
  1363. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1364. sense := -1;
  1365. ProcessSense(res);
  1366. RETURN res;
  1367. END ExecuteCommand;
  1368. PROCEDURE ProcessSense(VAR res: WORD);
  1369. BEGIN
  1370. IF res = Res_OK THEN
  1371. sense := 0; asc := 0; ascq := 0;
  1372. ELSIF res # Res_OK THEN
  1373. res := 2831;
  1374. IF sense <= 0 THEN
  1375. IF RequestSense() = Res_OK THEN END;
  1376. END;
  1377. IF sense > 0 THEN
  1378. res := 2832;
  1379. IF (asc = 27H) THEN res := Disks.WriteProtected;
  1380. ELSIF (asc = 28H) & (ascq = 0) THEN res := Disks.MediaChanged;
  1381. ELSIF (asc = 3AH) THEN res := Disks.MediaMissing; END;
  1382. END;
  1383. END;
  1384. END ProcessSense;
  1385. PROCEDURE TransferEx*(op: LONGINT; lba: HUGEINT; num: LONGINT; bufAdr: ADDRESS; dma: BOOLEAN): LONGINT;
  1386. VAR
  1387. command: Command;
  1388. res, timeout: LONGINT;
  1389. status: SET;
  1390. BEGIN {EXCLUSIVE}
  1391. IF (op # Disks.Read) & (op # Disks.Write) & (op # WriteAndVerify) THEN RETURN Disks.Unsupported; END;
  1392. IF ((op = Disks.Write) OR (op = WriteAndVerify)) & (Disks.ReadOnly IN flags) THEN RETURN Disks.WriteProtected; END;
  1393. res := WaitUntilReady();
  1394. command := NewCommandPacketTransfer(op, lba, num, bufAdr, num*blockSize, dma);
  1395. IF op = Disks.Read THEN
  1396. timeout := IOTimeout;
  1397. ELSE
  1398. (* first write needs more time on some drives *)
  1399. timeout := 4*IOTimeout;
  1400. END;
  1401. res := controller.ExecuteCommand(command, timeout, status);
  1402. sense := -1;
  1403. ProcessSense(res);
  1404. RETURN res;
  1405. END TransferEx;
  1406. PROCEDURE WaitUntilReady(): LONGINT;
  1407. VAR res: WORD; retry: BOOLEAN;
  1408. BEGIN
  1409. REPEAT
  1410. retry := FALSE;
  1411. res := TestUnitReady();
  1412. IF res # Res_OK THEN
  1413. (*IF res = Res_Err THEN*)
  1414. IF RequestSense() = Res_OK THEN
  1415. retry := (asc = 29H) OR ((asc = 4) & (ascq = 1)) OR ((asc = 28H) & (ascq = 0));
  1416. END;
  1417. IF retry THEN Objects.Yield(); END;
  1418. END;
  1419. UNTIL ~retry;
  1420. res := Res_OK;
  1421. RETURN res;
  1422. END WaitUntilReady;
  1423. (* ATAPI funtions *)
  1424. PROCEDURE Reset(): LONGINT;
  1425. VAR
  1426. i, res : LONGINT;
  1427. status: SET;
  1428. command: Command;
  1429. BEGIN
  1430. IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
  1431. KernelLog.String(name); KernelLog.String(" device reset"); KernelLog.Ln;
  1432. END;
  1433. command := NewCommand(8, Protocol_DeviceReset); (* Device Reset *)
  1434. res := controller.ExecuteCommand(command, ResetTimeout, status); (* reset packet device *)
  1435. sense := -1;
  1436. IF TraceVerbose THEN
  1437. IF (trace * TraceErrors # {}) & (res # Res_OK) THEN
  1438. KernelLog.String(name); KernelLog.String(" reset failed"); KernelLog.Ln;
  1439. ELSIF (trace * (TraceCommands + TraceAtapi) # {}) THEN
  1440. KernelLog.String(name); KernelLog.String(" done"); KernelLog.Ln;
  1441. END;
  1442. END;
  1443. IF RequestSense() # Res_OK THEN
  1444. IF res # Res_OK THEN res := Reset^(); END;
  1445. END;
  1446. IF res # Res_OK THEN RETURN 2816; END;
  1447. GetSize(i, i);
  1448. (*undocumented: the first command after Reset Device shall be a PACKET command, other
  1449. commands like Set Features otherwise abort.*)
  1450. RETURN Res_OK;
  1451. END Reset;
  1452. PROCEDURE RequestSense*(): LONGINT;
  1453. VAR
  1454. command: CommandPacket;
  1455. buf: ARRAY 18 OF CHAR;
  1456. res: WORD;
  1457. status: SET;
  1458. BEGIN
  1459. IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
  1460. Show(name); KernelLog.String(" request sense"); KernelLog.Ln;
  1461. END;
  1462. sense := -1;
  1463. command := NewCommandPacket(03H);
  1464. command.protocol := Protocol_PacketPIO;
  1465. command.read := TRUE;
  1466. command.bufAdr := ADDRESSOF(buf[0]);
  1467. command.size := LEN(buf);
  1468. command.packet[4] := CHR(LEN(buf));
  1469. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1470. IF TraceVerbose & (trace * (TraceErrors + TraceSense) # {}) & (res # Res_OK) THEN
  1471. Show(name); KernelLog.String(" request sense failed"); KernelLog.Ln;
  1472. END;
  1473. IF res # Res_OK THEN RETURN res; END;
  1474. sense := ORD(buf[2]) MOD 10H;
  1475. asc := ORD(buf[12]);
  1476. ascq := ORD(buf[13]);
  1477. fieldPointer[0] := buf[15]; fieldPointer[1] := buf[16]; fieldPointer[2] := buf[17];
  1478. IF TraceVerbose & (trace * TraceSense # {}) THEN
  1479. KernelLog.String(name); KernelLog.String(" request sense: ");
  1480. KernelLog.Hex(sense, -2); KernelLog.String(", ");
  1481. KernelLog.Hex(asc, -2); KernelLog.String(", ");
  1482. KernelLog.Hex(ascq, -2);
  1483. KernelLog.String(", "); KernelLog.Int(res, 0);
  1484. KernelLog.Ln;
  1485. END;
  1486. RETURN Res_OK;
  1487. END RequestSense;
  1488. PROCEDURE TestUnitReady*(): LONGINT;
  1489. VAR
  1490. command: CommandPacket;
  1491. res: WORD;
  1492. status: SET;
  1493. BEGIN
  1494. IF TraceVerbose & (trace * (TraceCommands + TraceAtapi) # {}) THEN
  1495. Show(name); KernelLog.String(" test unit ready");KernelLog.Ln;
  1496. END;
  1497. command := NewCommandPacket(00H);
  1498. command.protocol := Protocol_PacketPIO;
  1499. command.read := TRUE;
  1500. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1501. sense := -1;
  1502. IF TraceVerbose & (trace * TraceErrors # {}) & (res # Res_OK) THEN
  1503. KernelLog.String(name); KernelLog.String(" not ready "); KernelLog.Int(res, 0); KernelLog.Ln;
  1504. END;
  1505. RETURN res;
  1506. END TestUnitReady;
  1507. PROCEDURE Flush(): LONGINT;
  1508. BEGIN
  1509. RETURN Flush^();
  1510. END Flush;
  1511. PROCEDURE MediaEject*(immediate, load: BOOLEAN): LONGINT;
  1512. VAR
  1513. command: CommandPacket;
  1514. res, timeout: LONGINT;
  1515. status: SET;
  1516. BEGIN {EXCLUSIVE}
  1517. command := NewCommandPacket(1BH); (* start/stop unit *)
  1518. command.protocol := Protocol_PacketPIO;
  1519. IF immediate THEN
  1520. command.packet[1] := 1X; (* return immediately *)
  1521. timeout := ATAPITimeout;
  1522. ELSE
  1523. timeout := 4*ATAPITimeout;
  1524. END;
  1525. IF load THEN
  1526. command.packet[4] := 3X; (* load medium *)
  1527. ELSE
  1528. command.packet[4] := 2X; (* eject medium *)
  1529. END;
  1530. res := controller.ExecuteCommand(command, timeout, status);
  1531. sense := -1;
  1532. (*IF res # Res_OK THEN
  1533. res := MediaEject^(load);
  1534. END;*)
  1535. ProcessSense(res);
  1536. RETURN res;
  1537. END MediaEject;
  1538. PROCEDURE MediaLock*(lock: BOOLEAN): LONGINT;
  1539. VAR
  1540. command: CommandPacket;
  1541. res: WORD;
  1542. status: SET;
  1543. BEGIN {EXCLUSIVE}
  1544. command := NewCommandPacket(1EH); (* prevent/allow medium removal *)
  1545. command.protocol := Protocol_PacketPIO;
  1546. IF lock THEN
  1547. command.packet[4] := 1X; (* 1: lock medium, 0: unlock medium *)
  1548. END;
  1549. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1550. sense := -1;
  1551. ProcessSense(res);
  1552. RETURN res;
  1553. END MediaLock;
  1554. PROCEDURE Powersave(): LONGINT;
  1555. VAR
  1556. command: CommandPacket;
  1557. res: WORD;
  1558. status: SET;
  1559. BEGIN {EXCLUSIVE}
  1560. command := NewCommandPacket(1BH); (* start/stop unit *)
  1561. command.protocol := Protocol_PacketPIO;
  1562. command.packet[1] := 1X; (* return immediately *)
  1563. command.packet[4] := 0X; (* stop medium *)
  1564. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1565. sense := -1;
  1566. ProcessSense(res);
  1567. RETURN res;
  1568. END Powersave;
  1569. PROCEDURE ReadCapacity*(VAR blkSize, size: LONGINT): LONGINT;
  1570. VAR
  1571. buf: ARRAY 2 OF LONGINT; res, sense: LONGINT;
  1572. command: CommandPacket; status: SET;
  1573. BEGIN
  1574. IF TraceVerbose & (trace * (TraceCommands + TraceAtapi + TraceInit) # {}) THEN
  1575. Show(name); KernelLog.String(" read capacity");KernelLog.Ln;
  1576. END;
  1577. command := NewCommandPacket(25H);
  1578. command.protocol := Protocol_PacketPIO;
  1579. command.read := TRUE;
  1580. command.bufAdr := ADDRESSOF(buf[0]);
  1581. command.size := 8;
  1582. res := controller.ExecuteCommand(command, ATAPITimeout, status);
  1583. sense := -1;
  1584. IF TraceVerbose & (trace * (TraceErrors + TraceInit) # {}) & (res # Res_OK) THEN
  1585. Show(name); KernelLog.String(" read capacity failed "); KernelLog.Int(res, 0); KernelLog.Ln;
  1586. END;
  1587. IF res # Res_OK THEN RETURN res; END;
  1588. size := buf[0]; blkSize := buf[1];
  1589. Swap(size); Swap(blkSize);
  1590. INC(size); (*read capacity returns the last sector*)
  1591. IF TraceVerbose & (trace * (TraceCommands + TraceAtapi + TraceInit) # {}) THEN
  1592. Show(name); KernelLog.String(" read capacity ");
  1593. KernelLog.Int(size*blkSize, 4); KernelLog.String(" Bytes"); KernelLog.Ln;
  1594. END;
  1595. RETURN res
  1596. END ReadCapacity;
  1597. PROCEDURE NewCommandPacketTransfer(op: LONGINT; lba: HUGEINT; count: LONGINT; bufAdr: ADDRESS; size: LONGINT; dma: BOOLEAN): CommandPacket;
  1598. VAR
  1599. command: CommandPacket;
  1600. i, lbaLow, lbaHigh: LONGINT;
  1601. BEGIN
  1602. command := cmdPacket;
  1603. ResetCommand(command, SIZEOF(CommandPacketDesc));
  1604. FOR i:= 0 TO LEN(command.packet)-1 DO
  1605. command.packet[i] := 0X;
  1606. END;
  1607. command.packetLen := 12;
  1608. command.dev := dev; command.cmd := 0A0H;
  1609. command.read := (op = Disks.Read);
  1610. command.count := count;
  1611. command.bufAdr := bufAdr;
  1612. command.size := size;
  1613. IF dma THEN
  1614. command.protocol := Protocol_PacketDMA;
  1615. INCL(command.features, ATAPI_DMA);
  1616. ELSE
  1617. command.protocol := Protocol_PacketPIO;
  1618. END;
  1619. CASE op OF
  1620. Disks.Read: command.packet[0] := 28X; (* 0A8X *)
  1621. | Disks.Write : command.packet[0] := 2AX; (* 0AAX *)
  1622. | WriteAndVerify: command.packet[0] := 2EX;
  1623. ELSE HALT(Disks.Unsupported);
  1624. END;
  1625. lbaLow := SHORT(lba);
  1626. lbaHigh := SHORT(ASH(lba, -32));
  1627. ASSERT((lbaHigh = 0) OR (lbaHigh = -1)); (* negative value possible for raw writing *)
  1628. command.packet[2] := CHR(ASH(lbaLow, -24) MOD 100H);
  1629. command.packet[3] := CHR(ASH(lbaLow, -16) MOD 100H);
  1630. command.packet[4] := CHR(ASH(lbaLow, -8) MOD 100H);
  1631. command.packet[5] := CHR(lbaLow MOD 100H);
  1632. (* 28, 2A *)
  1633. command.packet[7] := CHR(ASH(count, -8) MOD 100H);
  1634. command.packet[8] := CHR(count MOD 100H);
  1635. (* A8, AA *)
  1636. (*command.packet[6] := CHR(ASH(count, -24) MOD 100H);
  1637. command.packet[7] := CHR(ASH(count, -16) MOD 100H);
  1638. command.packet[8] := CHR(ASH(count, -8) MOD 100H);
  1639. command.packet[9] := CHR(count MOD 100H);*)
  1640. RETURN command;
  1641. END NewCommandPacketTransfer;
  1642. PROCEDURE NewCommandPacket*(cmd: LONGINT): CommandPacket;
  1643. VAR
  1644. command: CommandPacket;
  1645. i: LONGINT;
  1646. BEGIN
  1647. command := cmdPacket;
  1648. ResetCommand(command, SIZEOF(CommandPacketDesc));
  1649. FOR i:= 0 TO LEN(command.packet)-1 DO
  1650. command.packet[i] := 0X;
  1651. END;
  1652. command.packetLen := 12;
  1653. command.dev := dev; command.cmd := 0A0H;
  1654. command.packet[0] := CHR(cmd);
  1655. RETURN command;
  1656. END NewCommandPacket;
  1657. PROCEDURE IdentifyDevice(buf: ARRAY OF INTEGER): LONGINT;
  1658. VAR res : WORD;
  1659. BEGIN
  1660. maxTransfer := 65535;
  1661. IF 7 IN SYSTEM.VAL(SET, LONG(buf[0])) THEN (* removable *)
  1662. INCL(id.type, RemovableBit);
  1663. (* RMSN *)
  1664. IF (4 IN SYSTEM.VAL(SET, LONG(buf[83]))) OR (0 IN SYSTEM.VAL(SET, LONG(buf[127]))) THEN INCL(id.type, RMSNBit) END;
  1665. END;
  1666. IF 0 IN SYSTEM.VAL(SET, LONG(buf[0])) THEN
  1667. (* packet 16 byte *)
  1668. INCL(id.type, Packet16Bit);
  1669. END;
  1670. IF ~atapiForcePio & ( 8 IN SYSTEM.VAL(SET, LONG(buf[49]))) THEN
  1671. (* DMA *)
  1672. INCL(id.type, DMABit);
  1673. res := IdentifyDMA(buf, id);
  1674. END;
  1675. (* flush cache *)
  1676. IF 12 IN SYSTEM.VAL(SET, buf[83]) THEN
  1677. INCL(id.type, FlushBit);
  1678. END;
  1679. IF LONG(buf[0]) MOD 10000H = CompactFlashSignature THEN INCL(id.type, CompactFlash) END; (*CF*)
  1680. GetATAString(buf, 27, 46, id.model);
  1681. id.devtype := ASH(buf[0], -8) MOD 20H;
  1682. IF (buf[80] # -1) & (buf[81] # -1) THEN
  1683. id.ver := ASH(LONG(buf[80]) MOD 10000H, 16) + LONG(buf[81]) MOD 10000H
  1684. END;
  1685. IF Packet16Bit IN id.type THEN
  1686. Show("2833 ATAPI: unsupported packet size"); KernelLog.Ln;
  1687. res := 2833;
  1688. ELSE
  1689. res := Res_OK;
  1690. END;
  1691. IF maxTransfer > DMABufferSize DIV 2048 THEN maxTransfer := DMABufferSize DIV 2048; END;
  1692. RETURN res
  1693. END IdentifyDevice;
  1694. PROCEDURE ShowDevice;
  1695. VAR i: LONGINT;
  1696. BEGIN
  1697. KernelLog.String(name); KernelLog.String(": ");
  1698. KernelLog.String("ATAPI");
  1699. IF Packet16Bit IN id.type THEN KernelLog.String(" (16bit)") END;
  1700. ShowDevType(id.devtype);
  1701. IF CompactFlash IN id.type THEN KernelLog.String(", CompactFlash") END; (*CF*)
  1702. IF RemovableBit IN id.type THEN KernelLog.String(", removable") END;
  1703. IF RMSNBit IN id.type THEN KernelLog.String(" (RMSN)") END;
  1704. IF id.majorVersion > 0 THEN KernelLog.String(", ATA/ATAPI-"); KernelLog.Int(id.majorVersion, 0); END;
  1705. IF DMABit IN id.type THEN
  1706. (*IF id.maxdmamode < 10 THEN
  1707. KernelLog.String(", MW DMA "); KernelLog.Int(id.maxdmamode, 1);
  1708. ELSE
  1709. KernelLog.String(", Ultra DMA "); KernelLog.Int(id.maxdmamode-10, 1);
  1710. END;*)
  1711. IF id.dmamode < 10 THEN
  1712. KernelLog.String(", MW DMA ");KernelLog.Int(id.dmamode, 1);
  1713. ELSE
  1714. KernelLog.String(", Ultra DMA "); KernelLog.Int(id.dmamode-10, 1);
  1715. END;
  1716. ELSE
  1717. KernelLog.String(", no DMA")
  1718. END;
  1719. KernelLog.String(", "); KernelLog.String(id.model);
  1720. IF id.ver # 0 THEN
  1721. KernelLog.String(", ver ");
  1722. i := 30; WHILE (i # 16) & ~ODD(ASH(id.ver, -i)) DO DEC(i) END;
  1723. KernelLog.Int(i-16, 1); KernelLog.Char(".");
  1724. KernelLog.Int(id.ver MOD 10000H, 1)
  1725. END;
  1726. KernelLog.Ln;
  1727. END ShowDevice;
  1728. PROCEDURE &Create*(acontroller: Controller; adev: LONGINT; identifyDevice: ARRAY OF INTEGER);
  1729. VAR res: WORD;
  1730. BEGIN
  1731. INCL(id.type, AtapiBit);
  1732. NEW(cmdPacket);
  1733. Create^(acontroller, adev, identifyDevice);
  1734. (* CD_ROM by default ReadOnly *)
  1735. IF id.devtype = ATAPI_CDRom THEN INCL(flags, Disks.ReadOnly); END;
  1736. res := Reset();
  1737. init := TRUE;
  1738. END Create;
  1739. PROCEDURE Finalize;
  1740. BEGIN
  1741. Finalize^();
  1742. END Finalize;
  1743. END DeviceATAPI;
  1744. VAR
  1745. controller: ARRAY MaxControllers OF Controller;
  1746. device: ARRAY MaxDevices OF Device;
  1747. nofControllers: LONGINT;
  1748. installed: BOOLEAN;
  1749. irqCount, expectedCount: LONGINT;
  1750. (* Options that can be set using boot config strings *)
  1751. ataForcePio : BOOLEAN;
  1752. atapiForcePio : BOOLEAN;
  1753. trace* : SET;
  1754. (* Block port input instruction. *)
  1755. PROCEDURE -RepInWord(port, bufAdr: ADDRESS; len: SIZE);
  1756. CODE {SYSTEM.AMD64}
  1757. POP RCX
  1758. POP RDI
  1759. POP RDX
  1760. CLD
  1761. REP INSW
  1762. END RepInWord;
  1763. (* Block port out instruction. *)
  1764. PROCEDURE -RepOutWord(port, bufAdr: ADDRESS; len: SIZE);
  1765. CODE {SYSTEM.AMD64}
  1766. POP RCX
  1767. POP RSI
  1768. POP RDX
  1769. CLD
  1770. REP OUTSW
  1771. END RepOutWord;
  1772. PROCEDURE ResetCommand(cmd: Command; size: SIZE);
  1773. BEGIN
  1774. ASSERT(cmd # NIL);
  1775. ASSERT(size MOD 4 = 0);
  1776. Machine.Fill32(SYSTEM.VAL(ADDRESS, cmd), size, 0);
  1777. END ResetCommand;
  1778. PROCEDURE GetPhysAdr(bufAdr: ADDRESS; size: LONGINT; VAR physAdr: ADDRESS): BOOLEAN;
  1779. BEGIN
  1780. physAdr := Machine.PhysicalAdr(bufAdr, size);
  1781. RETURN physAdr # Machine.NilAdr
  1782. END GetPhysAdr;
  1783. (*PROCEDURE GetPRDAdr(VAR c: Command): BOOLEAN;
  1784. VAR p: LONGINT;
  1785. BEGIN
  1786. NEW(c.prdt); (* must not cross page boundary, see Intel 290550-002 sec. 2.7.3 *)
  1787. p := Machine.PhysicalAdr(ADDRESSOF(c.prdt.prd[0]), MaxPRD*8);
  1788. c.prdtPhysAdr := p;
  1789. RETURN (p # Machine.NilAdr) & (p DIV PageSize = (p+MaxPRD*8-1) DIV PageSize)
  1790. END GetPRDAdr;*)
  1791. (* NanoDelay - Delay at least ns nanoseconds. *)
  1792. PROCEDURE NanoDelay(ns: LONGINT);
  1793. BEGIN
  1794. ns := ns*4;
  1795. WHILE ns > 0 DO DEC(ns) END
  1796. END NanoDelay;
  1797. (* Swap a longint *)
  1798. PROCEDURE Swap(VAR a: ARRAY OF SYSTEM.BYTE);
  1799. VAR x: SYSTEM.BYTE;
  1800. BEGIN
  1801. x := a[0]; a[0] := a[3]; a[3] := x;
  1802. x := a[1]; a[1] := a[2]; a[2] := x;
  1803. END Swap;
  1804. PROCEDURE KernelLogHex(x, j, w: LONGINT);
  1805. VAR i: LONGINT; buf: ARRAY 10 OF CHAR;
  1806. BEGIN
  1807. IF j = 0 THEN
  1808. IF w >= 0 THEN j := 8 ELSE j := 2; w := -w END;
  1809. END;
  1810. FOR i := j+1 TO w DO KernelLog.Char(" ") END;
  1811. FOR i := j-1 TO 0 BY -1 DO
  1812. buf[i] := CHR(x MOD 10H + 48);
  1813. IF buf[i] > "9" THEN
  1814. buf[i] := CHR(ORD(buf[i]) - 48 + 65 - 10)
  1815. END;
  1816. x := x DIV 10H
  1817. END;
  1818. buf[j] := 0X;
  1819. KernelLog.String(buf)
  1820. END KernelLogHex;
  1821. (* Convert an ATA identify string to a readable format. *)
  1822. PROCEDURE GetATAString(VAR buf: ARRAY OF INTEGER; from, to: LONGINT; VAR s: ARRAY OF CHAR);
  1823. VAR i, j: LONGINT;
  1824. BEGIN
  1825. FOR i := from TO to DO
  1826. s[2*(i-from)] := CHR(buf[i] DIV 100H MOD 100H);
  1827. s[2*(i-from)+1] := CHR(buf[i] MOD 100H)
  1828. END;
  1829. s[2*(to-from+1)] := 0X;
  1830. i := 0; j := 0;
  1831. WHILE s[i] # 0X DO
  1832. IF (s[i] >= 20X) & (s[i] <= 7EX) THEN s[j] := s[i]; INC(j) END;
  1833. INC(i);
  1834. IF (j # 0) & (s[j-1] = 20X) THEN
  1835. WHILE s[i] = 20X DO INC(i) END
  1836. END
  1837. END;
  1838. IF (j # 0) & (s[j-1] = 20X) THEN DEC(j) END;
  1839. s[j] := 0X
  1840. END GetATAString;
  1841. PROCEDURE IdentifyMajorVersion(buf: ARRAY OF INTEGER; VAR id: ID): LONGINT;
  1842. VAR
  1843. a, i: LONGINT;
  1844. BEGIN
  1845. a := 0;
  1846. IF buf[80] # -1 THEN
  1847. i := 3;
  1848. WHILE i < 15 DO
  1849. IF i IN SYSTEM.VAL(SET, buf[80]) THEN a := i; END;
  1850. INC(i);
  1851. END;
  1852. END;
  1853. id.majorVersion := a;
  1854. RETURN Res_OK;
  1855. END IdentifyMajorVersion;
  1856. PROCEDURE IdentifyDMA(buf: ARRAY OF INTEGER; VAR id: ID): LONGINT;
  1857. VAR a, i: LONGINT;
  1858. BEGIN
  1859. (* Determine the maximum Multiword DMA mode supported *)
  1860. a := -1; i := 0;
  1861. WHILE i < 3 DO
  1862. IF i IN SYSTEM.VAL(SET, buf[63]) THEN INC(a); END;
  1863. INC(i);
  1864. END;
  1865. id.maxdmamode := a;
  1866. (* Determine the currently selected Multiword DMA mode *)
  1867. a:= -1; i := 8;
  1868. WHILE i < 11 DO
  1869. IF i IN SYSTEM.VAL(SET, buf[63]) THEN a := i-8; END;
  1870. INC(i);
  1871. END;
  1872. id.dmamode := a;
  1873. (* Are the fields reported in word 88 valid? *)
  1874. IF 2 IN SYSTEM.VAL(SET, buf[53]) THEN
  1875. (* Determine the maximum Ultra DMA mode supported *)
  1876. a := -1; i := 0;
  1877. WHILE i < 8 DO
  1878. IF i IN SYSTEM.VAL(SET, buf[88]) THEN INC(a); END;
  1879. INC(i);
  1880. END;
  1881. IF a >= 0 THEN
  1882. id.maxdmamode := 10+a;
  1883. END;
  1884. (* Determine the currntly seleccted Ultra DMA mode *)
  1885. a:= -1; i := 8;
  1886. WHILE i < 16 DO
  1887. IF i IN SYSTEM.VAL(SET, buf[88]) THEN a := i-8; END;
  1888. INC(i);
  1889. END;
  1890. IF a >= 0 THEN
  1891. id.dmamode := 10+a;
  1892. END;
  1893. END;
  1894. RETURN Res_OK;
  1895. END IdentifyDMA;
  1896. PROCEDURE ShowCHS(chs: CHS);
  1897. BEGIN
  1898. KernelLog.Int(chs.cyls, 1);
  1899. KernelLog.Char("*");
  1900. KernelLog.Int(chs.hds, 1);
  1901. KernelLog.Char("*");
  1902. KernelLog.Int(chs.spt, 1)
  1903. END ShowCHS;
  1904. PROCEDURE ShowDevType(t: LONGINT);
  1905. BEGIN
  1906. CASE t OF
  1907. | 0: KernelLog.String(" direct access")
  1908. | 1: KernelLog.String(" sequential access")
  1909. | 2: KernelLog.String(" printer")
  1910. | 3: KernelLog.String(" processor")
  1911. | 4: KernelLog.String(" write-once")
  1912. | 5: KernelLog.String(" cd-rom")
  1913. | 6: KernelLog.String(" scanner")
  1914. | 7: KernelLog.String(" optical memory")
  1915. | 8: KernelLog.String(" medium changer")
  1916. | 9: KernelLog.String(" communications")
  1917. ELSE KernelLog.String(" type "); KernelLog.Int(t, 1)
  1918. END;
  1919. KernelLog.String(" device")
  1920. END ShowDevType;
  1921. PROCEDURE ShowDevices;
  1922. VAR dev: Device; nofDevices, i : LONGINT;
  1923. BEGIN
  1924. nofDevices := 0;
  1925. FOR i := 0 TO MaxDevices-1 DO
  1926. dev := device[i];
  1927. IF dev # NIL THEN
  1928. dev.ShowDevice();
  1929. INC(nofDevices);
  1930. END;
  1931. END;
  1932. IF (nofDevices = 0) THEN
  1933. KernelLog.String("No devices found."); KernelLog.Ln;
  1934. END;
  1935. END ShowDevices;
  1936. PROCEDURE AddController*(ctrl: Controller);
  1937. VAR
  1938. i, c: LONGINT;
  1939. BEGIN {EXCLUSIVE}
  1940. IF ctrl = NIL THEN RETURN; END;
  1941. c := -1;
  1942. FOR i:=0 TO nofControllers-1 DO
  1943. IF controller[i] # NIL THEN
  1944. IF ctrl.cmdbase = controller[i].cmdbase THEN
  1945. Show("Resource conflict for controller "); KernelLog.Int(i, 0); KernelLog.Ln;
  1946. c := i;
  1947. END;
  1948. END;
  1949. END;
  1950. IF c = -1 THEN
  1951. Show("Adding controller ");
  1952. ELSE
  1953. controller[c].Finalize;
  1954. Show("Replacing controller ");
  1955. END;
  1956. KernelLogHex(ctrl.cmdbase, 4, 0); KernelLog.String(", ");
  1957. KernelLogHex(ctrl.cnlbase, 4, 0); KernelLog.String(", ");
  1958. KernelLogHex(ctrl.bmbase, 4, 0); KernelLog.String(", ");
  1959. KernelLog.String("IRQ: "); KernelLog.Int(ctrl.irq, 0);
  1960. (* Add Controller *)
  1961. IF ctrl.cmdbase = 1F0H THEN
  1962. i := 0;
  1963. ELSIF ctrl.cmdbase = 170H THEN
  1964. i := 1;
  1965. ELSE
  1966. IF c = -1 THEN
  1967. i := nofControllers;
  1968. INC(nofControllers);
  1969. ELSE
  1970. i := c;
  1971. END;
  1972. END;
  1973. controller[i] := ctrl;
  1974. ctrl.ctrlID := i;
  1975. KernelLog.String(": ");
  1976. KernelLog.String(Name); KernelLog.Int(i*MaxDevicesC, 1);
  1977. KernelLog.String(".."); KernelLog.Int((i+1)*MaxDevicesC-1, 1);
  1978. (* Init Controller *)
  1979. ctrl.InitController();
  1980. KernelLog.Ln;
  1981. END AddController;
  1982. PROCEDURE IdentifyController*(bus, dev, fkt: LONGINT);
  1983. VAR res, pcmd_ba, pcnl_ba, scmd_ba, scnl_ba, bm_ba, irq: LONGINT; s: SET;
  1984. c: Controller;
  1985. BEGIN
  1986. res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr0Reg, pcmd_ba);
  1987. IF ~((res = PCI.Done) & (ODD(pcmd_ba) OR (pcmd_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
  1988. DEC(pcmd_ba, pcmd_ba MOD 8);
  1989. res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr1Reg, pcnl_ba);
  1990. IF ~((res = PCI.Done) & (ODD(pcnl_ba) OR (pcnl_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
  1991. DEC(pcnl_ba, pcnl_ba MOD 8);
  1992. res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr2Reg, scmd_ba);
  1993. IF ~((res = PCI.Done) & (ODD(scmd_ba) OR (scmd_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
  1994. DEC(scmd_ba, scmd_ba MOD 8);
  1995. res := PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr3Reg, scnl_ba);
  1996. IF ~((res = PCI.Done) & (ODD(scnl_ba) OR (scnl_ba = 0))) THEN RETURN; END; (* I/O mapped or leagacy *)
  1997. DEC(scnl_ba, scnl_ba MOD 8);
  1998. IF PCI.ReadConfigDword(bus, dev, fkt, PCI.Adr4Reg, bm_ba) # PCI.Done THEN RETURN; END;
  1999. IF ~((res = PCI.Done) & (ODD(bm_ba) OR (bm_ba = 0))) THEN RETURN; END; (* I/O mapped or no BM *)
  2000. DEC(bm_ba, bm_ba MOD 10H);
  2001. IF bm_ba # 0 THEN
  2002. (* InitBusMaster *)
  2003. IF PCI.ReadConfigWord(bus, dev, fkt, PCI.CmdReg, SYSTEM.VAL(LONGINT, s)) # PCI.Done THEN RETURN; END;
  2004. IF s*{2,0} = {0} THEN
  2005. INCL(s, 2);
  2006. IF PCI.WriteConfigWord(bus, dev, fkt, PCI.CmdReg, SYSTEM.VAL(LONGINT, s)) # PCI.Done THEN RETURN; END;
  2007. END;
  2008. IF s*{2,0} # {2,0} THEN bm_ba := 0; END;
  2009. END;
  2010. IF PCI.ReadConfigByte(bus, dev, fkt, PCI.IntlReg, irq) # PCI.Done THEN RETURN; END;
  2011. IF ~((res = PCI.Done)) THEN RETURN; END;
  2012. (* Primary Controller *)
  2013. IF (pcmd_ba = 0) OR ((pcmd_ba = 1F0H) & (pcnl_ba = 3F0H)) THEN
  2014. NEW(c, 1F0H, 3F0H, bm_ba, 14);
  2015. ELSE
  2016. NEW(c, pcmd_ba, pcnl_ba, bm_ba, irq);
  2017. END;
  2018. AddController(c);
  2019. (* Secondary Controller *)
  2020. IF bm_ba # 0 THEN
  2021. bm_ba := bm_ba+8;
  2022. END;
  2023. IF (scmd_ba = 0) OR ((scmd_ba = 170H) & (scnl_ba = 370H)) THEN
  2024. NEW(c, 170H, 370H, bm_ba, 15);
  2025. ELSE
  2026. NEW(c, scmd_ba, scnl_ba, bm_ba, irq);
  2027. END;
  2028. AddController(c);
  2029. END IdentifyController;
  2030. PROCEDURE ScanPCI(vendor, id: LONGINT);
  2031. VAR idx, bus, dev, fkt: LONGINT;
  2032. BEGIN
  2033. idx := 0;
  2034. WHILE PCI.FindPCIDevice(id, vendor, idx, bus, dev, fkt) = PCI.Done DO
  2035. Show("Found PCI device "); KernelLogHex(vendor, 4, 0); KernelLog.String(":"); KernelLogHex(id, 4, 0); KernelLog.Ln;
  2036. IdentifyController(bus, dev, fkt);
  2037. INC(idx);
  2038. END;
  2039. END ScanPCI;
  2040. PROCEDURE ScanPCIClass(class: LONGINT);
  2041. VAR idx, bus, dev, fkt: LONGINT;
  2042. BEGIN
  2043. idx := 0;
  2044. WHILE PCI.FindPCIClassCode(class, idx, bus, dev, fkt) = PCI.Done DO
  2045. Show("Found PCI device on bus "); KernelLog.Int(bus, 0); KernelLog.String(", device "); KernelLog.Int(dev, 0);
  2046. KernelLog.String(", function "); KernelLog.Int(fkt, 0); KernelLog.Ln;
  2047. IdentifyController(bus, dev, fkt);
  2048. INC(idx);
  2049. END;
  2050. END ScanPCIClass;
  2051. PROCEDURE IdentifyControllers;
  2052. VAR
  2053. class: LONGINT;
  2054. str: ARRAY 32 OF CHAR;
  2055. c: Controller;
  2056. BEGIN
  2057. nofControllers := 2;
  2058. Machine.GetConfig("ATADetect", str);
  2059. IF str = "default" THEN
  2060. Show("Scanning PCI bus for known ATA controllers..."); KernelLog.Ln;
  2061. (* Intel *)
  2062. ScanPCI(8086H, 24DBH); (* ICH5 IDE *)
  2063. ScanPCI(8086H, 24D1H); (* ICH5 SATA (82801EB) *)
  2064. ScanPCI(8086H, 24DFH); (* ICH5R SATA (82801ER) *)
  2065. ScanPCI(8086H, 7111H); (* PIIX/4 EIDE, VMWare *)
  2066. ScanPCI(8086H, 7010H); (* PIIX/3 (82371SB) *)
  2067. ScanPCI(8086H, 2411H); (* 8xx Chipset IDE *)
  2068. ScanPCI(8086H, 2421H); (* IDE (82801AB) *)
  2069. ScanPCI(8086H, 244BH); (* IDE (82801E, U100) *)
  2070. ScanPCI(8086H, 24CAH); (* ICH4-M (82801DBM) *)
  2071. ScanPCI(8086H, 248AH); (* ICH3-M (82801CAM) *)
  2072. ScanPCI(8086H, 2641H); (* ICH6-M (82801FBM) *)
  2073. ScanPCI(8086H, 2651H); (* ICH6-W (82801 FB/FW SATA) *)
  2074. ScanPCI(8086H, 266FH); (* ICH6 (82801 FB/FBM/FR/FW/FRW SATA *)
  2075. (* Others *)
  2076. ScanPCI(1106H, 0571H); (* Asus A7V IDE *)
  2077. ScanPCI(105AH, 0D30H); (* Asus A7V Promise *)
  2078. ScanPCI(1078H, 0102H); (* Cyrix IDE *)
  2079. ScanPCI(1166H, 0211H); (* Serverworks *)
  2080. ELSIF str = "legacy" THEN
  2081. Show("Legacy mode..."); KernelLog.Ln;
  2082. NEW(c, 1F0H, 3F0H, 0, 14);
  2083. AddController(c);
  2084. NEW(c, 170H, 370H, 0, 15);
  2085. AddController(c);
  2086. ELSE
  2087. Show("Scanning PCI bus for IDE & SATA class devices ..."); KernelLog.Ln;
  2088. FOR class := 010100H TO 0101FFH DO ScanPCIClass(class); END; (* IDE *)
  2089. FOR class := 010600H TO 0106FFH DO ScanPCIClass(class); END; (* SATA *)
  2090. IF (str = "raid") OR (str = "raid+other") THEN
  2091. Show("Scanning PCI bus for RAID class devices..."); KernelLog.Ln;
  2092. FOR class := 010400H TO 0104FFH DO ScanPCIClass(class); END; (* RAID *)
  2093. END;
  2094. IF (str = "other") OR (str = "raid+other") THEN
  2095. Show("Scanning PCI bus for PCI mass storage class devices..."); KernelLog.Ln;
  2096. FOR class := 018000H TO 0180FFH DO ScanPCIClass(class); END; (* Mass Storage *)
  2097. END;
  2098. END;
  2099. END IdentifyControllers;
  2100. PROCEDURE GetOptions;
  2101. VAR str : ARRAY 32 OF CHAR;
  2102. PROCEDURE CharacterInString(ch : CHAR; CONST string : ARRAY OF CHAR) : BOOLEAN;
  2103. VAR i : LONGINT;
  2104. BEGIN
  2105. FOR i := 0 TO LEN(string)-1 DO
  2106. IF string[i] = ch THEN RETURN TRUE; END;
  2107. END;
  2108. RETURN FALSE;
  2109. END CharacterInString;
  2110. BEGIN
  2111. Machine.GetConfig("ATATrace", str);
  2112. IF str # "" THEN
  2113. Show("Trace option string: "); KernelLog.String(str); KernelLog.Ln;
  2114. IF CharacterInString("0", str) THEN trace := trace + TraceCommands; END;
  2115. IF CharacterInString("1", str) THEN trace := trace + TraceErrors; END;
  2116. IF CharacterInString("2", str) THEN trace := trace + TraceAtapi; END;
  2117. IF CharacterInString("3", str) THEN trace := trace + TraceSense; END;
  2118. IF CharacterInString("4", str) THEN trace := trace + TraceBuffer; END;
  2119. IF CharacterInString("5", str) THEN trace := trace + TraceInit; END;
  2120. END;
  2121. Machine.GetConfig("ATAForcePIO", str);
  2122. IF str = "1" THEN
  2123. ataForcePio := TRUE;
  2124. Show("Force PIO mode for ATA devices"); KernelLog.Ln;
  2125. END;
  2126. Machine.GetConfig("ATAPIForcePIO", str);
  2127. IF str = "1" THEN
  2128. atapiForcePio := TRUE;
  2129. Show("Force PIO mode for ATAPI devices"); KernelLog.Ln;
  2130. END;
  2131. END GetOptions;
  2132. PROCEDURE Install*;
  2133. BEGIN
  2134. IF ~installed THEN
  2135. installed := TRUE;
  2136. GetOptions;
  2137. IdentifyControllers;
  2138. KernelLog.String("ATADisks: Detected devices:"); KernelLog.Ln;
  2139. ShowDevices;
  2140. ELSE
  2141. KernelLog.String("ATADisks: Driver is already loaded, devices: "); KernelLog.Ln;
  2142. ShowDevices;
  2143. END;
  2144. END Install;
  2145. PROCEDURE ShowCounter*;
  2146. BEGIN
  2147. Show("IRQs: "); KernelLog.Int(irqCount, 0); KernelLog.Ln;
  2148. KernelLog.String("IRQ-Waits: "); KernelLog.Int(expectedCount, 0); KernelLog.Ln;
  2149. END ShowCounter;
  2150. PROCEDURE ResetCounter*;
  2151. BEGIN
  2152. Show("Reset Counter"); KernelLog.Ln;
  2153. irqCount := 0;
  2154. expectedCount := 0;
  2155. END ResetCounter;
  2156. PROCEDURE Show(CONST string : ARRAY OF CHAR);
  2157. BEGIN
  2158. KernelLog.String("ATADisks: "); KernelLog.String(string);
  2159. END Show;
  2160. (* Clean up unloaded module. *)
  2161. PROCEDURE Cleanup;
  2162. VAR i: LONGINT; d: Device;
  2163. BEGIN
  2164. FOR i := 0 TO MaxDevices-1 DO
  2165. d := device[i];
  2166. IF d # NIL THEN
  2167. d.Finalize;
  2168. END
  2169. END;
  2170. FOR i := 0 TO MaxControllers-1 DO
  2171. IF (controller[i] # NIL) THEN
  2172. controller[i].Finalize();
  2173. controller[i] := NIL
  2174. END
  2175. END
  2176. END Cleanup;
  2177. BEGIN
  2178. Modules.InstallTermHandler(Cleanup);
  2179. Install;
  2180. END ATADisks.
  2181. Error codes
  2182. 2801 device select failed before issueing
  2183. 2802 device select failed after issueing
  2184. 2807 dma transfer timeout
  2185. 2808 dma transfer failed
  2186. 2809 dma transfer error
  2187. 2812 identify atapi failed
  2188. 2813 size 0 device
  2189. 2814 identify failed
  2190. 2815 bad controller port
  2191. 2816 atapi reset failed
  2192. 2817 ata set parameters failed
  2193. 2819 pio read timeout
  2194. 2820 pio read error
  2195. 2821 pio read error
  2196. 2822 pio write error
  2197. 2823 pio write timeout
  2198. 2824 pio write error
  2199. 2825 identify ata geometry bad
  2200. 2826 transfer out of range
  2201. 2827 ATA: removable with no RMSN support
  2202. 2828 ATAPI: removable with no RMSN support
  2203. 2829 ATAPI: packet command failed
  2204. 2830 ATAPI: transfer packet error (did not complete)
  2205. 2831 ATAPI: transfer failed (no sense data)
  2206. 2832 ATAPI: transfer failed (sense data available)
  2207. 2833 ATAPI: unsupported packet size
  2208. 2834 ATAPI: could not enable RMSN
  2209. 2835 ATAPI: could not disable RMSN
  2210. 2836 RMSN: get media status failed
  2211. 2837 Eject failed
  2212. 2838 Lock failed
  2213. 2839 Unlock failed
  2214. AosATADisk.Install ~ SystemTools.Free ATADisks ~
  2215. ATAErrors.Text