1/*
2 * Copyright (c) 2011 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <errors/errno.h>
12#include "sata_fis.h"
13
14void sata_h2d_fis_new(struct sata_fis_reg_h2d* fis, uint8_t command, uint64_t lba, uint16_t sectors)
15{
16    sata_h2d_fis_init(fis);
17    sata_h2d_set_command(fis, command);
18    sata_h2d_set_lba48(fis, lba);
19    sata_h2d_set_count(fis, sectors);
20}
21
22void sata_h2d_fis_init(struct sata_fis_reg_h2d* fis)
23{
24    fis->type = SATA_FIS_TYPE_H2D;
25
26    /* Device Shadow Register layout (see: [1])
27     * [  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  ]
28     * [  -  |  L  |  -  | DEV | HS3 | HS2 | HS1 | HS0 ]
29     *
30     * L is the address mode, cleared implies CHS addressing, set, LBA addressing
31     * DEV device select, cleared and set imply Device 0 and 1 resp.
32     *   for SATA this should always be cleared (see: [2])
33     * HS3-HS0 are bits 28-25 of the LBA 28 (not used for LBA 48, see [3])
34     *
35     * [1] Serial ATA NSSD Rev. 1.0 (Sept 2008), section 6.3.1
36     * [2] Serial ATA Rev. 2.6 (15-February-2007), section 13.1, paragraph 2
37     * [3] ATA8-ACS Rev. 3f (December 11, 2006), section 7.1.5.2
38     */
39    fis->device |= (1 << 6);
40}
41
42void sata_h2d_set_command(struct sata_fis_reg_h2d* fis, uint8_t command)
43{
44    fis->command = command;
45    /* set bit to indicate update of command register (see [1])
46     *
47     * [1]: SATA Rev. 2.6 (15-February-2007), section 10.3.4
48     */
49    fis->specialstuff |= (1 << 7);
50}
51
52void sata_h2d_set_feature(struct sata_fis_reg_h2d* fis, uint8_t feature)
53{
54    fis->feature = feature;
55}
56
57void sata_h2d_set_lba28(struct sata_fis_reg_h2d* fis, uint32_t lba)
58{
59    fis->lba0 = lba & 0xFF;
60    fis->lba1 = (lba >> 8) & 0xFF;
61    fis->lba2 = (lba >> 16) & 0xFF;
62    fis->device = (fis->device & ~0x0F) | ((lba >> 24) & 0x0F);
63}
64
65void sata_h2d_set_lba48(struct sata_fis_reg_h2d* fis, uint64_t lba)
66{
67    fis->lba0 = lba & 0xFF;
68    fis->lba1 = (lba >> 8) & 0xFF;
69    fis->lba2 = (lba >> 16) & 0xFF;
70    fis->device &= 0xF0; // clear bits otherwise used by lba28
71
72    fis->lba3 = (lba >> 24) & 0xFF;
73    fis->lba4 = (lba >> 32) & 0xFF;
74    fis->lba5 = (lba >> 40) & 0xFF;
75}
76
77void sata_h2d_set_count(struct sata_fis_reg_h2d* fis, uint16_t count)
78{
79    fis->countl = count & 0xFF;
80    fis->counth = (count >> 8) & 0xFF;
81}
82