source: mainline/uspace/drv/block/ahci/ahci.c@ 7dddd7b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7dddd7b was d51838f, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Let leaf drivers enable/disable/clear interrupts via hw_res instead of directly using irc.

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