2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/disk.h>
22 #include <grub/time.h>
25 #include <grub/scsi.h>
26 #include <grub/misc.h>
27 #include <grub/list.h>
28 #include <grub/loader.h>
30 GRUB_MOD_LICENSE ("GPLv3+");
32 struct grub_ahci_cmd_head
35 grub_uint32_t transfered
;
36 grub_uint64_t command_table_base
;
37 grub_uint32_t unused
[4];
40 struct grub_ahci_prdt_entry
42 grub_uint64_t data_base
;
47 struct grub_ahci_cmd_table
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];
55 struct grub_ahci_hba_port
57 grub_uint64_t command_list_base
;
58 grub_uint64_t fis_base
;
59 grub_uint32_t intstatus
;
61 grub_uint32_t command
;
62 grub_uint32_t unused1
;
63 grub_uint32_t task_file_data
;
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
;
72 grub_uint32_t unused4
[15];
75 enum grub_ahci_hba_port_command
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,
88 grub_uint32_t global_control
;
89 grub_uint32_t intr_status
;
90 grub_uint32_t ports_implemented
;
91 grub_uint32_t unused1
[6];
92 grub_uint32_t bios_handoff
;
93 grub_uint32_t unused2
[53];
94 struct grub_ahci_hba_port ports
[32];
97 struct grub_ahci_received_fis
104 GRUB_AHCI_HBA_CAP_NPORTS_MASK
= 0x1f
109 GRUB_AHCI_HBA_GLOBAL_CONTROL_RESET
= 0x00000001,
110 GRUB_AHCI_HBA_GLOBAL_CONTROL_INTR_EN
= 0x00000002,
111 GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
= 0x80000000,
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
123 struct grub_ahci_device
125 struct grub_ahci_device
*next
;
126 struct grub_ahci_device
**prev
;
127 volatile struct grub_ahci_hba
*hba
;
130 struct grub_pci_dma_chunk
*command_list_chunk
;
131 volatile struct grub_ahci_cmd_head
*command_list
;
132 struct grub_pci_dma_chunk
*command_table_chunk
;
133 volatile struct grub_ahci_cmd_table
*command_table
;
134 struct grub_pci_dma_chunk
*rfis
;
140 grub_ahci_readwrite_real (struct grub_ahci_device
*dev
,
141 struct grub_disk_ata_pass_through_parms
*parms
,
142 int spinup
, int reset
);
147 GRUB_AHCI_CONFIG_READ
= 0,
148 GRUB_AHCI_CONFIG_CFIS_LENGTH_MASK
= 0x1f,
149 GRUB_AHCI_CONFIG_ATAPI
= 0x20,
150 GRUB_AHCI_CONFIG_WRITE
= 0x40,
151 GRUB_AHCI_CONFIG_PREFETCH
= 0x80,
152 GRUB_AHCI_CONFIG_RESET
= 0x100,
153 GRUB_AHCI_CONFIG_BIST
= 0x200,
154 GRUB_AHCI_CONFIG_CLEAR_R_OK
= 0x400,
155 GRUB_AHCI_CONFIG_PMP_MASK
= 0xf000,
156 GRUB_AHCI_CONFIG_PRDT_LENGTH_MASK
= 0xffff0000,
158 #define GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT 0
159 #define GRUB_AHCI_CONFIG_PMP_SHIFT 12
160 #define GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT 16
161 #define GRUB_AHCI_INTERRUPT_ON_COMPLETE 0x80000000
163 #define GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH 0x200000
165 static struct grub_ahci_device
*grub_ahci_devices
;
169 grub_ahci_pciinit (grub_pci_device_t dev
,
170 grub_pci_id_t pciid
__attribute__ ((unused
)),
171 void *data
__attribute__ ((unused
)))
173 grub_pci_address_t addr
;
177 volatile struct grub_ahci_hba
*hba
;
180 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_CLASS
);
181 class = grub_pci_read (addr
);
183 /* Check if this class ID matches that of a PCI IDE Controller. */
184 if (class >> 8 != 0x010601)
187 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_ADDRESS_REG5
);
189 bar
= grub_pci_read (addr
);
191 if ((bar
& (GRUB_PCI_ADDR_SPACE_MASK
| GRUB_PCI_ADDR_MEM_TYPE_MASK
192 | GRUB_PCI_ADDR_MEM_PREFETCH
))
193 != (GRUB_PCI_ADDR_SPACE_MEMORY
| GRUB_PCI_ADDR_MEM_TYPE_32
))
196 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_COMMAND
);
197 grub_pci_write_word (addr
, grub_pci_read_word (addr
)
198 | GRUB_PCI_COMMAND_MEM_ENABLED
);
200 hba
= grub_pci_device_map_range (dev
, bar
& GRUB_PCI_ADDR_MEM_MASK
,
202 grub_dprintf ("ahci", "dev: %x:%x.%x\n", dev
.bus
, dev
.device
, dev
.function
);
204 grub_dprintf ("ahci", "tfd[0]: %x\n",
205 hba
->ports
[0].task_file_data
);
206 grub_dprintf ("ahci", "cmd[0]: %x\n",
207 hba
->ports
[0].command
);
208 grub_dprintf ("ahci", "st[0]: %x\n",
209 hba
->ports
[0].status
);
210 grub_dprintf ("ahci", "err[0]: %x\n",
211 hba
->ports
[0].sata_error
);
213 grub_dprintf ("ahci", "tfd[1]: %x\n",
214 hba
->ports
[1].task_file_data
);
215 grub_dprintf ("ahci", "cmd[1]: %x\n",
216 hba
->ports
[1].command
);
217 grub_dprintf ("ahci", "st[1]: %x\n",
218 hba
->ports
[1].status
);
219 grub_dprintf ("ahci", "err[1]: %x\n",
220 hba
->ports
[1].sata_error
);
222 hba
->ports
[1].sata_error
= hba
->ports
[1].sata_error
;
224 grub_dprintf ("ahci", "err[1]: %x\n",
225 hba
->ports
[1].sata_error
);
227 grub_dprintf ("ahci", "BH:%x\n", hba
->bios_handoff
);
229 if (! (hba
->bios_handoff
& GRUB_AHCI_BIOS_HANDOFF_OS_OWNED
))
231 grub_uint64_t endtime
;
233 grub_dprintf ("ahci", "Requesting AHCI ownership\n");
234 hba
->bios_handoff
= (hba
->bios_handoff
& ~GRUB_AHCI_BIOS_HANDOFF_RWC
)
235 | GRUB_AHCI_BIOS_HANDOFF_OS_OWNED
;
236 grub_dprintf ("ahci", "Waiting for BIOS to give up ownership\n");
237 endtime
= grub_get_time_ms () + 1000;
238 while ((hba
->bios_handoff
& GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED
)
239 && grub_get_time_ms () < endtime
);
240 if (hba
->bios_handoff
& GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED
)
242 grub_dprintf ("ahci", "Forcibly taking ownership\n");
243 hba
->bios_handoff
= GRUB_AHCI_BIOS_HANDOFF_OS_OWNED
;
244 hba
->bios_handoff
|= GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED
;
247 grub_dprintf ("ahci", "AHCI ownership obtained\n");
250 grub_dprintf ("ahci", "AHCI is already in OS mode\n");
252 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
254 grub_dprintf ("ahci", "err[1]: %x\n",
255 hba
->ports
[1].sata_error
);
257 if (!(hba
->global_control
& GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
))
258 grub_dprintf ("ahci", "AHCI is in compat mode. Switching\n");
260 grub_dprintf ("ahci", "AHCI is in AHCI mode.\n");
262 grub_dprintf ("ahci", "err[1]: %x\n",
263 hba
->ports
[1].sata_error
);
265 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
268 grub_uint64_t endtime;
269 hba->global_control |= 1;
270 endtime = grub_get_time_ms () + 1000;
271 while (hba->global_control & 1)
272 if (grub_get_time_ms () > endtime)
274 grub_dprintf ("ahci", "couldn't reset AHCI\n");
279 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
281 grub_dprintf ("ahci", "err[1]: %x\n",
282 hba
->ports
[1].sata_error
);
284 for (i
= 0; i
< 5; i
++)
286 hba
->global_control
|= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
;
288 if (hba
->global_control
& GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
)
293 grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
297 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
299 grub_dprintf ("ahci", "err[1]: %x\n",
300 hba
->ports
[1].sata_error
);
302 grub_dprintf ("ahci", "err[1]: %x\n",
303 hba
->ports
[1].sata_error
);
305 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
307 for (i
= 0; i
< 5; i
++)
309 hba
->global_control
|= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
;
311 if (hba
->global_control
& GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN
)
316 grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
320 grub_dprintf ("ahci", "err[1]: %x\n",
321 hba
->ports
[1].sata_error
);
323 grub_dprintf ("ahci", "GLC:%x\n", hba
->global_control
);
325 nports
= (GRUB_AHCI_HBA_CAP_NPORTS_MASK
) + 1;
327 grub_dprintf ("ahci", "%d AHCI ports, PI = 0x%x\n", nports
,
328 hba
->ports_implemented
);
330 struct grub_ahci_device
*adevs
[GRUB_AHCI_HBA_CAP_NPORTS_MASK
+ 1];
331 struct grub_ahci_device
*failed_adevs
[GRUB_AHCI_HBA_CAP_NPORTS_MASK
+ 1];
332 grub_uint32_t fr_running
= 0;
334 for (i
= 0; i
< nports
; i
++)
336 for (i
= 0; i
< nports
; i
++)
338 if (!(hba
->ports_implemented
& (1 << i
)))
344 adevs
[i
] = grub_zalloc (sizeof (*adevs
[i
]));
350 adevs
[i
]->present
= 1;
351 adevs
[i
]->num
= numdevs
++;
354 for (i
= 0; i
< nports
; i
++)
357 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
= adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
;
358 grub_dprintf ("ahci", "err: %x\n",
359 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
361 adevs
[i
]->command_list_chunk
= grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head
) * 32);
362 if (!adevs
[i
]->command_list_chunk
)
368 adevs
[i
]->command_table_chunk
= grub_memalign_dma32 (1024,
369 sizeof (struct grub_ahci_cmd_table
));
370 if (!adevs
[i
]->command_table_chunk
)
372 grub_dma_free (adevs
[i
]->command_list_chunk
);
377 adevs
[i
]->command_list
= grub_dma_get_virt (adevs
[i
]->command_list_chunk
);
378 adevs
[i
]->command_table
= grub_dma_get_virt (adevs
[i
]->command_table_chunk
);
380 grub_memset ((void *) adevs
[i
]->command_list
, 0,
381 sizeof (struct grub_ahci_cmd_table
));
382 grub_memset ((void *) adevs
[i
]->command_table
, 0,
383 sizeof (struct grub_ahci_cmd_head
) * 32);
385 adevs
[i
]->command_list
->command_table_base
386 = grub_dma_get_phys (adevs
[i
]->command_table_chunk
);
388 grub_dprintf ("ahci", "found device ahci%d (port %d), command_table = %p, command_list = %p\n",
389 adevs
[i
]->num
, adevs
[i
]->port
, grub_dma_get_virt (adevs
[i
]->command_table_chunk
),
390 grub_dma_get_virt (adevs
[i
]->command_list_chunk
));
392 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
395 grub_uint64_t endtime
;
396 endtime
= grub_get_time_ms () + 1000;
398 while (grub_get_time_ms () < endtime
)
400 for (i
= 0; i
< nports
; i
++)
401 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
407 for (i
= 0; i
< nports
; i
++)
408 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
410 grub_dprintf ("ahci", "couldn't stop FR on port %d\n", i
);
411 failed_adevs
[i
] = adevs
[i
];
415 for (i
= 0; i
< nports
; i
++)
417 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_ST
;
418 endtime
= grub_get_time_ms () + 1000;
420 while (grub_get_time_ms () < endtime
)
422 for (i
= 0; i
< nports
; i
++)
423 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
429 for (i
= 0; i
< nports
; i
++)
430 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
432 grub_dprintf ("ahci", "couldn't stop CR on port %d\n", i
);
433 failed_adevs
[i
] = adevs
[i
];
436 for (i
= 0; i
< nports
; i
++)
439 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].inten
= 0;
440 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].intstatus
= ~0;
441 // adevs[i]->hba->ports[adevs[i]->port].fbs = 0;
443 grub_dprintf ("ahci", "err: %x\n",
444 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
446 adevs
[i
]->rfis
= grub_memalign_dma32 (4096,
447 sizeof (struct grub_ahci_received_fis
));
448 grub_memset ((char *) grub_dma_get_virt (adevs
[i
]->rfis
), 0,
449 sizeof (struct grub_ahci_received_fis
));
450 grub_memset ((char *) grub_dma_get_virt (adevs
[i
]->command_list_chunk
), 0,
451 sizeof (struct grub_ahci_cmd_head
));
452 grub_memset ((char *) grub_dma_get_virt (adevs
[i
]->command_table_chunk
), 0,
453 sizeof (struct grub_ahci_cmd_table
));
454 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].fis_base
= grub_dma_get_phys (adevs
[i
]->rfis
);
455 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command_list_base
456 = grub_dma_get_phys (adevs
[i
]->command_list_chunk
);
457 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command_issue
= 0;
458 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_FRE
;
461 endtime
= grub_get_time_ms () + 1000;
463 while (grub_get_time_ms () < endtime
)
465 for (i
= 0; i
< nports
; i
++)
466 if (adevs
[i
] && !(adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
472 for (i
= 0; i
< nports
; i
++)
473 if (adevs
[i
] && !(adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
475 grub_dprintf ("ahci", "couldn't start FR on port %d\n", i
);
476 failed_adevs
[i
] = adevs
[i
];
480 for (i
= 0; i
< nports
; i
++)
483 grub_dprintf ("ahci", "err: %x\n",
484 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
485 fr_running
|= (1 << i
);
487 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_SPIN_UP
;
488 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_POWER_ON
;
489 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= 1 << 28;
491 grub_dprintf ("ahci", "err: %x\n",
492 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
495 /* 10ms should actually be enough. */
496 endtime
= grub_get_time_ms () + 100;
498 while (grub_get_time_ms () < endtime
)
500 for (i
= 0; i
< nports
; i
++)
501 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].status
& 7) != 3)
507 for (i
= 0; i
< nports
; i
++)
508 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].status
& 7) != 3)
510 grub_dprintf ("ahci", "couldn't detect device on port %d\n", i
);
511 failed_adevs
[i
] = adevs
[i
];
515 for (i
= 0; i
< nports
; i
++)
518 grub_dprintf ("ahci", "err: %x\n",
519 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
521 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_POWER_ON
;
522 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_SPIN_UP
;
524 grub_dprintf ("ahci", "err: %x\n",
525 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
527 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
= ~0;
528 grub_dprintf ("ahci", "err: %x\n",
529 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
531 grub_dprintf ("ahci", "offset: %x, tfd:%x, CMD: %x\n",
532 (int) ((char *) &adevs
[i
]->hba
->ports
[adevs
[i
]->port
].task_file_data
-
533 (char *) adevs
[i
]->hba
),
534 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].task_file_data
,
535 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
);
537 grub_dprintf ("ahci", "err: %x\n",
538 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
542 for (i
= 0; i
< nports
; i
++)
545 grub_dprintf ("ahci", "offset: %x, tfd:%x, CMD: %x\n",
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
);
551 grub_dprintf ("ahci", "err: %x\n",
552 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sata_error
);
554 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
555 = (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& 0x0fffffff) | (1 << 28) | 2 | 4;
557 /* struct grub_disk_ata_pass_through_parms parms2;
558 grub_memset (&parms2, 0, sizeof (parms2));
559 parms2.taskfile.cmd = 8;
560 grub_ahci_readwrite_real (dev, &parms2, 1, 1);*/
563 endtime
= grub_get_time_ms () + 10000;
565 while (grub_get_time_ms () < endtime
)
567 for (i
= 0; i
< nports
; i
++)
568 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].task_file_data
& 0x88))
574 for (i
= 0; i
< nports
; i
++)
575 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].task_file_data
& 0x88))
577 grub_dprintf ("ahci", "port %d is busy\n", i
);
578 failed_adevs
[i
] = adevs
[i
];
582 for (i
= 0; i
< nports
; i
++)
584 adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_ST
;
586 endtime
= grub_get_time_ms () + 1000;
588 while (grub_get_time_ms () < endtime
)
590 for (i
= 0; i
< nports
; i
++)
591 if (adevs
[i
] && !(adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
597 for (i
= 0; i
< nports
; i
++)
598 if (adevs
[i
] && !(adevs
[i
]->hba
->ports
[adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
600 grub_dprintf ("ahci", "couldn't start CR on port %d\n", i
);
601 failed_adevs
[i
] = adevs
[i
];
605 grub_dprintf ("ahci", "cleaning up failed devs\n");
607 for (i
= 0; i
< nports
; i
++)
608 if (failed_adevs
[i
] && (fr_running
& (1 << i
)))
609 failed_adevs
[i
]->hba
->ports
[failed_adevs
[i
]->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
611 endtime
= grub_get_time_ms () + 1000;
612 while (grub_get_time_ms () < endtime
)
614 for (i
= 0; i
< nports
; i
++)
615 if (failed_adevs
[i
] && (fr_running
& (1 << i
)) && (failed_adevs
[i
]->hba
->ports
[failed_adevs
[i
]->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
620 for (i
= 0; i
< nports
; i
++)
623 grub_dma_free (failed_adevs
[i
]->command_list_chunk
);
624 grub_dma_free (failed_adevs
[i
]->command_table_chunk
);
625 grub_dma_free (failed_adevs
[i
]->rfis
);
628 for (i
= 0; i
< nports
; i
++)
629 if (adevs
[i
] && (adevs
[i
]->hba
->ports
[adevs
[i
]->port
].sig
>> 16) == 0xeb14)
632 addr
= grub_pci_make_address (dev
, GRUB_PCI_REG_COMMAND
);
633 grub_pci_write_word (addr
, grub_pci_read_word (addr
)
634 | GRUB_PCI_COMMAND_BUS_MASTER
);
636 for (i
= 0; i
< nports
; i
++)
639 grub_list_push (GRUB_AS_LIST_P (&grub_ahci_devices
),
640 GRUB_AS_LIST (adevs
[i
]));
647 grub_ahci_initialize (void)
649 grub_pci_iterate (grub_ahci_pciinit
, NULL
);
654 grub_ahci_fini_hw (int noreturn
__attribute__ ((unused
)))
656 struct grub_ahci_device
*dev
;
658 for (dev
= grub_ahci_devices
; dev
; dev
= dev
->next
)
660 grub_uint64_t endtime
;
662 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
663 endtime
= grub_get_time_ms () + 1000;
664 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
665 if (grub_get_time_ms () > endtime
)
667 grub_dprintf ("ahci", "couldn't stop FR\n");
671 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_ST
;
672 endtime
= grub_get_time_ms () + 1000;
673 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
674 if (grub_get_time_ms () > endtime
)
676 grub_dprintf ("ahci", "couldn't stop CR\n");
679 grub_dma_free (dev
->command_list_chunk
);
680 grub_dma_free (dev
->command_table_chunk
);
681 grub_dma_free (dev
->rfis
);
682 dev
->command_list_chunk
= NULL
;
683 dev
->command_table_chunk
= NULL
;
686 return GRUB_ERR_NONE
;
690 reinit_port (struct grub_ahci_device
*dev
)
692 struct grub_pci_dma_chunk
*command_list
;
693 struct grub_pci_dma_chunk
*command_table
;
694 grub_uint64_t endtime
;
696 command_list
= grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head
));
700 command_table
= grub_memalign_dma32 (1024,
701 sizeof (struct grub_ahci_cmd_table
));
704 grub_dma_free (command_list
);
708 grub_dprintf ("ahci", "found device ahci%d (port %d)\n", dev
->num
, dev
->port
);
710 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
711 endtime
= grub_get_time_ms () + 1000;
712 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
713 if (grub_get_time_ms () > endtime
)
715 grub_dprintf ("ahci", "couldn't stop FR\n");
719 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_ST
;
720 endtime
= grub_get_time_ms () + 1000;
721 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
722 if (grub_get_time_ms () > endtime
)
724 grub_dprintf ("ahci", "couldn't stop CR\n");
728 dev
->hba
->ports
[dev
->port
].fbs
= 2;
730 dev
->rfis
= grub_memalign_dma32 (4096,
731 sizeof (struct grub_ahci_received_fis
));
732 grub_memset ((char *) grub_dma_get_virt (dev
->rfis
), 0,
733 sizeof (struct grub_ahci_received_fis
));
734 dev
->hba
->ports
[dev
->port
].fis_base
= grub_dma_get_phys (dev
->rfis
);
735 dev
->hba
->ports
[dev
->port
].command_list_base
736 = grub_dma_get_phys (command_list
);
737 dev
->hba
->ports
[dev
->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_FRE
;
738 while (!(dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
739 if (grub_get_time_ms () > endtime
)
741 grub_dprintf ("ahci", "couldn't start FR\n");
742 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
745 dev
->hba
->ports
[dev
->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_ST
;
746 while (!(dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
747 if (grub_get_time_ms () > endtime
)
749 grub_dprintf ("ahci", "couldn't start CR\n");
750 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_CR
;
754 dev
->hba
->ports
[dev
->port
].command
755 = (dev
->hba
->ports
[dev
->port
].command
& 0x0fffffff) | (1 << 28) | 2 | 4;
757 dev
->command_list_chunk
= command_list
;
758 dev
->command_list
= grub_dma_get_virt (command_list
);
759 dev
->command_table_chunk
= command_table
;
760 dev
->command_table
= grub_dma_get_virt (command_table
);
761 dev
->command_list
->command_table_base
762 = grub_dma_get_phys (command_table
);
766 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
767 endtime
= grub_get_time_ms () + 1000;
768 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_FR
))
769 if (grub_get_time_ms () > endtime
)
771 grub_dprintf ("ahci", "couldn't stop FR\n");
775 grub_dma_free (command_list
);
776 grub_dma_free (command_table
);
777 grub_dma_free (dev
->rfis
);
782 grub_ahci_restore_hw (void)
784 struct grub_ahci_device
**pdev
;
786 for (pdev
= &grub_ahci_devices
; *pdev
; pdev
= &((*pdev
)->next
))
787 if (reinit_port (*pdev
))
789 struct grub_ahci_device
*odev
;
791 *pdev
= (*pdev
)->next
;
794 return GRUB_ERR_NONE
;
801 grub_ahci_iterate (grub_ata_dev_iterate_hook_t hook
, void *hook_data
,
802 grub_disk_pull_t pull
)
804 struct grub_ahci_device
*dev
;
806 if (pull
!= GRUB_DISK_PULL_NONE
)
809 FOR_LIST_ELEMENTS(dev
, grub_ahci_devices
)
810 if (hook (GRUB_SCSI_SUBSYSTEM_AHCI
, dev
->num
, hook_data
))
818 find_free_cmd_slot (struct grub_ahci_device
*dev
)
821 for (i
= 0; i
< 32; i
++)
823 if (dev
->hda
->ports
[dev
->port
].command_issue
& (1 << i
))
825 if (dev
->hda
->ports
[dev
->port
].sata_active
& (1 << i
))
835 GRUB_AHCI_FIS_REG_H2D
= 0x27
838 static const int register_map
[11] = { 3 /* Features */,
844 2 /* CMD register */,
848 10 /* LBA48 high */ };
851 grub_ahci_reset_port (struct grub_ahci_device
*dev
, int force
)
853 grub_uint64_t endtime
;
855 dev
->hba
->ports
[dev
->port
].sata_error
= dev
->hba
->ports
[dev
->port
].sata_error
;
857 if (force
|| (dev
->hba
->ports
[dev
->port
].command_issue
& 1)
858 || (dev
->hba
->ports
[dev
->port
].task_file_data
& 0x80))
860 struct grub_disk_ata_pass_through_parms parms2
;
861 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_ST
;
862 dev
->hba
->ports
[dev
->port
].command_issue
= 0;
863 dev
->command_list
[0].config
= 0;
864 dev
->command_table
[0].prdt
[0].unused
= 0;
865 dev
->command_table
[0].prdt
[0].size
= 0;
866 dev
->command_table
[0].prdt
[0].data_base
= 0;
868 endtime
= grub_get_time_ms () + 1000;
869 while ((dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
870 if (grub_get_time_ms () > endtime
)
872 grub_dprintf ("ahci", "couldn't stop CR");
873 return grub_error (GRUB_ERR_IO
, "couldn't stop CR");
875 dev
->hba
->ports
[dev
->port
].command
|= 8;
876 while (dev
->hba
->ports
[dev
->port
].command
& 8)
877 if (grub_get_time_ms () > endtime
)
879 grub_dprintf ("ahci", "couldn't set CLO\n");
880 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_FRE
;
881 return grub_error (GRUB_ERR_IO
, "couldn't set CLO");
884 dev
->hba
->ports
[dev
->port
].command
|= GRUB_AHCI_HBA_PORT_CMD_ST
;
885 while (!(dev
->hba
->ports
[dev
->port
].command
& GRUB_AHCI_HBA_PORT_CMD_CR
))
886 if (grub_get_time_ms () > endtime
)
888 grub_dprintf ("ahci", "couldn't stop CR");
889 dev
->hba
->ports
[dev
->port
].command
&= ~GRUB_AHCI_HBA_PORT_CMD_ST
;
890 return grub_error (GRUB_ERR_IO
, "couldn't stop CR");
892 dev
->hba
->ports
[dev
->port
].sata_error
= dev
->hba
->ports
[dev
->port
].sata_error
;
893 grub_memset (&parms2
, 0, sizeof (parms2
));
894 parms2
.taskfile
.cmd
= 8;
895 return grub_ahci_readwrite_real (dev
, &parms2
, 1, 1);
897 return GRUB_ERR_NONE
;
901 grub_ahci_readwrite_real (struct grub_ahci_device
*dev
,
902 struct grub_disk_ata_pass_through_parms
*parms
,
903 int spinup
, int reset
)
905 struct grub_pci_dma_chunk
*bufc
;
906 grub_uint64_t endtime
;
908 grub_err_t err
= GRUB_ERR_NONE
;
910 grub_dprintf ("ahci", "AHCI tfd = %x\n",
911 dev
->hba
->ports
[dev
->port
].task_file_data
);
914 grub_ahci_reset_port (dev
, 0);
916 grub_dprintf ("ahci", "AHCI tfd = %x\n",
917 dev
->hba
->ports
[dev
->port
].task_file_data
);
918 dev
->hba
->ports
[dev
->port
].task_file_data
= 0;
919 dev
->hba
->ports
[dev
->port
].command_issue
= 0;
920 grub_dprintf ("ahci", "AHCI tfd = %x\n",
921 dev
->hba
->ports
[dev
->port
].task_file_data
);
923 dev
->hba
->ports
[dev
->port
].sata_error
= dev
->hba
->ports
[dev
->port
].sata_error
;
925 grub_dprintf("ahci", "grub_ahci_read (size=%llu, cmdsize = %llu)\n",
926 (unsigned long long) parms
->size
,
927 (unsigned long long) parms
->cmdsize
);
929 if (parms
->cmdsize
!= 0 && parms
->cmdsize
!= 12 && parms
->cmdsize
!= 16)
930 return grub_error (GRUB_ERR_BUG
, "incorrect ATAPI command size");
932 if (parms
->size
> GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH
)
933 return grub_error (GRUB_ERR_BUG
, "too big data buffer");
936 bufc
= grub_memalign_dma32 (1024, parms
->size
+ (parms
->size
& 1));
938 bufc
= grub_memalign_dma32 (1024, 512);
940 grub_dprintf ("ahci", "AHCI tfd = %x, CL=%p\n",
941 dev
->hba
->ports
[dev
->port
].task_file_data
,
943 /* FIXME: support port multipliers. */
944 dev
->command_list
[0].config
945 = (5 << GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT
)
946 // | GRUB_AHCI_CONFIG_CLEAR_R_OK
947 | (0 << GRUB_AHCI_CONFIG_PMP_SHIFT
)
948 | ((parms
->size
? 1 : 0) << GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT
)
949 | (parms
->cmdsize
? GRUB_AHCI_CONFIG_ATAPI
: 0)
950 | (parms
->write
? GRUB_AHCI_CONFIG_WRITE
: GRUB_AHCI_CONFIG_READ
)
951 | (parms
->taskfile
.cmd
== 8 ? (1 << 8) : 0);
952 grub_dprintf ("ahci", "AHCI tfd = %x\n",
953 dev
->hba
->ports
[dev
->port
].task_file_data
);
955 dev
->command_list
[0].transfered
= 0;
956 dev
->command_list
[0].command_table_base
957 = grub_dma_get_phys (dev
->command_table_chunk
);
959 grub_memset ((char *) dev
->command_list
[0].unused
, 0,
960 sizeof (dev
->command_list
[0].unused
));
962 grub_memset ((char *) &dev
->command_table
[0], 0,
963 sizeof (dev
->command_table
[0]));
964 grub_dprintf ("ahci", "AHCI tfd = %x\n",
965 dev
->hba
->ports
[dev
->port
].task_file_data
);
968 grub_memcpy ((char *) dev
->command_table
[0].command
, parms
->cmd
,
971 grub_dprintf ("ahci", "AHCI tfd = %x\n",
972 dev
->hba
->ports
[dev
->port
].task_file_data
);
974 dev
->command_table
[0].cfis
[0] = GRUB_AHCI_FIS_REG_H2D
;
975 dev
->command_table
[0].cfis
[1] = 0x80;
976 for (i
= 0; i
< sizeof (parms
->taskfile
.raw
); i
++)
977 dev
->command_table
[0].cfis
[register_map
[i
]] = parms
->taskfile
.raw
[i
];
979 grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
980 dev
->command_table
[0].cfis
[0], dev
->command_table
[0].cfis
[1],
981 dev
->command_table
[0].cfis
[2], dev
->command_table
[0].cfis
[3],
982 dev
->command_table
[0].cfis
[4], dev
->command_table
[0].cfis
[5],
983 dev
->command_table
[0].cfis
[6], dev
->command_table
[0].cfis
[7]);
984 grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
985 dev
->command_table
[0].cfis
[8], dev
->command_table
[0].cfis
[9],
986 dev
->command_table
[0].cfis
[10], dev
->command_table
[0].cfis
[11],
987 dev
->command_table
[0].cfis
[12], dev
->command_table
[0].cfis
[13],
988 dev
->command_table
[0].cfis
[14], dev
->command_table
[0].cfis
[15]);
990 dev
->command_table
[0].prdt
[0].data_base
= grub_dma_get_phys (bufc
);
991 dev
->command_table
[0].prdt
[0].unused
= 0;
992 dev
->command_table
[0].prdt
[0].size
= (parms
->size
- 1);
994 grub_dprintf ("ahci", "PRDT = %" PRIxGRUB_UINT64_T
", %x, %x (%"
996 dev
->command_table
[0].prdt
[0].data_base
,
997 dev
->command_table
[0].prdt
[0].unused
,
998 dev
->command_table
[0].prdt
[0].size
,
999 (grub_size_t
) ((char *) &dev
->command_table
[0].prdt
[0]
1000 - (char *) &dev
->command_table
[0]));
1003 grub_memcpy ((char *) grub_dma_get_virt (bufc
), parms
->buffer
, parms
->size
);
1005 grub_dprintf ("ahci", "AHCI command schedulded\n");
1006 grub_dprintf ("ahci", "AHCI tfd = %x\n",
1007 dev
->hba
->ports
[dev
->port
].task_file_data
);
1008 grub_dprintf ("ahci", "AHCI inten = %x\n",
1009 dev
->hba
->ports
[dev
->port
].inten
);
1010 grub_dprintf ("ahci", "AHCI intstatus = %x\n",
1011 dev
->hba
->ports
[dev
->port
].intstatus
);
1013 dev
->hba
->ports
[dev
->port
].inten
= 0xffffffff;//(1 << 2) | (1 << 5);
1014 dev
->hba
->ports
[dev
->port
].intstatus
= 0xffffffff;//(1 << 2) | (1 << 5);
1015 grub_dprintf ("ahci", "AHCI inten = %x\n",
1016 dev
->hba
->ports
[dev
->port
].inten
);
1017 grub_dprintf ("ahci", "AHCI tfd = %x\n",
1018 dev
->hba
->ports
[dev
->port
].task_file_data
);
1019 dev
->hba
->ports
[dev
->port
].sata_active
= 1;
1020 dev
->hba
->ports
[dev
->port
].command_issue
= 1;
1021 grub_dprintf ("ahci", "AHCI sig = %x\n", dev
->hba
->ports
[dev
->port
].sig
);
1022 grub_dprintf ("ahci", "AHCI tfd = %x\n",
1023 dev
->hba
->ports
[dev
->port
].task_file_data
);
1025 endtime
= grub_get_time_ms () + (spinup
? 20000 : 20000);
1026 while ((dev
->hba
->ports
[dev
->port
].command_issue
& 1))
1027 if (grub_get_time_ms () > endtime
)
1029 grub_dprintf ("ahci", "AHCI status <%x %x %x %x>\n",
1030 dev
->hba
->ports
[dev
->port
].command_issue
,
1031 dev
->hba
->ports
[dev
->port
].sata_active
,
1032 dev
->hba
->ports
[dev
->port
].intstatus
,
1033 dev
->hba
->ports
[dev
->port
].task_file_data
);
1034 dev
->hba
->ports
[dev
->port
].command_issue
= 0;
1035 err
= grub_error (GRUB_ERR_IO
, "AHCI transfer timed out");
1037 grub_ahci_reset_port (dev
, 1);
1041 grub_dprintf ("ahci", "AHCI command completed <%x %x %x %x %x, %x %x>\n",
1042 dev
->hba
->ports
[dev
->port
].command_issue
,
1043 dev
->hba
->ports
[dev
->port
].intstatus
,
1044 dev
->hba
->ports
[dev
->port
].task_file_data
,
1045 dev
->command_list
[0].transfered
,
1046 dev
->hba
->ports
[dev
->port
].sata_error
,
1047 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x00],
1048 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x18]);
1049 grub_dprintf ("ahci",
1050 "last PIO FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
1051 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x08],
1052 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x09],
1053 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0a],
1054 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0b],
1055 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0c],
1056 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0d],
1057 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0e],
1058 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x0f]);
1059 grub_dprintf ("ahci",
1060 "last REG FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
1061 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x10],
1062 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x11],
1063 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x12],
1064 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x13],
1065 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x14],
1066 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x15],
1067 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x16],
1068 ((grub_uint32_t
*) grub_dma_get_virt (dev
->rfis
))[0x17]);
1071 grub_memcpy (parms
->buffer
, (char *) grub_dma_get_virt (bufc
), parms
->size
);
1072 grub_dma_free (bufc
);
1078 grub_ahci_readwrite (grub_ata_t disk
,
1079 struct grub_disk_ata_pass_through_parms
*parms
,
1082 return grub_ahci_readwrite_real (disk
->data
, parms
, spinup
, 0);
1086 grub_ahci_open (int id
, int devnum
, struct grub_ata
*ata
)
1088 struct grub_ahci_device
*dev
;
1090 if (id
!= GRUB_SCSI_SUBSYSTEM_AHCI
)
1091 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "not an AHCI device");
1093 FOR_LIST_ELEMENTS(dev
, grub_ahci_devices
)
1094 if (dev
->num
== devnum
)
1098 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, "no such AHCI device");
1100 grub_dprintf ("ahci", "opening AHCI dev `ahci%d'\n", dev
->num
);
1104 ata
->atapi
= dev
->atapi
;
1105 ata
->maxbuffer
= GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH
;
1106 ata
->present
= &dev
->present
;
1108 return GRUB_ERR_NONE
;
1111 static struct grub_ata_dev grub_ahci_dev
=
1113 .iterate
= grub_ahci_iterate
,
1114 .open
= grub_ahci_open
,
1115 .readwrite
= grub_ahci_readwrite
,
1120 static struct grub_preboot
*fini_hnd
;
1124 grub_stop_disk_firmware ();
1126 /* AHCI initialization. */
1127 grub_ahci_initialize ();
1129 /* AHCI devices are handled by scsi.mod. */
1130 grub_ata_dev_register (&grub_ahci_dev
);
1132 fini_hnd
= grub_loader_register_preboot_hook (grub_ahci_fini_hw
,
1133 grub_ahci_restore_hw
,
1134 GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK
);
1139 grub_ahci_fini_hw (0);
1140 grub_loader_unregister_preboot_hook (fini_hnd
);
1142 grub_ata_dev_unregister (&grub_ahci_dev
);