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