source: mainline/uspace/drv/block/ahci/ahci.c@ 1db4e2ae

Last change on this file since 1db4e2ae was 60744cb, checked in by Jiri Svoboda <jiri@…>, 16 months ago

Let driver specify any argument to IRQ handler

This allows the driver to register a single handler for multiple
interrupts and still distinguish between them. It also removes
the extra step of having to get softstate from ddf_dev_t.

  • Property mode set to 100644
File size: 32.0 KB
Line 
1/*
2 * Copyright (c) 2012 Petr Jerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 * AHCI SATA driver implementation.
31 */
32
33#include <as.h>
34#include <errno.h>
35#include <stdio.h>
36#include <ddf/interrupt.h>
37#include <ddf/log.h>
38#include <device/hw_res.h>
39#include <device/hw_res_parsed.h>
40#include <pci_dev_iface.h>
41#include <ahci_iface.h>
42#include "ahci.h"
43#include "ahci_hw.h"
44#include "ahci_sata.h"
45
46#define NAME "ahci"
47
48#define LO(ptr) \
49 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) & 0xffffffff))
50
51#define HI(ptr) \
52 ((uint32_t) (((uint64_t) ((uintptr_t) (ptr))) >> 32))
53
54/** Interrupt pseudocode for a single port
55 *
56 * The interrupt handling works as follows:
57 *
58 * 1. Port interrupt status register is read
59 * (stored as arg2).
60 * 2. If port interrupt is indicated, then:
61 * 3. Port interrupt status register is cleared.
62 * 4. Global interrupt status register is read
63 * and cleared (any potential interrupts from
64 * other ports are reasserted automatically).
65 * 5. Port number is stored as arg1.
66 * 6. The interrupt is accepted.
67 *
68 */
69#define AHCI_PORT_CMDS(port) \
70 { \
71 /* Read port interrupt status register */ \
72 .cmd = CMD_PIO_READ_32, \
73 .addr = NULL, \
74 .dstarg = 2 \
75 }, \
76 { \
77 /* Check if port asserted interrupt */ \
78 .cmd = CMD_PREDICATE, \
79 .value = 5, \
80 .srcarg = 2, \
81 }, \
82 { \
83 /* Clear port interrupt status register */ \
84 .cmd = CMD_PIO_WRITE_A_32, \
85 .addr = NULL, \
86 .srcarg = 2 \
87 }, \
88 { \
89 /* Read global interrupt status register */ \
90 .cmd = CMD_PIO_READ_32, \
91 .addr = NULL, \
92 .dstarg = 0 \
93 }, \
94 { \
95 /* Clear global interrupt status register */ \
96 .cmd = CMD_PIO_WRITE_A_32, \
97 .addr = NULL, \
98 .srcarg = 0 \
99 }, \
100 { \
101 /* Indicate port interrupt assertion */ \
102 .cmd = CMD_LOAD, \
103 .value = (port), \
104 .dstarg = 1 \
105 }, \
106 { \
107 /* Accept the interrupt */ \
108 .cmd = CMD_ACCEPT \
109 }
110
111static errno_t get_sata_device_name(ddf_fun_t *, size_t, char *);
112static errno_t get_num_blocks(ddf_fun_t *, uint64_t *);
113static errno_t get_block_size(ddf_fun_t *, size_t *);
114static errno_t read_blocks(ddf_fun_t *, uint64_t, size_t, void *);
115static errno_t write_blocks(ddf_fun_t *, uint64_t, size_t, void *);
116
117static errno_t ahci_identify_device(sata_dev_t *);
118static errno_t ahci_set_highest_ultra_dma_mode(sata_dev_t *);
119static errno_t ahci_rb_fpdma(sata_dev_t *, uintptr_t, uint64_t);
120static errno_t ahci_wb_fpdma(sata_dev_t *, uintptr_t, uint64_t);
121
122static void ahci_sata_devices_create(ahci_dev_t *, ddf_dev_t *);
123static ahci_dev_t *ahci_ahci_create(ddf_dev_t *);
124static void ahci_ahci_hw_start(ahci_dev_t *);
125
126static errno_t ahci_dev_add(ddf_dev_t *);
127
128static void ahci_get_model_name(uint16_t *, char *);
129
130static fibril_mutex_t sata_devices_count_lock;
131static int sata_devices_count = 0;
132
133/*
134 * AHCI Interface
135 */
136
137static ahci_iface_t ahci_interface = {
138 .get_sata_device_name = &get_sata_device_name,
139 .get_num_blocks = &get_num_blocks,
140 .get_block_size = &get_block_size,
141 .read_blocks = &read_blocks,
142 .write_blocks = &write_blocks
143};
144
145static ddf_dev_ops_t ahci_ops = {
146 .interfaces[AHCI_DEV_IFACE] = &ahci_interface
147};
148
149static driver_ops_t driver_ops = {
150 .dev_add = &ahci_dev_add
151};
152
153static driver_t ahci_driver = {
154 .name = NAME,
155 .driver_ops = &driver_ops
156};
157
158/** Get SATA structure from DDF function. */
159static sata_dev_t *fun_sata_dev(ddf_fun_t *fun)
160{
161 return ddf_fun_data_get(fun);
162}
163
164/** Get SATA device name.
165 *
166 * @param fun Device function handling the call.
167 * @param sata_dev_name_length Length of the sata_dev_name buffer.
168 * @param sata_dev_name Buffer for SATA device name.
169 *
170 * @return EOK.
171 *
172 */
173static errno_t get_sata_device_name(ddf_fun_t *fun,
174 size_t sata_dev_name_length, char *sata_dev_name)
175{
176 sata_dev_t *sata = fun_sata_dev(fun);
177 str_cpy(sata_dev_name, sata_dev_name_length, sata->model);
178 return EOK;
179}
180
181/** Get Number of blocks in SATA device.
182 *
183 * @param fun Device function handling the call.
184 * @param blocks Return number of blocks in SATA device.
185 *
186 * @return EOK.
187 *
188 */
189static errno_t get_num_blocks(ddf_fun_t *fun, uint64_t *num_blocks)
190{
191 sata_dev_t *sata = fun_sata_dev(fun);
192 *num_blocks = sata->blocks;
193 return EOK;
194}
195
196/** Get SATA device block size.
197 *
198 * @param fun Device function handling the call.
199 * @param block_size Return block size.
200 *
201 * @return EOK.
202 *
203 */
204static errno_t get_block_size(ddf_fun_t *fun, size_t *block_size)
205{
206 sata_dev_t *sata = fun_sata_dev(fun);
207 *block_size = sata->block_size;
208 return EOK;
209}
210
211/** Read data blocks into SATA device.
212 *
213 * @param fun Device function handling the call.
214 * @param blocknum Number of first block.
215 * @param count Number of blocks to read.
216 * @param buf Buffer for data.
217 *
218 * @return EOK if succeed, error code otherwise
219 *
220 */
221static errno_t read_blocks(ddf_fun_t *fun, uint64_t blocknum,
222 size_t count, void *buf)
223{
224 sata_dev_t *sata = fun_sata_dev(fun);
225
226 uintptr_t phys;
227 void *ibuf = AS_AREA_ANY;
228 errno_t rc = dmamem_map_anonymous(sata->block_size, DMAMEM_4GiB,
229 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, &ibuf);
230 if (rc != EOK) {
231 ddf_msg(LVL_ERROR, "Cannot allocate read buffer.");
232 return rc;
233 }
234
235 memset(buf, 0, sata->block_size);
236
237 fibril_mutex_lock(&sata->lock);
238
239 for (size_t cur = 0; cur < count; cur++) {
240 rc = ahci_rb_fpdma(sata, phys, blocknum + cur);
241 if (rc != EOK)
242 break;
243
244 memcpy((void *) (((uint8_t *) buf) + (sata->block_size * cur)),
245 ibuf, sata->block_size);
246 }
247
248 fibril_mutex_unlock(&sata->lock);
249 dmamem_unmap_anonymous(ibuf);
250
251 return rc;
252}
253
254/** Write data blocks into SATA device.
255 *
256 * @param fun Device function handling the call.
257 * @param blocknum Number of first block.
258 * @param count Number of blocks to write.
259 * @param buf Buffer with data.
260 *
261 * @return EOK if succeed, error code otherwise
262 *
263 */
264static errno_t write_blocks(ddf_fun_t *fun, uint64_t blocknum,
265 size_t count, void *buf)
266{
267 sata_dev_t *sata = fun_sata_dev(fun);
268
269 uintptr_t phys;
270 void *ibuf = AS_AREA_ANY;
271 errno_t rc = dmamem_map_anonymous(sata->block_size, DMAMEM_4GiB,
272 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, &ibuf);
273 if (rc != EOK) {
274 ddf_msg(LVL_ERROR, "Cannot allocate write buffer.");
275 return rc;
276 }
277
278 fibril_mutex_lock(&sata->lock);
279
280 for (size_t cur = 0; cur < count; cur++) {
281 memcpy(ibuf, (void *) (((uint8_t *) buf) + (sata->block_size * cur)),
282 sata->block_size);
283 rc = ahci_wb_fpdma(sata, phys, blocknum + cur);
284 if (rc != EOK)
285 break;
286 }
287
288 fibril_mutex_unlock(&sata->lock);
289 dmamem_unmap_anonymous(ibuf);
290
291 return rc;
292}
293
294/*
295 * AHCI Commands
296 */
297
298/** Wait for interrupt event.
299 *
300 * @param sata SATA device structure.
301 *
302 * @return Value of interrupt state register.
303 *
304 */
305static ahci_port_is_t ahci_wait_event(sata_dev_t *sata)
306{
307 fibril_mutex_lock(&sata->event_lock);
308
309 sata->event_pxis = 0;
310 while (sata->event_pxis == 0)
311 fibril_condvar_wait(&sata->event_condvar, &sata->event_lock);
312
313 ahci_port_is_t pxis = sata->event_pxis;
314
315 if (ahci_port_is_permanent_error(pxis))
316 sata->is_invalid_device = true;
317
318 fibril_mutex_unlock(&sata->event_lock);
319
320 return pxis;
321}
322
323/** Set AHCI registers for identifying SATA device.
324 *
325 * @param sata SATA device structure.
326 * @param phys Physical address of working buffer.
327 *
328 */
329static void ahci_identify_device_cmd(sata_dev_t *sata, uintptr_t phys)
330{
331 volatile sata_std_command_frame_t *cmd =
332 (sata_std_command_frame_t *) sata->cmd_table;
333
334 cmd->fis_type = SATA_CMD_FIS_TYPE;
335 cmd->c = SATA_CMD_FIS_COMMAND_INDICATOR;
336 cmd->command = 0xec;
337 cmd->features = 0;
338 cmd->lba_lower = 0;
339 cmd->device = 0;
340 cmd->lba_upper = 0;
341 cmd->features_upper = 0;
342 cmd->count = 0;
343 cmd->reserved1 = 0;
344 cmd->control = 0;
345 cmd->reserved2 = 0;
346
347 volatile ahci_cmd_prdt_t *prdt =
348 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
349
350 prdt->data_address_low = LO(phys);
351 prdt->data_address_upper = HI(phys);
352 prdt->reserved1 = 0;
353 prdt->dbc = SATA_IDENTIFY_DEVICE_BUFFER_LENGTH - 1;
354 prdt->reserved2 = 0;
355 prdt->ioc = 0;
356
357 sata->cmd_header->prdtl = 1;
358 sata->cmd_header->flags =
359 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
360 AHCI_CMDHDR_FLAGS_2DWCMD;
361 sata->cmd_header->bytesprocessed = 0;
362
363 /* Run command. */
364 sata->port->pxsact |= 1;
365 sata->port->pxci |= 1;
366}
367
368/** Set AHCI registers for identifying packet SATA device.
369 *
370 * @param sata SATA device structure.
371 * @param phys Physical address of working buffer.
372 *
373 */
374static void ahci_identify_packet_device_cmd(sata_dev_t *sata, uintptr_t phys)
375{
376 volatile sata_std_command_frame_t *cmd =
377 (sata_std_command_frame_t *) sata->cmd_table;
378
379 cmd->fis_type = SATA_CMD_FIS_TYPE;
380 cmd->c = SATA_CMD_FIS_COMMAND_INDICATOR;
381 cmd->command = 0xa1;
382 cmd->features = 0;
383 cmd->lba_lower = 0;
384 cmd->device = 0;
385 cmd->lba_upper = 0;
386 cmd->features_upper = 0;
387 cmd->count = 0;
388 cmd->reserved1 = 0;
389 cmd->control = 0;
390 cmd->reserved2 = 0;
391
392 volatile ahci_cmd_prdt_t *prdt =
393 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
394
395 prdt->data_address_low = LO(phys);
396 prdt->data_address_upper = HI(phys);
397 prdt->reserved1 = 0;
398 prdt->dbc = SATA_IDENTIFY_DEVICE_BUFFER_LENGTH - 1;
399 prdt->reserved2 = 0;
400 prdt->ioc = 0;
401
402 sata->cmd_header->prdtl = 1;
403 sata->cmd_header->flags =
404 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
405 AHCI_CMDHDR_FLAGS_2DWCMD;
406 sata->cmd_header->bytesprocessed = 0;
407
408 /* Run command. */
409 sata->port->pxsact |= 1;
410 sata->port->pxci |= 1;
411}
412
413/** Fill device identification in SATA device structure.
414 *
415 * @param sata SATA device structure.
416 *
417 * @return EOK if succeed, error code otherwise.
418 *
419 */
420static errno_t ahci_identify_device(sata_dev_t *sata)
421{
422 if (sata->is_invalid_device) {
423 ddf_msg(LVL_ERROR,
424 "Identify command device on invalid device");
425 return EINTR;
426 }
427
428 uintptr_t phys;
429 sata_identify_data_t *idata = AS_AREA_ANY;
430 errno_t rc = dmamem_map_anonymous(SATA_IDENTIFY_DEVICE_BUFFER_LENGTH,
431 DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0, &phys,
432 (void *) &idata);
433 if (rc != EOK) {
434 ddf_msg(LVL_ERROR, "Cannot allocate buffer to identify device.");
435 return rc;
436 }
437
438 memset(idata, 0, SATA_IDENTIFY_DEVICE_BUFFER_LENGTH);
439
440 fibril_mutex_lock(&sata->lock);
441
442 ahci_identify_device_cmd(sata, phys);
443 ahci_port_is_t pxis = ahci_wait_event(sata);
444
445 if (sata->is_invalid_device) {
446 ddf_msg(LVL_ERROR,
447 "Unrecoverable error during ata identify device");
448 goto error;
449 }
450
451 if (ahci_port_is_tfes(pxis)) {
452 ahci_identify_packet_device_cmd(sata, phys);
453 pxis = ahci_wait_event(sata);
454
455 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
456 ddf_msg(LVL_ERROR,
457 "Unrecoverable error during ata identify packet device");
458 goto error;
459 }
460
461 sata->is_packet_device = true;
462 }
463
464 ahci_get_model_name(idata->model_name, sata->model);
465
466 /*
467 * Due to QEMU limitation (as of 2012-06-22),
468 * only NCQ FPDMA mode is supported.
469 */
470 if ((idata->sata_cap & sata_np_cap_ncq) == 0) {
471 ddf_msg(LVL_ERROR, "%s: NCQ must be supported", sata->model);
472 goto error;
473 }
474
475 uint16_t logsec = idata->physical_logic_sector_size;
476 if ((logsec & 0xc000) == 0x4000) {
477 /* Length of sector may be larger than 512 B */
478 if (logsec & 0x0100) {
479 /* Size of sector is larger than 512 B */
480 ddf_msg(LVL_ERROR,
481 "%s: Sector length other than 512 B not supported",
482 sata->model);
483 goto error;
484 }
485
486 if ((logsec & 0x0200) && ((logsec & 0x000f) != 0)) {
487 /* Physical sectors per logical sector is greather than 1 */
488 ddf_msg(LVL_ERROR,
489 "%s: Sector length other than 512 B not supported",
490 sata->model);
491 goto error;
492 }
493 }
494
495 if (sata->is_packet_device) {
496 /*
497 * Due to QEMU limitation (as of 2012-06-22),
498 * only NCQ FPDMA mode supported - block size is
499 * 512 B, not 2048 B!
500 */
501 sata->block_size = SATA_DEFAULT_SECTOR_SIZE;
502 sata->blocks = 0;
503 } else {
504 sata->block_size = SATA_DEFAULT_SECTOR_SIZE;
505
506 if ((idata->caps & sata_rd_cap_lba) == 0) {
507 ddf_msg(LVL_ERROR, "%s: LBA for NCQ must be supported",
508 sata->model);
509 goto error;
510 } else if ((idata->cmd_set1 & sata_cs1_addr48) == 0) {
511 sata->blocks = (uint32_t) idata->total_lba28_0 |
512 ((uint32_t) idata->total_lba28_1 << 16);
513 } else {
514 /* Device supports LBA-48 addressing. */
515 sata->blocks = (uint64_t) idata->total_lba48_0 |
516 ((uint64_t) idata->total_lba48_1 << 16) |
517 ((uint64_t) idata->total_lba48_2 << 32) |
518 ((uint64_t) idata->total_lba48_3 << 48);
519 }
520 }
521
522 uint8_t udma_mask = idata->udma & 0x007f;
523 sata->highest_udma_mode = (uint8_t) -1;
524 if (udma_mask == 0) {
525 ddf_msg(LVL_ERROR,
526 "%s: UDMA mode for NCQ FPDMA mode must be supported",
527 sata->model);
528 goto error;
529 } else {
530 for (uint8_t i = 0; i < 7; i++) {
531 if (udma_mask & (1 << i))
532 sata->highest_udma_mode = i;
533 }
534 }
535
536 fibril_mutex_unlock(&sata->lock);
537 dmamem_unmap_anonymous(idata);
538
539 return EOK;
540
541error:
542 fibril_mutex_unlock(&sata->lock);
543 dmamem_unmap_anonymous(idata);
544
545 return EINTR;
546}
547
548/** Set AHCI registers for setting SATA device transfer mode.
549 *
550 * @param sata SATA device structure.
551 * @param phys Physical address of working buffer.
552 * @param mode Required mode.
553 *
554 */
555static void ahci_set_mode_cmd(sata_dev_t *sata, uintptr_t phys, uint8_t mode)
556{
557 volatile sata_std_command_frame_t *cmd =
558 (sata_std_command_frame_t *) sata->cmd_table;
559
560 cmd->fis_type = SATA_CMD_FIS_TYPE;
561 cmd->c = SATA_CMD_FIS_COMMAND_INDICATOR;
562 cmd->command = 0xef;
563 cmd->features = 0x03;
564 cmd->lba_lower = 0;
565 cmd->device = 0;
566 cmd->lba_upper = 0;
567 cmd->features_upper = 0;
568 cmd->count = mode;
569 cmd->reserved1 = 0;
570 cmd->control = 0;
571 cmd->reserved2 = 0;
572
573 volatile ahci_cmd_prdt_t *prdt =
574 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
575
576 prdt->data_address_low = LO(phys);
577 prdt->data_address_upper = HI(phys);
578 prdt->reserved1 = 0;
579 prdt->dbc = SATA_SET_FEATURE_BUFFER_LENGTH - 1;
580 prdt->reserved2 = 0;
581 prdt->ioc = 0;
582
583 sata->cmd_header->prdtl = 1;
584 sata->cmd_header->flags =
585 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
586 AHCI_CMDHDR_FLAGS_2DWCMD;
587 sata->cmd_header->bytesprocessed = 0;
588
589 /* Run command. */
590 sata->port->pxsact |= 1;
591 sata->port->pxci |= 1;
592}
593
594/** Set highest ultra DMA mode supported by SATA device.
595 *
596 * @param sata SATA device structure.
597 *
598 * @return EOK if succeed, error code otherwise
599 *
600 */
601static errno_t ahci_set_highest_ultra_dma_mode(sata_dev_t *sata)
602{
603 if (sata->is_invalid_device) {
604 ddf_msg(LVL_ERROR,
605 "%s: Setting highest UDMA mode on invalid device",
606 sata->model);
607 return EINTR;
608 }
609
610 if (sata->highest_udma_mode == (uint8_t) -1) {
611 ddf_msg(LVL_ERROR,
612 "%s: No AHCI UDMA support.", sata->model);
613 return EINTR;
614 }
615
616 if (sata->highest_udma_mode > 6) {
617 ddf_msg(LVL_ERROR,
618 "%s: Unknown AHCI UDMA mode.", sata->model);
619 return EINTR;
620 }
621
622 uintptr_t phys;
623 sata_identify_data_t *idata = AS_AREA_ANY;
624 errno_t rc = dmamem_map_anonymous(SATA_SET_FEATURE_BUFFER_LENGTH,
625 DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0, &phys,
626 (void *) &idata);
627 if (rc != EOK) {
628 ddf_msg(LVL_ERROR, "Cannot allocate buffer for device set mode.");
629 return rc;
630 }
631
632 memset(idata, 0, SATA_SET_FEATURE_BUFFER_LENGTH);
633
634 fibril_mutex_lock(&sata->lock);
635
636 uint8_t mode = 0x40 | (sata->highest_udma_mode & 0x07);
637 ahci_set_mode_cmd(sata, phys, mode);
638 ahci_port_is_t pxis = ahci_wait_event(sata);
639
640 if (sata->is_invalid_device) {
641 ddf_msg(LVL_ERROR,
642 "%s: Unrecoverable error during set highest UDMA mode",
643 sata->model);
644 goto error;
645 }
646
647 if (ahci_port_is_error(pxis)) {
648 ddf_msg(LVL_ERROR,
649 "%s: Error during set highest UDMA mode", sata->model);
650 goto error;
651 }
652
653 fibril_mutex_unlock(&sata->lock);
654 dmamem_unmap_anonymous(idata);
655
656 return EOK;
657
658error:
659 fibril_mutex_unlock(&sata->lock);
660 dmamem_unmap_anonymous(idata);
661
662 return EINTR;
663}
664
665/** Set AHCI registers for reading one sector from the SATA device using FPDMA.
666 *
667 * @param sata SATA device structure.
668 * @param phys Physical address of buffer for sector data.
669 * @param blocknum Block number to read.
670 *
671 */
672static void ahci_rb_fpdma_cmd(sata_dev_t *sata, uintptr_t phys,
673 uint64_t blocknum)
674{
675 volatile sata_ncq_command_frame_t *cmd =
676 (sata_ncq_command_frame_t *) sata->cmd_table;
677
678 cmd->fis_type = SATA_CMD_FIS_TYPE;
679 cmd->c = SATA_CMD_FIS_COMMAND_INDICATOR;
680 cmd->command = 0x60;
681 cmd->tag = 0;
682 cmd->control = 0;
683
684 cmd->reserved1 = 0;
685 cmd->reserved2 = 0;
686 cmd->reserved3 = 0;
687 cmd->reserved4 = 0;
688 cmd->reserved5 = 0;
689 cmd->reserved6 = 0;
690
691 cmd->sector_count_low = 1;
692 cmd->sector_count_high = 0;
693
694 cmd->lba0 = blocknum & 0xff;
695 cmd->lba1 = (blocknum >> 8) & 0xff;
696 cmd->lba2 = (blocknum >> 16) & 0xff;
697 cmd->lba3 = (blocknum >> 24) & 0xff;
698 cmd->lba4 = (blocknum >> 32) & 0xff;
699 cmd->lba5 = (blocknum >> 40) & 0xff;
700
701 volatile ahci_cmd_prdt_t *prdt =
702 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
703
704 prdt->data_address_low = LO(phys);
705 prdt->data_address_upper = HI(phys);
706 prdt->reserved1 = 0;
707 prdt->dbc = sata->block_size - 1;
708 prdt->reserved2 = 0;
709 prdt->ioc = 0;
710
711 sata->cmd_header->prdtl = 1;
712 sata->cmd_header->flags =
713 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
714 AHCI_CMDHDR_FLAGS_5DWCMD;
715 sata->cmd_header->bytesprocessed = 0;
716
717 sata->port->pxsact |= 1;
718 sata->port->pxci |= 1;
719}
720
721/** Read one sector from the SATA device using FPDMA.
722 *
723 * @param sata SATA device structure.
724 * @param phys Physical address of buffer for sector data.
725 * @param blocknum Block number to read.
726 *
727 * @return EOK if succeed, error code otherwise
728 *
729 */
730static errno_t ahci_rb_fpdma(sata_dev_t *sata, uintptr_t phys, uint64_t blocknum)
731{
732 if (sata->is_invalid_device) {
733 ddf_msg(LVL_ERROR,
734 "%s: FPDMA read from invalid device", sata->model);
735 return EINTR;
736 }
737
738 ahci_rb_fpdma_cmd(sata, phys, blocknum);
739 ahci_port_is_t pxis = ahci_wait_event(sata);
740
741 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
742 ddf_msg(LVL_ERROR,
743 "%s: Unrecoverable error during FPDMA read", sata->model);
744 return EINTR;
745 }
746
747 return EOK;
748}
749
750/** Set AHCI registers for writing one sector to the SATA device, use FPDMA.
751 *
752 * @param sata SATA device structure.
753 * @param phys Physical address of buffer with sector data.
754 * @param blocknum Block number to write.
755 *
756 * @return EOK if succeed, error code otherwise
757 *
758 */
759static void ahci_wb_fpdma_cmd(sata_dev_t *sata, uintptr_t phys,
760 uint64_t blocknum)
761{
762 volatile sata_ncq_command_frame_t *cmd =
763 (sata_ncq_command_frame_t *) sata->cmd_table;
764
765 cmd->fis_type = SATA_CMD_FIS_TYPE;
766 cmd->c = SATA_CMD_FIS_COMMAND_INDICATOR;
767 cmd->command = 0x61;
768 cmd->tag = 0;
769 cmd->control = 0;
770
771 cmd->reserved1 = 0;
772 cmd->reserved2 = 0;
773 cmd->reserved3 = 0;
774 cmd->reserved4 = 0;
775 cmd->reserved5 = 0;
776 cmd->reserved6 = 0;
777
778 cmd->sector_count_low = 1;
779 cmd->sector_count_high = 0;
780
781 cmd->lba0 = blocknum & 0xff;
782 cmd->lba1 = (blocknum >> 8) & 0xff;
783 cmd->lba2 = (blocknum >> 16) & 0xff;
784 cmd->lba3 = (blocknum >> 24) & 0xff;
785 cmd->lba4 = (blocknum >> 32) & 0xff;
786 cmd->lba5 = (blocknum >> 40) & 0xff;
787
788 volatile ahci_cmd_prdt_t *prdt =
789 (ahci_cmd_prdt_t *) (&sata->cmd_table[0x20]);
790
791 prdt->data_address_low = LO(phys);
792 prdt->data_address_upper = HI(phys);
793 prdt->reserved1 = 0;
794 prdt->dbc = sata->block_size - 1;
795 prdt->reserved2 = 0;
796 prdt->ioc = 0;
797
798 sata->cmd_header->prdtl = 1;
799 sata->cmd_header->flags =
800 AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK |
801 AHCI_CMDHDR_FLAGS_WRITE |
802 AHCI_CMDHDR_FLAGS_5DWCMD;
803 sata->cmd_header->bytesprocessed = 0;
804
805 sata->port->pxsact |= 1;
806 sata->port->pxci |= 1;
807}
808
809/** Write one sector into the SATA device, use FPDMA.
810 *
811 * @param sata SATA device structure.
812 * @param phys Physical address of buffer with sector data.
813 * @param blocknum Block number to write.
814 *
815 * @return EOK if succeed, error code otherwise
816 *
817 */
818static errno_t ahci_wb_fpdma(sata_dev_t *sata, uintptr_t phys, uint64_t blocknum)
819{
820 if (sata->is_invalid_device) {
821 ddf_msg(LVL_ERROR,
822 "%s: FPDMA write to invalid device", sata->model);
823 return EINTR;
824 }
825
826 ahci_wb_fpdma_cmd(sata, phys, blocknum);
827 ahci_port_is_t pxis = ahci_wait_event(sata);
828
829 if ((sata->is_invalid_device) || (ahci_port_is_error(pxis))) {
830 ddf_msg(LVL_ERROR,
831 "%s: Unrecoverable error during FPDMA write", sata->model);
832 return EINTR;
833 }
834
835 return EOK;
836}
837
838/*
839 * Interrupts handling
840 */
841
842static irq_pio_range_t ahci_ranges[] = {
843 {
844 .base = 0,
845 .size = 0,
846 }
847};
848
849static irq_cmd_t ahci_cmds[] = {
850 AHCI_PORT_CMDS(0),
851 AHCI_PORT_CMDS(1),
852 AHCI_PORT_CMDS(2),
853 AHCI_PORT_CMDS(3),
854 AHCI_PORT_CMDS(4),
855 AHCI_PORT_CMDS(5),
856 AHCI_PORT_CMDS(6),
857 AHCI_PORT_CMDS(7),
858 AHCI_PORT_CMDS(8),
859 AHCI_PORT_CMDS(9),
860 AHCI_PORT_CMDS(10),
861 AHCI_PORT_CMDS(11),
862 AHCI_PORT_CMDS(12),
863 AHCI_PORT_CMDS(13),
864 AHCI_PORT_CMDS(14),
865 AHCI_PORT_CMDS(15),
866 AHCI_PORT_CMDS(16),
867 AHCI_PORT_CMDS(17),
868 AHCI_PORT_CMDS(18),
869 AHCI_PORT_CMDS(19),
870 AHCI_PORT_CMDS(20),
871 AHCI_PORT_CMDS(21),
872 AHCI_PORT_CMDS(22),
873 AHCI_PORT_CMDS(23),
874 AHCI_PORT_CMDS(24),
875 AHCI_PORT_CMDS(25),
876 AHCI_PORT_CMDS(26),
877 AHCI_PORT_CMDS(27),
878 AHCI_PORT_CMDS(28),
879 AHCI_PORT_CMDS(29),
880 AHCI_PORT_CMDS(30),
881 AHCI_PORT_CMDS(31)
882};
883
884/** AHCI interrupt handler.
885 *
886 * @param icall The IPC call structure.
887 * @param arg Argument (ahci_dev_t *)
888 */
889static void ahci_interrupt(ipc_call_t *icall, void *arg)
890{
891 ahci_dev_t *ahci = (ahci_dev_t *)arg;
892 unsigned int port = ipc_get_arg1(icall);
893 ahci_port_is_t pxis = ipc_get_arg2(icall);
894
895 if (port >= AHCI_MAX_PORTS)
896 return;
897
898 sata_dev_t *sata = (sata_dev_t *) ahci->sata_devs[port];
899 if (sata == NULL)
900 return;
901
902 /* Evaluate port event */
903 if ((ahci_port_is_end_of_operation(pxis)) ||
904 (ahci_port_is_error(pxis))) {
905 fibril_mutex_lock(&sata->event_lock);
906
907 sata->event_pxis = pxis;
908 fibril_condvar_signal(&sata->event_condvar);
909
910 fibril_mutex_unlock(&sata->event_lock);
911 }
912}
913
914/*
915 * AHCI and SATA device creating and initializing routines
916 */
917
918/** Allocate SATA device structure with buffers for hardware.
919 *
920 * @param port AHCI port structure
921 *
922 * @return SATA device structure if succeed, NULL otherwise.
923 *
924 */
925static sata_dev_t *ahci_sata_allocate(ahci_dev_t *ahci, volatile ahci_port_t *port)
926{
927 size_t size = 4096;
928 uintptr_t phys = 0;
929 void *virt_fb = AS_AREA_ANY;
930 void *virt_cmd = AS_AREA_ANY;
931 void *virt_table = AS_AREA_ANY;
932 ddf_fun_t *fun;
933
934 fun = ddf_fun_create(ahci->dev, fun_exposed, NULL);
935
936 sata_dev_t *sata = ddf_fun_data_alloc(fun, sizeof(sata_dev_t));
937 if (sata == NULL)
938 return NULL;
939
940 sata->fun = fun;
941 sata->port = port;
942
943 /* Allocate and init retfis structure. */
944 errno_t rc = dmamem_map_anonymous(size, DMAMEM_4GiB,
945 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, &virt_fb);
946 if (rc != EOK)
947 goto error_retfis;
948
949 memset(virt_fb, 0, size);
950 sata->port->pxfbu = HI(phys);
951 sata->port->pxfb = LO(phys);
952
953 /* Allocate and init command header structure. */
954 rc = dmamem_map_anonymous(size, DMAMEM_4GiB,
955 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, &virt_cmd);
956 if (rc != EOK)
957 goto error_cmd;
958
959 memset(virt_cmd, 0, size);
960 sata->port->pxclbu = HI(phys);
961 sata->port->pxclb = LO(phys);
962 sata->cmd_header = (ahci_cmdhdr_t *) virt_cmd;
963
964 /* Allocate and init command table structure. */
965 rc = dmamem_map_anonymous(size, DMAMEM_4GiB,
966 AS_AREA_READ | AS_AREA_WRITE, 0, &phys, &virt_table);
967 if (rc != EOK)
968 goto error_table;
969
970 memset(virt_table, 0, size);
971 sata->cmd_header->cmdtableu = HI(phys);
972 sata->cmd_header->cmdtable = LO(phys);
973 sata->cmd_table = (uint32_t *) virt_table;
974
975 return sata;
976
977error_table:
978 dmamem_unmap(virt_cmd, size);
979error_cmd:
980 dmamem_unmap(virt_fb, size);
981error_retfis:
982 free(sata);
983 return NULL;
984}
985
986/** Initialize and start SATA hardware device.
987 *
988 * @param sata SATA device structure.
989 *
990 */
991static void ahci_sata_hw_start(sata_dev_t *sata)
992{
993 ahci_port_cmd_t pxcmd;
994
995 pxcmd.u32 = sata->port->pxcmd;
996
997 /* Frame receiver disabled. */
998 pxcmd.fre = 0;
999
1000 /* Disable process the command list. */
1001 pxcmd.st = 0;
1002
1003 sata->port->pxcmd = pxcmd.u32;
1004
1005 /* Clear interrupt status. */
1006 sata->port->pxis = 0xffffffff;
1007
1008 /* Clear error status. */
1009 sata->port->pxserr = 0xffffffff;
1010
1011 /* Enable all interrupts. */
1012 sata->port->pxie = 0xffffffff;
1013
1014 /* Frame receiver enabled. */
1015 pxcmd.fre = 1;
1016
1017 /* Enable process the command list. */
1018 pxcmd.st = 1;
1019
1020 sata->port->pxcmd = pxcmd.u32;
1021}
1022
1023/** Create and initialize connected SATA structure device
1024 *
1025 * @param ahci AHCI device structure.
1026 * @param dev DDF device structure.
1027 * @param port AHCI port structure.
1028 * @param port_num Number of AHCI port with existing SATA device.
1029 *
1030 * @return EOK if succeed, error code otherwise.
1031 *
1032 */
1033static errno_t ahci_sata_create(ahci_dev_t *ahci, ddf_dev_t *dev,
1034 volatile ahci_port_t *port, unsigned int port_num)
1035{
1036 ddf_fun_t *fun = NULL;
1037 errno_t rc;
1038
1039 sata_dev_t *sata = ahci_sata_allocate(ahci, port);
1040 if (sata == NULL)
1041 return EINTR;
1042
1043 /* Set pointers between SATA and AHCI structures. */
1044 sata->ahci = ahci;
1045 sata->port_num = port_num;
1046 ahci->sata_devs[port_num] = sata;
1047
1048 /* Initialize synchronization structures */
1049 fibril_mutex_initialize(&sata->lock);
1050 fibril_mutex_initialize(&sata->event_lock);
1051 fibril_condvar_initialize(&sata->event_condvar);
1052
1053 ahci_sata_hw_start(sata);
1054
1055 /* Identify device. */
1056 if (ahci_identify_device(sata) != EOK)
1057 goto error;
1058
1059 /* Set required UDMA mode */
1060 if (ahci_set_highest_ultra_dma_mode(sata) != EOK)
1061 goto error;
1062
1063 /* Add device to the system */
1064 char sata_dev_name[16];
1065 snprintf(sata_dev_name, 16, "ahci_%u", sata_devices_count);
1066
1067 fibril_mutex_lock(&sata_devices_count_lock);
1068 sata_devices_count++;
1069 fibril_mutex_unlock(&sata_devices_count_lock);
1070
1071 rc = ddf_fun_set_name(sata->fun, sata_dev_name);
1072 if (rc != EOK) {
1073 ddf_msg(LVL_ERROR, "Failed setting function name.");
1074 goto error;
1075 }
1076
1077 ddf_fun_set_ops(fun, &ahci_ops);
1078
1079 rc = ddf_fun_bind(fun);
1080 if (rc != EOK) {
1081 ddf_msg(LVL_ERROR, "Failed binding function.");
1082 goto error;
1083 }
1084
1085 return EOK;
1086
1087error:
1088 sata->is_invalid_device = true;
1089 if (fun != NULL)
1090 ddf_fun_destroy(fun);
1091
1092 return EINTR;
1093}
1094
1095/** Create and initialize all SATA structure devices for connected SATA drives.
1096 *
1097 * @param ahci AHCI device structure.
1098 * @param dev DDF device structure.
1099 *
1100 */
1101static void ahci_sata_devices_create(ahci_dev_t *ahci, ddf_dev_t *dev)
1102{
1103 for (unsigned int port_num = 0; port_num < AHCI_MAX_PORTS; port_num++) {
1104 /* Active ports only */
1105 if (!(ahci->memregs->ghc.pi & (1 << port_num)))
1106 continue;
1107
1108 volatile ahci_port_t *port = ahci->memregs->ports + port_num;
1109
1110 /* Active devices only */
1111 ahci_port_ssts_t pxssts;
1112 pxssts.u32 = port->pxssts;
1113 if (pxssts.det != AHCI_PORT_SSTS_DET_ACTIVE)
1114 continue;
1115
1116 ahci_sata_create(ahci, dev, port, port_num);
1117 }
1118}
1119
1120/** Create AHCI device structure, intialize it and register interrupt routine.
1121 *
1122 * @param dev DDF device structure.
1123 *
1124 * @return AHCI device structure if succeed, NULL otherwise.
1125 *
1126 */
1127static ahci_dev_t *ahci_ahci_create(ddf_dev_t *dev)
1128{
1129 ahci_dev_t *ahci = ddf_dev_data_alloc(dev, sizeof(ahci_dev_t));
1130 if (!ahci)
1131 return NULL;
1132
1133 /* Connect to parent device */
1134 ahci->parent_sess = ddf_dev_parent_sess_get(dev);
1135 if (ahci->parent_sess == NULL)
1136 return NULL;
1137
1138 ahci->dev = dev;
1139
1140 hw_res_list_parsed_t hw_res_parsed;
1141 hw_res_list_parsed_init(&hw_res_parsed);
1142 if (hw_res_get_list_parsed(ahci->parent_sess, &hw_res_parsed, 0) != EOK)
1143 goto error_get_res_parsed;
1144
1145 /* Map AHCI registers. */
1146 ahci->memregs = AS_AREA_ANY;
1147
1148 physmem_map(RNGABS(hw_res_parsed.mem_ranges.ranges[0]),
1149 AHCI_MEMREGS_PAGES_COUNT, AS_AREA_READ | AS_AREA_WRITE,
1150 (void *) &ahci->memregs);
1151 if (ahci->memregs == NULL)
1152 goto error_map_registers;
1153
1154 /* Register interrupt handler */
1155 ahci_ranges[0].base = RNGABS(hw_res_parsed.mem_ranges.ranges[0]);
1156 ahci_ranges[0].size = sizeof(ahci_memregs_t);
1157
1158 for (unsigned int port = 0; port < AHCI_MAX_PORTS; port++) {
1159 size_t base = port * 7;
1160
1161 ahci_cmds[base].addr =
1162 ((uint32_t *) RNGABSPTR(hw_res_parsed.mem_ranges.ranges[0])) +
1163 AHCI_PORTS_REGISTERS_OFFSET + port * AHCI_PORT_REGISTERS_SIZE +
1164 AHCI_PORT_IS_REGISTER_OFFSET;
1165 ahci_cmds[base + 2].addr = ahci_cmds[base].addr;
1166
1167 ahci_cmds[base + 3].addr =
1168 ((uint32_t *) RNGABSPTR(hw_res_parsed.mem_ranges.ranges[0])) +
1169 AHCI_GHC_IS_REGISTER_OFFSET;
1170 ahci_cmds[base + 4].addr = ahci_cmds[base + 3].addr;
1171 }
1172
1173 irq_code_t ct;
1174 ct.cmdcount = sizeof(ahci_cmds) / sizeof(irq_cmd_t);
1175 ct.cmds = ahci_cmds;
1176 ct.rangecount = sizeof(ahci_ranges) / sizeof(irq_pio_range_t);
1177 ct.ranges = ahci_ranges;
1178
1179 cap_irq_handle_t irq_cap;
1180 errno_t rc = register_interrupt_handler(dev,
1181 hw_res_parsed.irqs.irqs[0], ahci_interrupt, (void *)ahci, &ct,
1182 &irq_cap);
1183 if (rc != EOK) {
1184 ddf_msg(LVL_ERROR, "Failed registering interrupt handler.");
1185 goto error_register_interrupt_handler;
1186 }
1187
1188 rc = hw_res_enable_interrupt(ahci->parent_sess,
1189 hw_res_parsed.irqs.irqs[0]);
1190 if (rc != EOK) {
1191 ddf_msg(LVL_ERROR, "Failed enable interupt.");
1192 goto error_enable_interrupt;
1193 }
1194
1195 hw_res_list_parsed_clean(&hw_res_parsed);
1196 return ahci;
1197
1198error_enable_interrupt:
1199 unregister_interrupt_handler(dev, irq_cap);
1200
1201error_register_interrupt_handler:
1202 // FIXME: unmap physical memory
1203
1204error_map_registers:
1205 hw_res_list_parsed_clean(&hw_res_parsed);
1206
1207error_get_res_parsed:
1208 free(ahci);
1209 return NULL;
1210}
1211
1212/** Initialize and start AHCI hardware device.
1213 *
1214 * @param ahci AHCI device.
1215 *
1216 */
1217static void ahci_ahci_hw_start(ahci_dev_t *ahci)
1218{
1219 /* Disable command completion coalescing feature */
1220 ahci_ghc_ccc_ctl_t ccc;
1221
1222 ccc.u32 = ahci->memregs->ghc.ccc_ctl;
1223 ccc.en = 0;
1224 ahci->memregs->ghc.ccc_ctl = ccc.u32;
1225
1226 /* Set master latency timer. */
1227 pci_config_space_write_8(ahci->parent_sess, AHCI_PCI_MLT, 32);
1228
1229 /* Enable PCI interrupt and bus mastering */
1230 ahci_pcireg_cmd_t cmd;
1231
1232 pci_config_space_read_16(ahci->parent_sess, AHCI_PCI_CMD, &cmd.u16);
1233 cmd.id = 0;
1234 cmd.bme = 1;
1235 pci_config_space_write_16(ahci->parent_sess, AHCI_PCI_CMD, cmd.u16);
1236
1237 /* Enable AHCI and interrupt. */
1238 ahci->memregs->ghc.ghc = AHCI_GHC_GHC_AE | AHCI_GHC_GHC_IE;
1239}
1240
1241/** AHCI device driver initialization
1242 *
1243 * Create and initialize all SATA structure devices for connected
1244 * SATA drives.
1245 *
1246 * @param dev DDF device structure.
1247 *
1248 * @return EOK if succeed, error code otherwise.
1249 *
1250 */
1251static errno_t ahci_dev_add(ddf_dev_t *dev)
1252{
1253 ahci_dev_t *ahci = ahci_ahci_create(dev);
1254 if (ahci == NULL)
1255 goto error;
1256
1257 /* Start AHCI hardware. */
1258 ahci_ahci_hw_start(ahci);
1259
1260 /* Create device structures for sata devices attached to AHCI. */
1261 ahci_sata_devices_create(ahci, dev);
1262
1263 return EOK;
1264
1265error:
1266 return EINTR;
1267}
1268
1269/*
1270 * Helpers and utilities
1271 */
1272
1273/** Convert SATA model name
1274 *
1275 * Convert SATA model name from machine format returned by
1276 * identify device command to human readable form.
1277 *
1278 * @param src Source buffer with device name in machine format.
1279 * @param dst Buffer for human readable string, minimum size is 41 chars.
1280 *
1281 */
1282static void ahci_get_model_name(uint16_t *src, char *dst)
1283{
1284 uint8_t model[40];
1285 memset(model, 0, 40);
1286
1287 for (unsigned int i = 0; i < 20; i++) {
1288 uint16_t w = src[i];
1289 model[2 * i] = w >> 8;
1290 model[2 * i + 1] = w & 0x00ff;
1291 }
1292
1293 uint32_t len = 40;
1294 while ((len > 0) && (model[len - 1] == 0x20))
1295 len--;
1296
1297 size_t pos = 0;
1298 for (unsigned int i = 0; i < len; i++) {
1299 uint8_t c = model[i];
1300 if (c >= 0x80)
1301 c = '?';
1302
1303 chr_encode(c, dst, &pos, 40);
1304 }
1305
1306 dst[pos] = '\0';
1307}
1308
1309/*
1310 * AHCI Main routine
1311 */
1312
1313int main(int argc, char *argv[])
1314{
1315 printf("%s: HelenOS AHCI device driver\n", NAME);
1316 ddf_log_init(NAME);
1317 fibril_mutex_initialize(&sata_devices_count_lock);
1318 return ddf_driver_main(&ahci_driver);
1319}
Note: See TracBrowser for help on using the repository browser.