source: mainline/uspace/drv/block/ahci/ahci.c@ ebbc8a74

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ebbc8a74 was 76c07e4, checked in by Martin Decky <martin@…>, 13 years ago

fix condition reset

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