ahci.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/dl.h>
  19. #include <grub/disk.h>
  20. #include <grub/mm.h>
  21. #include <grub/time.h>
  22. #include <grub/pci.h>
  23. #include <grub/ata.h>
  24. #include <grub/scsi.h>
  25. #include <grub/misc.h>
  26. #include <grub/list.h>
  27. #include <grub/loader.h>
  28. GRUB_MOD_LICENSE ("GPLv3+");
  29. struct grub_ahci_cmd_head
  30. {
  31. grub_uint32_t config;
  32. grub_uint32_t transferred;
  33. grub_uint64_t command_table_base;
  34. grub_uint32_t unused[4];
  35. };
  36. struct grub_ahci_prdt_entry
  37. {
  38. grub_uint64_t data_base;
  39. grub_uint32_t unused;
  40. grub_uint32_t size;
  41. };
  42. struct grub_ahci_cmd_table
  43. {
  44. grub_uint8_t cfis[0x40];
  45. grub_uint8_t command[0x10];
  46. grub_uint8_t reserved[0x30];
  47. struct grub_ahci_prdt_entry prdt[1];
  48. };
  49. struct grub_ahci_hba_port
  50. {
  51. grub_uint64_t command_list_base;
  52. grub_uint64_t fis_base;
  53. grub_uint32_t intstatus;
  54. grub_uint32_t inten;
  55. grub_uint32_t command;
  56. grub_uint32_t unused1;
  57. grub_uint32_t task_file_data;
  58. grub_uint32_t sig;
  59. grub_uint32_t status;
  60. grub_uint32_t unused2;
  61. grub_uint32_t sata_error;
  62. grub_uint32_t sata_active;
  63. grub_uint32_t command_issue;
  64. grub_uint32_t unused3;
  65. grub_uint32_t fbs;
  66. grub_uint32_t unused4[15];
  67. };
  68. enum grub_ahci_hba_port_command
  69. {
  70. GRUB_AHCI_HBA_PORT_CMD_ST = 0x01,
  71. GRUB_AHCI_HBA_PORT_CMD_SPIN_UP = 0x02,
  72. GRUB_AHCI_HBA_PORT_CMD_POWER_ON = 0x04,
  73. GRUB_AHCI_HBA_PORT_CMD_FRE = 0x10,
  74. GRUB_AHCI_HBA_PORT_CMD_CR = 0x8000,
  75. GRUB_AHCI_HBA_PORT_CMD_FR = 0x4000,
  76. };
  77. enum grub_ahci_hba_port_int_status
  78. {
  79. GRUB_AHCI_HBA_PORT_IS_IFS = (1UL << 27),
  80. GRUB_AHCI_HBA_PORT_IS_HBDS = (1UL << 28),
  81. GRUB_AHCI_HBA_PORT_IS_HBFS = (1UL << 29),
  82. GRUB_AHCI_HBA_PORT_IS_TFES = (1UL << 30),
  83. };
  84. #define GRUB_AHCI_HBA_PORT_IS_FATAL_MASK ( \
  85. GRUB_AHCI_HBA_PORT_IS_IFS | \
  86. GRUB_AHCI_HBA_PORT_IS_HBDS | \
  87. GRUB_AHCI_HBA_PORT_IS_HBFS | \
  88. GRUB_AHCI_HBA_PORT_IS_TFES)
  89. struct grub_ahci_hba
  90. {
  91. grub_uint32_t cap;
  92. grub_uint32_t global_control;
  93. grub_uint32_t intr_status;
  94. grub_uint32_t ports_implemented;
  95. grub_uint32_t unused1[6];
  96. grub_uint32_t bios_handoff;
  97. grub_uint32_t unused2[53];
  98. struct grub_ahci_hba_port ports[32];
  99. };
  100. struct grub_ahci_received_fis
  101. {
  102. char raw[4096];
  103. };
  104. enum
  105. {
  106. GRUB_AHCI_HBA_CAP_NPORTS_MASK = 0x1f
  107. };
  108. enum
  109. {
  110. GRUB_AHCI_HBA_GLOBAL_CONTROL_RESET = 0x00000001,
  111. GRUB_AHCI_HBA_GLOBAL_CONTROL_INTR_EN = 0x00000002,
  112. GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN = 0x80000000,
  113. };
  114. enum
  115. {
  116. GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED = 1,
  117. GRUB_AHCI_BIOS_HANDOFF_OS_OWNED = 2,
  118. GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED = 8,
  119. GRUB_AHCI_BIOS_HANDOFF_RWC = 8
  120. };
  121. struct grub_ahci_device
  122. {
  123. struct grub_ahci_device *next;
  124. struct grub_ahci_device **prev;
  125. volatile struct grub_ahci_hba *hba;
  126. int port;
  127. int num;
  128. struct grub_pci_dma_chunk *command_list_chunk;
  129. volatile struct grub_ahci_cmd_head *command_list;
  130. struct grub_pci_dma_chunk *command_table_chunk;
  131. volatile struct grub_ahci_cmd_table *command_table;
  132. struct grub_pci_dma_chunk *rfis;
  133. int present;
  134. int atapi;
  135. };
  136. static grub_err_t
  137. grub_ahci_readwrite_real (struct grub_ahci_device *dev,
  138. struct grub_disk_ata_pass_through_parms *parms, int reset);
  139. enum
  140. {
  141. GRUB_AHCI_CONFIG_READ = 0,
  142. GRUB_AHCI_CONFIG_CFIS_LENGTH_MASK = 0x1f,
  143. GRUB_AHCI_CONFIG_ATAPI = 0x20,
  144. GRUB_AHCI_CONFIG_WRITE = 0x40,
  145. GRUB_AHCI_CONFIG_PREFETCH = 0x80,
  146. GRUB_AHCI_CONFIG_RESET = 0x100,
  147. GRUB_AHCI_CONFIG_BIST = 0x200,
  148. GRUB_AHCI_CONFIG_CLEAR_R_OK = 0x400,
  149. GRUB_AHCI_CONFIG_PMP_MASK = 0xf000,
  150. GRUB_AHCI_CONFIG_PRDT_LENGTH_MASK = 0xffff0000,
  151. };
  152. #define GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT 0
  153. #define GRUB_AHCI_CONFIG_PMP_SHIFT 12
  154. #define GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT 16
  155. #define GRUB_AHCI_INTERRUPT_ON_COMPLETE 0x80000000
  156. #define GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH 0x200000
  157. static struct grub_ahci_device *grub_ahci_devices;
  158. static int numdevs;
  159. static int
  160. grub_ahci_pciinit (grub_pci_device_t dev,
  161. grub_pci_id_t pciid __attribute__ ((unused)),
  162. void *data __attribute__ ((unused)))
  163. {
  164. grub_pci_address_t addr;
  165. grub_uint32_t class;
  166. grub_uint32_t bar;
  167. unsigned i, nports;
  168. volatile struct grub_ahci_hba *hba;
  169. /* Read class. */
  170. addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
  171. class = grub_pci_read (addr);
  172. /* Check if this class ID matches that of a PCI IDE Controller. */
  173. if (class >> 8 != 0x010601)
  174. return 0;
  175. addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG5);
  176. bar = grub_pci_read (addr);
  177. if ((bar & (GRUB_PCI_ADDR_SPACE_MASK | GRUB_PCI_ADDR_MEM_TYPE_MASK
  178. | GRUB_PCI_ADDR_MEM_PREFETCH))
  179. != (GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32))
  180. return 0;
  181. addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  182. grub_pci_write_word (addr, grub_pci_read_word (addr)
  183. | GRUB_PCI_COMMAND_MEM_ENABLED | GRUB_PCI_COMMAND_BUS_MASTER);
  184. hba = grub_pci_device_map_range (dev, bar & GRUB_PCI_ADDR_MEM_MASK,
  185. sizeof (*hba));
  186. grub_dprintf ("ahci", "dev: %x:%x.%x\n", dev.bus, dev.device, dev.function);
  187. grub_dprintf ("ahci", "tfd[0]: %x\n",
  188. hba->ports[0].task_file_data);
  189. grub_dprintf ("ahci", "cmd[0]: %x\n",
  190. hba->ports[0].command);
  191. grub_dprintf ("ahci", "st[0]: %x\n",
  192. hba->ports[0].status);
  193. grub_dprintf ("ahci", "err[0]: %x\n",
  194. hba->ports[0].sata_error);
  195. grub_dprintf ("ahci", "tfd[1]: %x\n",
  196. hba->ports[1].task_file_data);
  197. grub_dprintf ("ahci", "cmd[1]: %x\n",
  198. hba->ports[1].command);
  199. grub_dprintf ("ahci", "st[1]: %x\n",
  200. hba->ports[1].status);
  201. grub_dprintf ("ahci", "err[1]: %x\n",
  202. hba->ports[1].sata_error);
  203. hba->ports[1].sata_error = hba->ports[1].sata_error;
  204. grub_dprintf ("ahci", "err[1]: %x\n",
  205. hba->ports[1].sata_error);
  206. grub_dprintf ("ahci", "BH:%x\n", hba->bios_handoff);
  207. if (! (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_OS_OWNED))
  208. {
  209. grub_uint64_t endtime;
  210. grub_dprintf ("ahci", "Requesting AHCI ownership\n");
  211. hba->bios_handoff = (hba->bios_handoff & ~GRUB_AHCI_BIOS_HANDOFF_RWC)
  212. | GRUB_AHCI_BIOS_HANDOFF_OS_OWNED;
  213. grub_dprintf ("ahci", "Waiting for BIOS to give up ownership\n");
  214. endtime = grub_get_time_ms () + 1000;
  215. while ((hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED)
  216. && grub_get_time_ms () < endtime);
  217. if (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED)
  218. {
  219. grub_dprintf ("ahci", "Forcibly taking ownership\n");
  220. hba->bios_handoff = GRUB_AHCI_BIOS_HANDOFF_OS_OWNED;
  221. hba->bios_handoff |= GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED;
  222. }
  223. else
  224. grub_dprintf ("ahci", "AHCI ownership obtained\n");
  225. }
  226. else
  227. grub_dprintf ("ahci", "AHCI is already in OS mode\n");
  228. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  229. grub_dprintf ("ahci", "err[1]: %x\n",
  230. hba->ports[1].sata_error);
  231. if (!(hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN))
  232. grub_dprintf ("ahci", "AHCI is in compat mode. Switching\n");
  233. else
  234. grub_dprintf ("ahci", "AHCI is in AHCI mode.\n");
  235. grub_dprintf ("ahci", "err[1]: %x\n",
  236. hba->ports[1].sata_error);
  237. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  238. /* {
  239. grub_uint64_t endtime;
  240. hba->global_control |= 1;
  241. endtime = grub_get_time_ms () + 1000;
  242. while (hba->global_control & 1)
  243. if (grub_get_time_ms () > endtime)
  244. {
  245. grub_dprintf ("ahci", "couldn't reset AHCI\n");
  246. return 0;
  247. }
  248. }*/
  249. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  250. grub_dprintf ("ahci", "err[1]: %x\n",
  251. hba->ports[1].sata_error);
  252. for (i = 0; i < 5; i++)
  253. {
  254. hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN;
  255. grub_millisleep (1);
  256. if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN)
  257. break;
  258. }
  259. if (i == 5)
  260. {
  261. grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
  262. return 0;
  263. }
  264. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  265. grub_dprintf ("ahci", "err[1]: %x\n",
  266. hba->ports[1].sata_error);
  267. grub_dprintf ("ahci", "err[1]: %x\n",
  268. hba->ports[1].sata_error);
  269. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  270. for (i = 0; i < 5; i++)
  271. {
  272. hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN;
  273. grub_millisleep (1);
  274. if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN)
  275. break;
  276. }
  277. if (i == 5)
  278. {
  279. grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
  280. return 0;
  281. }
  282. grub_dprintf ("ahci", "err[1]: %x\n",
  283. hba->ports[1].sata_error);
  284. grub_dprintf ("ahci", "GLC:%x\n", hba->global_control);
  285. nports = (GRUB_AHCI_HBA_CAP_NPORTS_MASK) + 1;
  286. grub_dprintf ("ahci", "%d AHCI ports, PI = 0x%x\n", nports,
  287. hba->ports_implemented);
  288. struct grub_ahci_device *adevs[GRUB_AHCI_HBA_CAP_NPORTS_MASK + 1];
  289. struct grub_ahci_device *failed_adevs[GRUB_AHCI_HBA_CAP_NPORTS_MASK + 1];
  290. grub_uint32_t fr_running = 0;
  291. for (i = 0; i < nports; i++)
  292. failed_adevs[i] = 0;
  293. for (i = 0; i < nports; i++)
  294. {
  295. if (!(hba->ports_implemented & (1 << i)))
  296. {
  297. adevs[i] = 0;
  298. continue;
  299. }
  300. adevs[i] = grub_zalloc (sizeof (*adevs[i]));
  301. if (!adevs[i])
  302. return 1;
  303. adevs[i]->hba = hba;
  304. adevs[i]->port = i;
  305. adevs[i]->present = 1;
  306. adevs[i]->num = numdevs++;
  307. }
  308. for (i = 0; i < nports; i++)
  309. if (adevs[i])
  310. {
  311. adevs[i]->hba->ports[adevs[i]->port].sata_error = adevs[i]->hba->ports[adevs[i]->port].sata_error;
  312. grub_dprintf ("ahci", "port: %d, err: %x\n", adevs[i]->port,
  313. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  314. adevs[i]->command_list_chunk = grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head) * 32);
  315. if (!adevs[i]->command_list_chunk)
  316. {
  317. adevs[i] = 0;
  318. continue;
  319. }
  320. adevs[i]->command_table_chunk = grub_memalign_dma32 (1024,
  321. sizeof (struct grub_ahci_cmd_table));
  322. if (!adevs[i]->command_table_chunk)
  323. {
  324. grub_dma_free (adevs[i]->command_list_chunk);
  325. adevs[i] = 0;
  326. continue;
  327. }
  328. adevs[i]->command_list = grub_dma_get_virt (adevs[i]->command_list_chunk);
  329. adevs[i]->command_table = grub_dma_get_virt (adevs[i]->command_table_chunk);
  330. grub_memset ((void *) adevs[i]->command_list, 0,
  331. sizeof (struct grub_ahci_cmd_table));
  332. grub_memset ((void *) adevs[i]->command_table, 0,
  333. sizeof (struct grub_ahci_cmd_head) * 32);
  334. adevs[i]->command_list->command_table_base
  335. = grub_dma_get_phys (adevs[i]->command_table_chunk);
  336. grub_dprintf ("ahci", "found device ahci%d (port %d), command_table = %p, command_list = %p\n",
  337. adevs[i]->num, adevs[i]->port, grub_dma_get_virt (adevs[i]->command_table_chunk),
  338. grub_dma_get_virt (adevs[i]->command_list_chunk));
  339. adevs[i]->hba->ports[adevs[i]->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  340. }
  341. grub_uint64_t endtime;
  342. endtime = grub_get_time_ms () + 1000;
  343. while (grub_get_time_ms () < endtime)
  344. {
  345. for (i = 0; i < nports; i++)
  346. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  347. break;
  348. if (i == nports)
  349. break;
  350. }
  351. for (i = 0; i < nports; i++)
  352. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  353. {
  354. grub_dprintf ("ahci", "couldn't stop FR on port %d\n", i);
  355. failed_adevs[i] = adevs[i];
  356. adevs[i] = 0;
  357. }
  358. for (i = 0; i < nports; i++)
  359. if (adevs[i])
  360. adevs[i]->hba->ports[adevs[i]->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
  361. endtime = grub_get_time_ms () + 1000;
  362. while (grub_get_time_ms () < endtime)
  363. {
  364. for (i = 0; i < nports; i++)
  365. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  366. break;
  367. if (i == nports)
  368. break;
  369. }
  370. for (i = 0; i < nports; i++)
  371. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  372. {
  373. grub_dprintf ("ahci", "couldn't stop CR on port %d\n", i);
  374. failed_adevs[i] = adevs[i];
  375. adevs[i] = 0;
  376. }
  377. for (i = 0; i < nports; i++)
  378. if (adevs[i])
  379. {
  380. adevs[i]->hba->ports[adevs[i]->port].inten = 0;
  381. adevs[i]->hba->ports[adevs[i]->port].intstatus = ~0;
  382. // adevs[i]->hba->ports[adevs[i]->port].fbs = 0;
  383. grub_dprintf ("ahci", "port: %d, err: %x\n", adevs[i]->port,
  384. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  385. adevs[i]->rfis = grub_memalign_dma32 (4096,
  386. sizeof (struct grub_ahci_received_fis));
  387. grub_memset ((char *) grub_dma_get_virt (adevs[i]->rfis), 0,
  388. sizeof (struct grub_ahci_received_fis));
  389. grub_memset ((char *) grub_dma_get_virt (adevs[i]->command_list_chunk), 0,
  390. sizeof (struct grub_ahci_cmd_head));
  391. grub_memset ((char *) grub_dma_get_virt (adevs[i]->command_table_chunk), 0,
  392. sizeof (struct grub_ahci_cmd_table));
  393. adevs[i]->hba->ports[adevs[i]->port].fis_base = grub_dma_get_phys (adevs[i]->rfis);
  394. adevs[i]->hba->ports[adevs[i]->port].command_list_base
  395. = grub_dma_get_phys (adevs[i]->command_list_chunk);
  396. adevs[i]->hba->ports[adevs[i]->port].command_issue = 0;
  397. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_FRE;
  398. }
  399. endtime = grub_get_time_ms () + 1000;
  400. while (grub_get_time_ms () < endtime)
  401. {
  402. for (i = 0; i < nports; i++)
  403. if (adevs[i] && !(adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  404. break;
  405. if (i == nports)
  406. break;
  407. }
  408. for (i = 0; i < nports; i++)
  409. if (adevs[i] && !(adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  410. {
  411. grub_dprintf ("ahci", "couldn't start FR on port %d\n", i);
  412. failed_adevs[i] = adevs[i];
  413. adevs[i] = 0;
  414. }
  415. for (i = 0; i < nports; i++)
  416. if (adevs[i])
  417. {
  418. grub_dprintf ("ahci", "port: %d, err: %x\n", adevs[i]->port,
  419. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  420. fr_running |= (1 << i);
  421. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_SPIN_UP;
  422. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_POWER_ON;
  423. adevs[i]->hba->ports[adevs[i]->port].command |= 1 << 28;
  424. grub_dprintf ("ahci", "port: %d, err: %x\n", adevs[i]->port,
  425. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  426. }
  427. /* 10ms should actually be enough. */
  428. endtime = grub_get_time_ms () + 100;
  429. while (grub_get_time_ms () < endtime)
  430. {
  431. for (i = 0; i < nports; i++)
  432. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].status & 7) != 3)
  433. break;
  434. if (i == nports)
  435. break;
  436. }
  437. for (i = 0; i < nports; i++)
  438. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].status & 7) != 3)
  439. {
  440. grub_dprintf ("ahci", "couldn't detect device on port %d\n", i);
  441. failed_adevs[i] = adevs[i];
  442. adevs[i] = 0;
  443. }
  444. for (i = 0; i < nports; i++)
  445. if (adevs[i])
  446. {
  447. grub_dprintf ("ahci", "port %d, err: %x\n", adevs[i]->port,
  448. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  449. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_POWER_ON;
  450. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_SPIN_UP;
  451. grub_dprintf ("ahci", "port %d, err: %x\n", adevs[i]->port,
  452. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  453. adevs[i]->hba->ports[adevs[i]->port].sata_error = ~0;
  454. grub_dprintf ("ahci", "port %d, err: %x\n", adevs[i]->port,
  455. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  456. grub_dprintf ("ahci", "port %d, offset: %x, tfd:%x, CMD: %x\n", adevs[i]->port,
  457. (int) ((char *) &adevs[i]->hba->ports[adevs[i]->port].task_file_data -
  458. (char *) adevs[i]->hba),
  459. adevs[i]->hba->ports[adevs[i]->port].task_file_data,
  460. adevs[i]->hba->ports[adevs[i]->port].command);
  461. grub_dprintf ("ahci", "port %d, err: %x\n", adevs[i]->port,
  462. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  463. }
  464. for (i = 0; i < nports; i++)
  465. if (adevs[i])
  466. {
  467. grub_dprintf ("ahci", "port %d, offset: %x, tfd:%x, CMD: %x\n", adevs[i]->port,
  468. (int) ((char *) &adevs[i]->hba->ports[adevs[i]->port].task_file_data -
  469. (char *) adevs[i]->hba),
  470. adevs[i]->hba->ports[adevs[i]->port].task_file_data,
  471. adevs[i]->hba->ports[adevs[i]->port].command);
  472. grub_dprintf ("ahci", "port: %d, err: %x\n", adevs[i]->port,
  473. adevs[i]->hba->ports[adevs[i]->port].sata_error);
  474. adevs[i]->hba->ports[adevs[i]->port].command
  475. = (adevs[i]->hba->ports[adevs[i]->port].command & 0x0fffffff) | (1 << 28)
  476. | GRUB_AHCI_HBA_PORT_CMD_SPIN_UP
  477. | GRUB_AHCI_HBA_PORT_CMD_POWER_ON;
  478. /* struct grub_disk_ata_pass_through_parms parms2;
  479. grub_memset (&parms2, 0, sizeof (parms2));
  480. parms2.taskfile.cmd = 8;
  481. grub_ahci_readwrite_real (dev, &parms2, 1);*/
  482. }
  483. endtime = grub_get_time_ms () + 32000;
  484. while (grub_get_time_ms () < endtime)
  485. {
  486. for (i = 0; i < nports; i++)
  487. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].task_file_data & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ)))
  488. break;
  489. if (i == nports)
  490. break;
  491. }
  492. for (i = 0; i < nports; i++)
  493. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].task_file_data & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ)))
  494. {
  495. grub_dprintf ("ahci", "port %d is busy\n", i);
  496. failed_adevs[i] = adevs[i];
  497. adevs[i] = 0;
  498. }
  499. for (i = 0; i < nports; i++)
  500. if (adevs[i])
  501. adevs[i]->hba->ports[adevs[i]->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST;
  502. endtime = grub_get_time_ms () + 1000;
  503. while (grub_get_time_ms () < endtime)
  504. {
  505. for (i = 0; i < nports; i++)
  506. if (adevs[i] && !(adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  507. break;
  508. if (i == nports)
  509. break;
  510. }
  511. for (i = 0; i < nports; i++)
  512. if (adevs[i] && !(adevs[i]->hba->ports[adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  513. {
  514. grub_dprintf ("ahci", "couldn't start CR on port %d\n", i);
  515. failed_adevs[i] = adevs[i];
  516. adevs[i] = 0;
  517. }
  518. grub_dprintf ("ahci", "cleaning up failed devs\n");
  519. for (i = 0; i < nports; i++)
  520. if (failed_adevs[i] && (fr_running & (1 << i)))
  521. failed_adevs[i]->hba->ports[failed_adevs[i]->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  522. endtime = grub_get_time_ms () + 1000;
  523. while (grub_get_time_ms () < endtime)
  524. {
  525. for (i = 0; i < nports; i++)
  526. if (failed_adevs[i] && (fr_running & (1 << i)) && (failed_adevs[i]->hba->ports[failed_adevs[i]->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  527. break;
  528. if (i == nports)
  529. break;
  530. }
  531. for (i = 0; i < nports; i++)
  532. if (failed_adevs[i])
  533. {
  534. grub_dma_free (failed_adevs[i]->command_list_chunk);
  535. grub_dma_free (failed_adevs[i]->command_table_chunk);
  536. grub_dma_free (failed_adevs[i]->rfis);
  537. }
  538. for (i = 0; i < nports; i++)
  539. if (adevs[i] && (adevs[i]->hba->ports[adevs[i]->port].sig >> 16) == 0xeb14)
  540. adevs[i]->atapi = 1;
  541. addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  542. grub_pci_write_word (addr, grub_pci_read_word (addr)
  543. | GRUB_PCI_COMMAND_BUS_MASTER);
  544. for (i = 0; i < nports; i++)
  545. if (adevs[i])
  546. {
  547. grub_list_push (GRUB_AS_LIST_P (&grub_ahci_devices),
  548. GRUB_AS_LIST (adevs[i]));
  549. }
  550. return 0;
  551. }
  552. static grub_err_t
  553. grub_ahci_initialize (void)
  554. {
  555. grub_pci_iterate (grub_ahci_pciinit, NULL);
  556. return grub_errno;
  557. }
  558. static grub_err_t
  559. grub_ahci_fini_hw (int noreturn __attribute__ ((unused)))
  560. {
  561. struct grub_ahci_device *dev;
  562. for (dev = grub_ahci_devices; dev; dev = dev->next)
  563. {
  564. grub_uint64_t endtime;
  565. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  566. endtime = grub_get_time_ms () + 1000;
  567. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  568. if (grub_get_time_ms () > endtime)
  569. {
  570. grub_dprintf ("ahci", "couldn't stop FR\n");
  571. break;
  572. }
  573. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
  574. endtime = grub_get_time_ms () + 1000;
  575. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  576. if (grub_get_time_ms () > endtime)
  577. {
  578. grub_dprintf ("ahci", "couldn't stop CR\n");
  579. break;
  580. }
  581. grub_dma_free (dev->command_list_chunk);
  582. grub_dma_free (dev->command_table_chunk);
  583. grub_dma_free (dev->rfis);
  584. dev->command_list_chunk = NULL;
  585. dev->command_table_chunk = NULL;
  586. dev->rfis = NULL;
  587. }
  588. return GRUB_ERR_NONE;
  589. }
  590. static int
  591. reinit_port (struct grub_ahci_device *dev)
  592. {
  593. struct grub_pci_dma_chunk *command_list;
  594. struct grub_pci_dma_chunk *command_table;
  595. grub_uint64_t endtime;
  596. command_list = grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head));
  597. if (!command_list)
  598. return 1;
  599. command_table = grub_memalign_dma32 (1024,
  600. sizeof (struct grub_ahci_cmd_table));
  601. if (!command_table)
  602. {
  603. grub_dma_free (command_list);
  604. return 1;
  605. }
  606. grub_dprintf ("ahci", "found device ahci%d (port %d)\n", dev->num, dev->port);
  607. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  608. endtime = grub_get_time_ms () + 1000;
  609. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  610. if (grub_get_time_ms () > endtime)
  611. {
  612. grub_dprintf ("ahci", "couldn't stop FR\n");
  613. goto out;
  614. }
  615. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
  616. endtime = grub_get_time_ms () + 1000;
  617. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  618. if (grub_get_time_ms () > endtime)
  619. {
  620. grub_dprintf ("ahci", "couldn't stop CR\n");
  621. goto out;
  622. }
  623. dev->hba->ports[dev->port].fbs = 2;
  624. dev->rfis = grub_memalign_dma32 (4096,
  625. sizeof (struct grub_ahci_received_fis));
  626. grub_memset ((char *) grub_dma_get_virt (dev->rfis), 0,
  627. sizeof (struct grub_ahci_received_fis));
  628. dev->hba->ports[dev->port].fis_base = grub_dma_get_phys (dev->rfis);
  629. dev->hba->ports[dev->port].command_list_base
  630. = grub_dma_get_phys (command_list);
  631. dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_FRE;
  632. while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  633. if (grub_get_time_ms () > endtime)
  634. {
  635. grub_dprintf ("ahci", "couldn't start FR\n");
  636. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  637. goto out;
  638. }
  639. dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST;
  640. while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  641. if (grub_get_time_ms () > endtime)
  642. {
  643. grub_dprintf ("ahci", "couldn't start CR\n");
  644. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_CR;
  645. goto out_stop_fr;
  646. }
  647. dev->hba->ports[dev->port].command
  648. = (dev->hba->ports[dev->port].command & 0x0fffffff) | (1 << 28) | 2 | 4;
  649. dev->command_list_chunk = command_list;
  650. dev->command_list = grub_dma_get_virt (command_list);
  651. dev->command_table_chunk = command_table;
  652. dev->command_table = grub_dma_get_virt (command_table);
  653. dev->command_list->command_table_base
  654. = grub_dma_get_phys (command_table);
  655. return 0;
  656. out_stop_fr:
  657. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  658. endtime = grub_get_time_ms () + 1000;
  659. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
  660. if (grub_get_time_ms () > endtime)
  661. {
  662. grub_dprintf ("ahci", "couldn't stop FR\n");
  663. break;
  664. }
  665. out:
  666. grub_dma_free (command_list);
  667. grub_dma_free (command_table);
  668. grub_dma_free (dev->rfis);
  669. return 1;
  670. }
  671. static grub_err_t
  672. grub_ahci_restore_hw (void)
  673. {
  674. struct grub_ahci_device **pdev;
  675. for (pdev = &grub_ahci_devices; *pdev; pdev = &((*pdev)->next))
  676. if (reinit_port (*pdev))
  677. {
  678. struct grub_ahci_device *odev;
  679. odev = *pdev;
  680. *pdev = (*pdev)->next;
  681. grub_free (odev);
  682. }
  683. return GRUB_ERR_NONE;
  684. }
  685. static int
  686. grub_ahci_iterate (grub_ata_dev_iterate_hook_t hook, void *hook_data,
  687. grub_disk_pull_t pull)
  688. {
  689. struct grub_ahci_device *dev;
  690. if (pull != GRUB_DISK_PULL_NONE)
  691. return 0;
  692. FOR_LIST_ELEMENTS(dev, grub_ahci_devices)
  693. if (hook (GRUB_SCSI_SUBSYSTEM_AHCI, dev->num, hook_data))
  694. return 1;
  695. return 0;
  696. }
  697. #if 0
  698. static int
  699. find_free_cmd_slot (struct grub_ahci_device *dev)
  700. {
  701. int i;
  702. for (i = 0; i < 32; i++)
  703. {
  704. if (dev->hda->ports[dev->port].command_issue & (1 << i))
  705. continue;
  706. if (dev->hda->ports[dev->port].sata_active & (1 << i))
  707. continue;
  708. return i;
  709. }
  710. return -1;
  711. }
  712. #endif
  713. enum
  714. {
  715. GRUB_AHCI_FIS_REG_H2D = 0x27
  716. };
  717. static const int register_map[11] = { 3 /* Features */,
  718. 12 /* Sectors */,
  719. 4 /* LBA low */,
  720. 5 /* LBA mid */,
  721. 6 /* LBA high */,
  722. 7 /* Device */,
  723. 2 /* CMD register */,
  724. 13 /* Sectors 48 */,
  725. 8 /* LBA48 low */,
  726. 9 /* LBA48 mid */,
  727. 10 /* LBA48 high */ };
  728. static grub_err_t
  729. grub_ahci_reset_port (struct grub_ahci_device *dev, int force)
  730. {
  731. grub_uint64_t endtime;
  732. dev->hba->ports[dev->port].sata_error = dev->hba->ports[dev->port].sata_error;
  733. if (force || (dev->hba->ports[dev->port].command_issue & 1)
  734. || (dev->hba->ports[dev->port].task_file_data & 0x80))
  735. {
  736. struct grub_disk_ata_pass_through_parms parms2;
  737. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
  738. dev->hba->ports[dev->port].command_issue = 0;
  739. dev->command_list[0].config = 0;
  740. dev->command_table[0].prdt[0].unused = 0;
  741. dev->command_table[0].prdt[0].size = 0;
  742. dev->command_table[0].prdt[0].data_base = 0;
  743. endtime = grub_get_time_ms () + 1000;
  744. while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  745. if (grub_get_time_ms () > endtime)
  746. {
  747. grub_dprintf ("ahci", "couldn't stop CR");
  748. return grub_error (GRUB_ERR_IO, "couldn't stop CR");
  749. }
  750. dev->hba->ports[dev->port].command |= 8;
  751. while (dev->hba->ports[dev->port].command & 8)
  752. if (grub_get_time_ms () > endtime)
  753. {
  754. grub_dprintf ("ahci", "couldn't set CLO\n");
  755. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
  756. return grub_error (GRUB_ERR_IO, "couldn't set CLO");
  757. }
  758. dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST;
  759. while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
  760. if (grub_get_time_ms () > endtime)
  761. {
  762. grub_dprintf ("ahci", "couldn't stop CR");
  763. dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
  764. return grub_error (GRUB_ERR_IO, "couldn't stop CR");
  765. }
  766. dev->hba->ports[dev->port].sata_error = dev->hba->ports[dev->port].sata_error;
  767. grub_memset (&parms2, 0, sizeof (parms2));
  768. parms2.taskfile.cmd = 8;
  769. return grub_ahci_readwrite_real (dev, &parms2, 1);
  770. }
  771. return GRUB_ERR_NONE;
  772. }
  773. static grub_err_t
  774. grub_ahci_readwrite_real (struct grub_ahci_device *dev,
  775. struct grub_disk_ata_pass_through_parms *parms, int reset)
  776. {
  777. struct grub_pci_dma_chunk *bufc;
  778. grub_uint64_t endtime;
  779. unsigned i;
  780. grub_err_t err = GRUB_ERR_NONE;
  781. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  782. dev->hba->ports[dev->port].task_file_data);
  783. if (!reset)
  784. grub_ahci_reset_port (dev, 0);
  785. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  786. dev->hba->ports[dev->port].task_file_data);
  787. dev->hba->ports[dev->port].task_file_data = 0;
  788. dev->hba->ports[dev->port].command_issue = 0;
  789. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  790. dev->hba->ports[dev->port].task_file_data);
  791. dev->hba->ports[dev->port].sata_error = dev->hba->ports[dev->port].sata_error;
  792. grub_dprintf("ahci", "grub_ahci_read (size=%llu, cmdsize = %llu)\n",
  793. (unsigned long long) parms->size,
  794. (unsigned long long) parms->cmdsize);
  795. if (parms->cmdsize != 0 && parms->cmdsize != 12 && parms->cmdsize != 16)
  796. return grub_error (GRUB_ERR_BUG, "incorrect ATAPI command size");
  797. if (parms->size > GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH)
  798. return grub_error (GRUB_ERR_BUG, "too big data buffer");
  799. if (parms->size)
  800. bufc = grub_memalign_dma32 (1024, parms->size + (parms->size & 1));
  801. else
  802. bufc = grub_memalign_dma32 (1024, 512);
  803. grub_dprintf ("ahci", "AHCI tfd = %x, CL=%p\n",
  804. dev->hba->ports[dev->port].task_file_data,
  805. dev->command_list);
  806. /* FIXME: support port multipliers. */
  807. dev->command_list[0].config
  808. = (5 << GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT)
  809. // | GRUB_AHCI_CONFIG_CLEAR_R_OK
  810. | (0 << GRUB_AHCI_CONFIG_PMP_SHIFT)
  811. | ((parms->size ? 1 : 0) << GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT)
  812. | (parms->cmdsize ? GRUB_AHCI_CONFIG_ATAPI : 0)
  813. | (parms->write ? GRUB_AHCI_CONFIG_WRITE : GRUB_AHCI_CONFIG_READ)
  814. | (parms->taskfile.cmd == 8 ? (1 << 8) : 0);
  815. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  816. dev->hba->ports[dev->port].task_file_data);
  817. dev->command_list[0].transferred = 0;
  818. dev->command_list[0].command_table_base
  819. = grub_dma_get_phys (dev->command_table_chunk);
  820. grub_memset ((char *) dev->command_list[0].unused, 0,
  821. sizeof (dev->command_list[0].unused));
  822. grub_memset ((char *) &dev->command_table[0], 0,
  823. sizeof (dev->command_table[0]));
  824. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  825. dev->hba->ports[dev->port].task_file_data);
  826. if (parms->cmdsize)
  827. grub_memcpy ((char *) dev->command_table[0].command, parms->cmd,
  828. parms->cmdsize);
  829. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  830. dev->hba->ports[dev->port].task_file_data);
  831. dev->command_table[0].cfis[0] = GRUB_AHCI_FIS_REG_H2D;
  832. dev->command_table[0].cfis[1] = 0x80;
  833. for (i = 0; i < sizeof (parms->taskfile.raw); i++)
  834. dev->command_table[0].cfis[register_map[i]] = parms->taskfile.raw[i];
  835. grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  836. dev->command_table[0].cfis[0], dev->command_table[0].cfis[1],
  837. dev->command_table[0].cfis[2], dev->command_table[0].cfis[3],
  838. dev->command_table[0].cfis[4], dev->command_table[0].cfis[5],
  839. dev->command_table[0].cfis[6], dev->command_table[0].cfis[7]);
  840. grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  841. dev->command_table[0].cfis[8], dev->command_table[0].cfis[9],
  842. dev->command_table[0].cfis[10], dev->command_table[0].cfis[11],
  843. dev->command_table[0].cfis[12], dev->command_table[0].cfis[13],
  844. dev->command_table[0].cfis[14], dev->command_table[0].cfis[15]);
  845. dev->command_table[0].prdt[0].data_base = grub_dma_get_phys (bufc);
  846. dev->command_table[0].prdt[0].unused = 0;
  847. dev->command_table[0].prdt[0].size = (parms->size - 1);
  848. grub_dprintf ("ahci", "PRDT = %" PRIxGRUB_UINT64_T ", %x, %x (%"
  849. PRIuGRUB_SIZE ")\n",
  850. dev->command_table[0].prdt[0].data_base,
  851. dev->command_table[0].prdt[0].unused,
  852. dev->command_table[0].prdt[0].size,
  853. (grub_size_t) ((char *) &dev->command_table[0].prdt[0]
  854. - (char *) &dev->command_table[0]));
  855. if (parms->write)
  856. grub_memcpy ((char *) grub_dma_get_virt (bufc), parms->buffer, parms->size);
  857. grub_dprintf ("ahci", "AHCI command scheduled\n");
  858. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  859. dev->hba->ports[dev->port].task_file_data);
  860. grub_dprintf ("ahci", "AHCI inten = %x\n",
  861. dev->hba->ports[dev->port].inten);
  862. grub_dprintf ("ahci", "AHCI intstatus = %x\n",
  863. dev->hba->ports[dev->port].intstatus);
  864. dev->hba->ports[dev->port].inten = 0xffffffff;//(1 << 2) | (1 << 5);
  865. dev->hba->ports[dev->port].intstatus = 0xffffffff;//(1 << 2) | (1 << 5);
  866. grub_dprintf ("ahci", "AHCI inten = %x\n",
  867. dev->hba->ports[dev->port].inten);
  868. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  869. dev->hba->ports[dev->port].task_file_data);
  870. dev->hba->ports[dev->port].sata_active = 1;
  871. dev->hba->ports[dev->port].command_issue = 1;
  872. grub_dprintf ("ahci", "AHCI sig = %x\n", dev->hba->ports[dev->port].sig);
  873. grub_dprintf ("ahci", "AHCI tfd = %x\n",
  874. dev->hba->ports[dev->port].task_file_data);
  875. endtime = grub_get_time_ms () + 20000;
  876. while ((dev->hba->ports[dev->port].command_issue & 1))
  877. if (grub_get_time_ms () > endtime ||
  878. (dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK))
  879. {
  880. grub_dprintf ("ahci", "AHCI status <%x %x %x %x>\n",
  881. dev->hba->ports[dev->port].command_issue,
  882. dev->hba->ports[dev->port].sata_active,
  883. dev->hba->ports[dev->port].intstatus,
  884. dev->hba->ports[dev->port].task_file_data);
  885. dev->hba->ports[dev->port].command_issue = 0;
  886. if (dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK)
  887. err = grub_error (GRUB_ERR_IO, "AHCI transfer error");
  888. else
  889. err = grub_error (GRUB_ERR_IO, "AHCI transfer timed out");
  890. if (!reset)
  891. grub_ahci_reset_port (dev, 1);
  892. break;
  893. }
  894. grub_dprintf ("ahci", "AHCI command completed <%x %x %x %x %x, %x %x>\n",
  895. dev->hba->ports[dev->port].command_issue,
  896. dev->hba->ports[dev->port].intstatus,
  897. dev->hba->ports[dev->port].task_file_data,
  898. dev->command_list[0].transferred,
  899. dev->hba->ports[dev->port].sata_error,
  900. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x00],
  901. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x18]);
  902. grub_dprintf ("ahci",
  903. "last PIO FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
  904. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x08],
  905. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x09],
  906. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0a],
  907. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0b],
  908. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0c],
  909. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0d],
  910. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0e],
  911. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0f]);
  912. grub_dprintf ("ahci",
  913. "last REG FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
  914. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x10],
  915. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x11],
  916. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x12],
  917. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x13],
  918. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x14],
  919. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x15],
  920. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x16],
  921. ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x17]);
  922. if (!parms->write)
  923. grub_memcpy (parms->buffer, (char *) grub_dma_get_virt (bufc), parms->size);
  924. grub_dma_free (bufc);
  925. return err;
  926. }
  927. static grub_err_t
  928. grub_ahci_readwrite (grub_ata_t disk,
  929. struct grub_disk_ata_pass_through_parms *parms,
  930. int spinup __attribute__((__unused__)))
  931. {
  932. return grub_ahci_readwrite_real (disk->data, parms, 0);
  933. }
  934. static grub_err_t
  935. grub_ahci_open (int id, int devnum, struct grub_ata *ata)
  936. {
  937. struct grub_ahci_device *dev;
  938. if (id != GRUB_SCSI_SUBSYSTEM_AHCI)
  939. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an AHCI device");
  940. FOR_LIST_ELEMENTS(dev, grub_ahci_devices)
  941. if (dev->num == devnum)
  942. break;
  943. if (! dev)
  944. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such AHCI device");
  945. grub_dprintf ("ahci", "opening AHCI dev `ahci%d'\n", dev->num);
  946. ata->data = dev;
  947. ata->dma = 1;
  948. ata->atapi = dev->atapi;
  949. ata->maxbuffer = GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH;
  950. ata->present = &dev->present;
  951. return GRUB_ERR_NONE;
  952. }
  953. static struct grub_ata_dev grub_ahci_dev =
  954. {
  955. .iterate = grub_ahci_iterate,
  956. .open = grub_ahci_open,
  957. .readwrite = grub_ahci_readwrite,
  958. };
  959. static struct grub_preboot *fini_hnd;
  960. GRUB_MOD_INIT(ahci)
  961. {
  962. grub_stop_disk_firmware ();
  963. /* AHCI initialization. */
  964. grub_ahci_initialize ();
  965. /* AHCI devices are handled by scsi.mod. */
  966. grub_ata_dev_register (&grub_ahci_dev);
  967. fini_hnd = grub_loader_register_preboot_hook (grub_ahci_fini_hw,
  968. grub_ahci_restore_hw,
  969. GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
  970. }
  971. GRUB_MOD_FINI(ahci)
  972. {
  973. grub_ahci_fini_hw (0);
  974. grub_loader_unregister_preboot_hook (fini_hnd);
  975. grub_ata_dev_unregister (&grub_ahci_dev);
  976. }