Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / ahci.c
1 // Low level AHCI disk access
2 //
3 // Copyright (C) 2010 Gerd Hoffmann <kraxel@redhat.com>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "types.h" // u8
8 #include "ioport.h" // inb
9 #include "util.h" // dprintf
10 #include "biosvar.h" // GET_EBDA
11 #include "pci.h" // foreachpci
12 #include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
13 #include "pci_regs.h" // PCI_INTERRUPT_LINE
14 #include "boot.h" // add_bcv_hd
15 #include "disk.h" // struct ata_s
16 #include "ata.h" // ATA_CB_STAT
17 #include "ahci.h" // CDB_CMD_READ_10
18 #include "blockcmd.h" // CDB_CMD_READ_10
19
20 #define AHCI_REQUEST_TIMEOUT 32000 // 32 seconds max for IDE ops
21 #define AHCI_RESET_TIMEOUT     500 // 500 miliseconds
22 #define AHCI_LINK_TIMEOUT       10 // 10 miliseconds
23
24 /****************************************************************
25  * these bits must run in both 16bit and 32bit modes
26  ****************************************************************/
27
28 // prepare sata command fis
29 static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
30 {
31     memset_fl(fis, 0, sizeof(*fis));
32     SET_FLATPTR(fis->command, command);
33 }
34
35 static void sata_prep_readwrite(struct sata_cmd_fis *fis,
36                                 struct disk_op_s *op, int iswrite)
37 {
38     u64 lba = op->lba;
39     u8 command;
40
41     memset_fl(fis, 0, sizeof(*fis));
42
43     if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
44         SET_FLATPTR(fis->sector_count2, op->count >> 8);
45         SET_FLATPTR(fis->lba_low2,      lba >> 24);
46         SET_FLATPTR(fis->lba_mid2,      lba >> 32);
47         SET_FLATPTR(fis->lba_high2,     lba >> 40);
48         lba &= 0xffffff;
49         command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
50                    : ATA_CMD_READ_DMA_EXT);
51     } else {
52         command = (iswrite ? ATA_CMD_WRITE_DMA
53                    : ATA_CMD_READ_DMA);
54     }
55     SET_FLATPTR(fis->feature,      1); /* dma */
56     SET_FLATPTR(fis->command,      command);
57     SET_FLATPTR(fis->sector_count, op->count);
58     SET_FLATPTR(fis->lba_low,      lba);
59     SET_FLATPTR(fis->lba_mid,      lba >> 8);
60     SET_FLATPTR(fis->lba_high,     lba >> 16);
61     SET_FLATPTR(fis->device,       ((lba >> 24) & 0xf) | ATA_CB_DH_LBA);
62 }
63
64 static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 blocksize)
65 {
66     memset_fl(fis, 0, sizeof(*fis));
67     SET_FLATPTR(fis->command,  ATA_CMD_PACKET);
68     SET_FLATPTR(fis->feature,  1); /* dma */
69     SET_FLATPTR(fis->lba_mid,  blocksize);
70     SET_FLATPTR(fis->lba_high, blocksize >> 8);
71 }
72
73 // ahci register access helpers
74 static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
75 {
76     u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
77     return pci_readl(addr);
78 }
79
80 static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
81 {
82     u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
83     pci_writel(addr, val);
84 }
85
86 static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg)
87 {
88     u32 ctrl_reg = 0x100;
89     ctrl_reg += pnr * 0x80;
90     ctrl_reg += port_reg;
91     return ctrl_reg;
92 }
93
94 static u32 ahci_port_readl(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg)
95 {
96     u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
97     return ahci_ctrl_readl(ctrl, ctrl_reg);
98 }
99
100 static void ahci_port_writel(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg, u32 val)
101 {
102     u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
103     ahci_ctrl_writel(ctrl, ctrl_reg, val);
104 }
105
106 // submit ahci command + wait for result
107 static int ahci_command(struct ahci_port_s *port, int iswrite, int isatapi,
108                         void *buffer, u32 bsize)
109 {
110     u32 val, status, success, flags, intbits, error;
111     struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl);
112     struct ahci_cmd_s  *cmd  = GET_GLOBAL(port->cmd);
113     struct ahci_fis_s  *fis  = GET_GLOBAL(port->fis);
114     struct ahci_list_s *list = GET_GLOBAL(port->list);
115     u32 pnr                  = GET_GLOBAL(port->pnr);
116     u64 end;
117
118     SET_FLATPTR(cmd->fis.reg,       0x27);
119     SET_FLATPTR(cmd->fis.pmp_type,  (1 << 7)); /* cmd fis */
120     SET_FLATPTR(cmd->prdt[0].base,  ((u32)buffer));
121     SET_FLATPTR(cmd->prdt[0].baseu, 0);
122     SET_FLATPTR(cmd->prdt[0].flags, bsize-1);
123
124     flags = ((1 << 16) | /* one prd entry */
125              (iswrite ? (1 << 6) : 0) |
126              (isatapi ? (1 << 5) : 0) |
127              (5 << 0)); /* fis length (dwords) */
128     SET_FLATPTR(list[0].flags,  flags);
129     SET_FLATPTR(list[0].bytes,  0);
130     SET_FLATPTR(list[0].base,   ((u32)(cmd)));
131     SET_FLATPTR(list[0].baseu,  0);
132
133     dprintf(2, "AHCI/%d: send cmd ...\n", pnr);
134     intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
135     if (intbits)
136         ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
137     ahci_port_writel(ctrl, pnr, PORT_SCR_ACT, 1);
138     ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1);
139
140     end = calc_future_tsc(AHCI_REQUEST_TIMEOUT);
141     do {
142         for (;;) {
143             intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
144             if (intbits) {
145                 ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
146                 if (intbits & 0x02) {
147                     status = GET_FLATPTR(fis->psfis[2]);
148                     error  = GET_FLATPTR(fis->psfis[3]);
149                     break;
150                 }
151                 if (intbits & 0x01) {
152                     status = GET_FLATPTR(fis->rfis[2]);
153                     error  = GET_FLATPTR(fis->rfis[3]);
154                     break;
155                 }
156             }
157             if (check_tsc(end)) {
158                 warn_timeout();
159                 return -1;
160             }
161             yield();
162         }
163         dprintf(2, "AHCI/%d: ... intbits 0x%x, status 0x%x ...\n",
164                 pnr, intbits, status);
165     } while (status & ATA_CB_STAT_BSY);
166
167     success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF |
168                                   ATA_CB_STAT_ERR)) &&
169                ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY)));
170     if (success) {
171         dprintf(2, "AHCI/%d: ... finished, status 0x%x, OK\n", pnr,
172                 status);
173     } else {
174         dprintf(2, "AHCI/%d: ... finished, status 0x%x, ERROR 0x%x\n", pnr,
175                 status, error);
176
177         // non-queued error recovery (AHCI 1.3 section 6.2.2.1)
178         // Clears PxCMD.ST to 0 to reset the PxCI register
179         val = ahci_port_readl(ctrl, pnr, PORT_CMD);
180         ahci_port_writel(ctrl, pnr, PORT_CMD, val & ~PORT_CMD_START);
181
182         // waits for PxCMD.CR to clear to 0
183         while (1) {
184             val = ahci_port_readl(ctrl, pnr, PORT_CMD);
185             if ((val & PORT_CMD_LIST_ON) == 0)
186                 break;
187             yield();
188         }
189
190         // Clears any error bits in PxSERR to enable capturing new errors
191         val = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
192         ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, val);
193
194         // Clears status bits in PxIS as appropriate
195         val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
196         ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
197
198         // If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to 1, issue
199         // a COMRESET to the device to put it in an idle state
200         val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
201         if (val & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ)) {
202             dprintf(2, "AHCI/%d: issue comreset\n", pnr);
203             val = ahci_port_readl(ctrl, pnr, PORT_SCR_CTL);
204             // set Device Detection Initialization (DET) to 1 for 1 ms for comreset
205             ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val | 1);
206             mdelay (1);
207             ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val);
208         }
209
210         // Sets PxCMD.ST to 1 to enable issuing new commands
211         val = ahci_port_readl(ctrl, pnr, PORT_CMD);
212         ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START);
213     }
214     return success ? 0 : -1;
215 }
216
217 #define CDROM_CDB_SIZE 12
218
219 int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
220 {
221     if (! CONFIG_AHCI)
222         return 0;
223
224     struct ahci_port_s *port = container_of(
225         op->drive_g, struct ahci_port_s, drive);
226     struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
227     u8 *atapi = cdbcmd;
228     int i, rc;
229
230     sata_prep_atapi(&cmd->fis, blocksize);
231     for (i = 0; i < CDROM_CDB_SIZE; i++) {
232         SET_FLATPTR(cmd->atapi[i], atapi[i]);
233     }
234     rc = ahci_command(port, 0, 1, op->buf_fl,
235                       op->count * blocksize);
236     if (rc < 0)
237         return DISK_RET_EBADTRACK;
238     return DISK_RET_SUCCESS;
239 }
240
241 // read/write count blocks from a harddrive, op->buf_fl must be word aligned
242 static int
243 ahci_disk_readwrite_aligned(struct disk_op_s *op, int iswrite)
244 {
245     struct ahci_port_s *port = container_of(
246         op->drive_g, struct ahci_port_s, drive);
247     struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
248     int rc;
249
250     sata_prep_readwrite(&cmd->fis, op, iswrite);
251     rc = ahci_command(port, iswrite, 0, op->buf_fl,
252                       op->count * DISK_SECTOR_SIZE);
253     dprintf(2, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n",
254             iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc);
255     if (rc < 0)
256         return DISK_RET_EBADTRACK;
257     return DISK_RET_SUCCESS;
258 }
259
260 // read/write count blocks from a harddrive.
261 static int
262 ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
263 {
264     // if caller's buffer is word aligned, use it directly
265     if (((u32) op->buf_fl & 1) == 0)
266         return ahci_disk_readwrite_aligned(op, iswrite);
267
268     // Use a word aligned buffer for AHCI I/O
269     int rc;
270     struct disk_op_s localop = *op;
271     u8 *alignedbuf_fl = GET_GLOBAL(bounce_buf_fl);
272     u8 *position = op->buf_fl;
273
274     localop.buf_fl = alignedbuf_fl;
275     localop.count = 1;
276
277     if (iswrite) {
278         u16 block;
279         for (block = 0; block < op->count; block++) {
280             memcpy_fl (alignedbuf_fl, position, DISK_SECTOR_SIZE);
281             rc = ahci_disk_readwrite_aligned (&localop, 1);
282             if (rc)
283                 return rc;
284             position += DISK_SECTOR_SIZE;
285             localop.lba++;
286         }
287     } else { // read
288         u16 block;
289         for (block = 0; block < op->count; block++) {
290             rc = ahci_disk_readwrite_aligned (&localop, 0);
291             if (rc)
292                 return rc;
293             memcpy_fl (position, alignedbuf_fl, DISK_SECTOR_SIZE);
294             position += DISK_SECTOR_SIZE;
295             localop.lba++;
296         }
297     }
298     return DISK_RET_SUCCESS;
299 }
300
301 // command demuxer
302 int process_ahci_op(struct disk_op_s *op)
303 {
304     struct ahci_port_s *port;
305     u32 atapi;
306
307     if (!CONFIG_AHCI)
308         return 0;
309
310     port = container_of(op->drive_g, struct ahci_port_s, drive);
311     atapi = GET_GLOBAL(port->atapi);
312
313     if (atapi) {
314         switch (op->command) {
315         case CMD_READ:
316             return cdb_read(op);
317         case CMD_WRITE:
318         case CMD_FORMAT:
319             return DISK_RET_EWRITEPROTECT;
320         case CMD_RESET:
321             /* FIXME: what should we do here? */
322         case CMD_VERIFY:
323         case CMD_SEEK:
324             return DISK_RET_SUCCESS;
325         default:
326             dprintf(1, "AHCI: unknown cdrom command %d\n", op->command);
327             op->count = 0;
328             return DISK_RET_EPARAM;
329         }
330     } else {
331         switch (op->command) {
332         case CMD_READ:
333             return ahci_disk_readwrite(op, 0);
334         case CMD_WRITE:
335             return ahci_disk_readwrite(op, 1);
336         case CMD_RESET:
337             /* FIXME: what should we do here? */
338         case CMD_FORMAT:
339         case CMD_VERIFY:
340         case CMD_SEEK:
341             return DISK_RET_SUCCESS;
342         default:
343             dprintf(1, "AHCI: unknown disk command %d\n", op->command);
344             op->count = 0;
345             return DISK_RET_EPARAM;
346         }
347     }
348 }
349
350 /****************************************************************
351  * everything below is pure 32bit code
352  ****************************************************************/
353
354 static void
355 ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr)
356 {
357     u32 val;
358     u64 end;
359
360     /* disable FIS + CMD */
361     end = calc_future_tsc(AHCI_RESET_TIMEOUT);
362     for (;;) {
363         val = ahci_port_readl(ctrl, pnr, PORT_CMD);
364         if (!(val & (PORT_CMD_FIS_RX | PORT_CMD_START |
365                      PORT_CMD_FIS_ON | PORT_CMD_LIST_ON)))
366             break;
367         val &= ~(PORT_CMD_FIS_RX | PORT_CMD_START);
368         ahci_port_writel(ctrl, pnr, PORT_CMD, val);
369         if (check_tsc(end)) {
370             warn_timeout();
371             break;
372         }
373         yield();
374     }
375
376     /* disable + clear IRQs */
377     ahci_port_writel(ctrl, pnr, PORT_IRQ_MASK, 0);
378     val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
379     if (val)
380         ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
381 }
382
383 static struct ahci_port_s*
384 ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr)
385 {
386     struct ahci_port_s *port = malloc_tmp(sizeof(*port));
387
388     if (!port) {
389         warn_noalloc();
390         return NULL;
391     }
392     port->pnr = pnr;
393     port->ctrl = ctrl;
394     port->list = memalign_tmp(1024, 1024);
395     port->fis = memalign_tmp(256, 256);
396     port->cmd = memalign_tmp(256, 256);
397     if (port->list == NULL || port->fis == NULL || port->cmd == NULL) {
398         warn_noalloc();
399         return NULL;
400     }
401     memset(port->list, 0, 1024);
402     memset(port->fis, 0, 256);
403     memset(port->cmd, 0, 256);
404
405     ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list);
406     ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis);
407     return port;
408 }
409
410 static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
411 {
412     struct ahci_port_s *tmp;
413     u32 cmd;
414
415     tmp = malloc_fseg(sizeof(*port));
416     *tmp = *port;
417     free(port);
418     port = tmp;
419
420     ahci_port_reset(port->ctrl, port->pnr);
421
422     free(port->list);
423     free(port->fis);
424     free(port->cmd);
425     port->list = memalign_low(1024, 1024);
426     port->fis = memalign_low(256, 256);
427     port->cmd = memalign_low(256, 256);
428
429     ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list);
430     ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis);
431
432     cmd = ahci_port_readl(port->ctrl, port->pnr, PORT_CMD);
433     cmd |= (PORT_CMD_FIS_RX|PORT_CMD_START);
434     ahci_port_writel(port->ctrl, port->pnr, PORT_CMD, cmd);
435
436     return port;
437 }
438
439 static void ahci_port_release(struct ahci_port_s *port)
440 {
441     ahci_port_reset(port->ctrl, port->pnr);
442     free(port->list);
443     free(port->fis);
444     free(port->cmd);
445     free(port);
446 }
447
448 #define MAXMODEL 40
449
450 /* See ahci spec chapter 10.1 "Software Initialization of HBA" */
451 static int ahci_port_init(struct ahci_port_s *port)
452 {
453     struct ahci_ctrl_s *ctrl = port->ctrl;
454     u32 pnr = port->pnr;
455     char model[MAXMODEL+1];
456     u16 buffer[256];
457     u32 cmd, stat, err, tf;
458     u64 end;
459     int rc;
460
461     /* enable FIS recv */
462     cmd = ahci_port_readl(ctrl, pnr, PORT_CMD);
463     cmd |= PORT_CMD_FIS_RX;
464     ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
465
466     /* spin up */
467     cmd |= PORT_CMD_SPIN_UP;
468     ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
469     end = calc_future_tsc(AHCI_LINK_TIMEOUT);
470     for (;;) {
471         stat = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
472         if ((stat & 0x07) == 0x03) {
473             dprintf(1, "AHCI/%d: link up\n", port->pnr);
474             break;
475         }
476         if (check_tsc(end)) {
477             dprintf(1, "AHCI/%d: link down\n", port->pnr);
478             return -1;
479         }
480         yield();
481     }
482
483     /* clear error status */
484     err = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
485     if (err)
486         ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, err);
487
488     /* wait for device becoming ready */
489     end = calc_future_tsc(AHCI_REQUEST_TIMEOUT);
490     for (;;) {
491         tf = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
492         if (!(tf & (ATA_CB_STAT_BSY |
493                     ATA_CB_STAT_DRQ)))
494             break;
495         if (check_tsc(end)) {
496             warn_timeout();
497             dprintf(1, "AHCI/%d: device not ready (tf 0x%x)\n", port->pnr, tf);
498             return -1;
499         }
500         yield();
501     }
502
503     /* start device */
504     cmd |= PORT_CMD_START;
505     ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
506
507     sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_PACKET_DEVICE);
508     rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
509     if (rc == 0) {
510         port->atapi = 1;
511     } else {
512         port->atapi = 0;
513         sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE);
514         rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
515         if (rc < 0)
516             return -1;
517     }
518
519     port->drive.type = DTYPE_AHCI;
520     port->drive.cntl_id = pnr;
521     port->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
522
523     if (!port->atapi) {
524         // found disk (ata)
525         port->drive.blksize = DISK_SECTOR_SIZE;
526         port->drive.pchs.cylinders = buffer[1];
527         port->drive.pchs.heads = buffer[3];
528         port->drive.pchs.spt = buffer[6];
529
530         u64 sectors;
531         if (buffer[83] & (1 << 10)) // word 83 - lba48 support
532             sectors = *(u64*)&buffer[100]; // word 100-103
533         else
534             sectors = *(u32*)&buffer[60]; // word 60 and word 61
535         port->drive.sectors = sectors;
536         u64 adjsize = sectors >> 11;
537         char adjprefix = 'M';
538         if (adjsize >= (1 << 16)) {
539             adjsize >>= 10;
540             adjprefix = 'G';
541         }
542         port->desc = znprintf(MAXDESCSIZE
543                               , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
544                               , port->pnr
545                               , ata_extract_model(model, MAXMODEL, buffer)
546                               , ata_extract_version(buffer)
547                               , (u32)adjsize, adjprefix);
548         port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
549     } else {
550         // found cdrom (atapi)
551         port->drive.blksize = CDROM_SECTOR_SIZE;
552         port->drive.sectors = (u64)-1;
553         u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
554         if (!iscd) {
555             dprintf(1, "AHCI/%d: atapi device is'nt a cdrom\n", port->pnr);
556             return -1;
557         }
558         port->desc = znprintf(MAXDESCSIZE
559                               , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]"
560                               , port->pnr
561                               , ata_extract_model(model, MAXMODEL, buffer)
562                               , ata_extract_version(buffer));
563         port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
564     }
565     return 0;
566 }
567
568 // Detect any drives attached to a given controller.
569 static void
570 ahci_port_detect(void *data)
571 {
572     struct ahci_port_s *port = data;
573     int rc;
574
575     dprintf(2, "AHCI/%d: probing\n", port->pnr);
576     ahci_port_reset(port->ctrl, port->pnr);
577     rc = ahci_port_init(port);
578     if (rc < 0)
579         ahci_port_release(port);
580     else {
581         port = ahci_port_realloc(port);
582         dprintf(1, "AHCI/%d: registering: \"%s\"\n", port->pnr, port->desc);
583         if (!port->atapi) {
584             // Register with bcv system.
585             boot_add_hd(&port->drive, port->desc, port->prio);
586         } else {
587             // fill cdidmap
588             boot_add_cd(&port->drive, port->desc, port->prio);
589         }
590     }
591 }
592
593 // Initialize an ata controller and detect its drives.
594 static void
595 ahci_init_controller(struct pci_device *pci)
596 {
597     struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
598     struct ahci_port_s *port;
599     u16 bdf = pci->bdf;
600     u32 val, pnr, max;
601
602     if (!ctrl) {
603         warn_noalloc();
604         return;
605     }
606
607     if (bounce_buf_init() < 0) {
608         warn_noalloc();
609         free(ctrl);
610         return;
611     }
612
613     ctrl->pci_tmp = pci;
614     ctrl->pci_bdf = bdf;
615     ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
616     ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
617     dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n",
618             bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq);
619
620     pci_config_maskw(bdf, PCI_COMMAND, 0,
621                      PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
622
623     val = ahci_ctrl_readl(ctrl, HOST_CTL);
624     ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
625
626     ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP);
627     ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL);
628     dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n",
629             ctrl->caps, ctrl->ports);
630
631     max = ctrl->caps & 0x1f;
632     for (pnr = 0; pnr <= max; pnr++) {
633         if (!(ctrl->ports & (1 << pnr)))
634             continue;
635         port = ahci_port_alloc(ctrl, pnr);
636         if (port == NULL)
637             continue;
638         run_thread(ahci_port_detect, port);
639     }
640 }
641
642 // Locate and init ahci controllers.
643 static void
644 ahci_init(void)
645 {
646     // Scan PCI bus for ATA adapters
647     struct pci_device *pci;
648     foreachpci(pci) {
649         if (pci->class != PCI_CLASS_STORAGE_SATA)
650             continue;
651         if (pci->prog_if != 1 /* AHCI rev 1 */)
652             continue;
653         ahci_init_controller(pci);
654     }
655 }
656
657 void
658 ahci_setup(void)
659 {
660     ASSERT32FLAT();
661     if (!CONFIG_AHCI)
662         return;
663
664     dprintf(3, "init ahci\n");
665     ahci_init();
666 }