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