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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <errors/errno.h> 12#include <ahci/sata_fis.h> 13 14errval_t sata_alloc_h2d_register_fis(void **fis_p, size_t *fis_size_p) 15{ 16 struct sata_fis_reg_h2d *fis; 17 18 fis = calloc(1, sizeof(*fis)); 19 if (!fis) { 20 return LIB_ERR_MALLOC_FAIL; 21 } 22 fis->type = SATA_FIS_TYPE_H2D; 23 24 /* Device Shadow Register layout (see: [1]) 25 * [ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ] 26 * [ - | L | - | DEV | HS3 | HS2 | HS1 | HS0 ] 27 * 28 * L is the address mode, cleared implies CHS addressing, set, LBA addressing 29 * DEV device select, cleared and set imply Device 0 and 1 resp. 30 * for SATA this should always be cleared (see: [2]) 31 * HS3-HS0 are bits 28-25 of the LBA 28 (not used for LBA 48, see [3]) 32 * 33 * [1] Serial ATA NSSD Rev. 1.0 (Sept 2008), section 6.3.1 34 * [2] Serial ATA Rev. 2.6 (15-February-2007), section 13.1, paragraph 2 35 * [3] ATA8-ACS Rev. 3f (December 11, 2006), section 7.1.5.2 36 */ 37 fis->device |= (1 << 6); 38 39 *fis_p = fis; 40 *fis_size_p = sizeof(*fis); 41 42 return SYS_ERR_OK; 43} 44 45errval_t sata_set_command(void *fis, uint8_t command) 46{ 47 uint8_t fis_type = *(uint8_t*)fis; 48 49 if (fis_type == SATA_FIS_TYPE_H2D) { 50 struct sata_fis_reg_h2d *fis_reg_h2d = fis; 51 fis_reg_h2d->command = command; 52 53 /* set bit to indicate update of command register (see [1]) 54 * 55 * [1]: SATA Rev. 2.6 (15-February-2007), section 10.3.4 56 */ 57 fis_reg_h2d->specialstuff |= (1 << 7); 58 59 return SYS_ERR_OK; 60 } 61 else { 62 return SATA_ERR_INVALID_TYPE; 63 } 64} 65 66errval_t sata_set_feature(void *fis, uint8_t feature) 67{ 68 uint8_t fis_type = *(uint8_t*)fis; 69 70 if (fis_type == SATA_FIS_TYPE_H2D) { 71 struct sata_fis_reg_h2d *fis_reg_h2d = fis; 72 fis_reg_h2d->feature = feature; 73 74 return SYS_ERR_OK; 75 } 76 else { 77 return SATA_ERR_INVALID_TYPE; 78 } 79} 80 81errval_t sata_set_lba28(void *fis, uint32_t lba) 82{ 83 uint8_t fis_type = *(uint8_t*)fis; 84 85 if (fis_type == SATA_FIS_TYPE_H2D) { 86 struct sata_fis_reg_h2d *fis_reg_h2d = fis; 87 fis_reg_h2d->lba0 = lba & 0xFF; 88 fis_reg_h2d->lba1 = (lba >> 8) & 0xFF; 89 fis_reg_h2d->lba2 = (lba >> 16) & 0xFF; 90 fis_reg_h2d->device = (fis_reg_h2d->device & ~0x0F) | ((lba >> 24) & 0x0F); 91 92 return SYS_ERR_OK; 93 } 94 else { 95 return SATA_ERR_INVALID_TYPE; 96 } 97} 98 99errval_t sata_set_lba48(void *fis, uint64_t lba) 100{ 101 uint8_t fis_type = *(uint8_t*)fis; 102 103 if (fis_type == SATA_FIS_TYPE_H2D) { 104 struct sata_fis_reg_h2d *fis_reg_h2d = fis; 105 fis_reg_h2d->lba0 = lba & 0xFF; 106 fis_reg_h2d->lba1 = (lba >> 8) & 0xFF; 107 fis_reg_h2d->lba2 = (lba >> 16) & 0xFF; 108 fis_reg_h2d->device &= 0xF0; // clear bits otherwise used by lba28 109 110 fis_reg_h2d->lba3 = (lba >> 24) & 0xFF; 111 fis_reg_h2d->lba4 = (lba >> 32) & 0xFF; 112 fis_reg_h2d->lba5 = (lba >> 40) & 0xFF; 113 114 return SYS_ERR_OK; 115 } 116 else { 117 return SATA_ERR_INVALID_TYPE; 118 } 119} 120 121errval_t sata_set_count(void *fis, uint16_t count) 122{ 123 uint8_t fis_type = *(uint8_t*)fis; 124 125 if (fis_type == SATA_FIS_TYPE_H2D) { 126 struct sata_fis_reg_h2d *fis_reg_h2d = fis; 127 fis_reg_h2d->countl = count & 0xFF; 128 fis_reg_h2d->counth = (count >> 8) & 0xFF; 129 130 return SYS_ERR_OK; 131 } 132 else { 133 return SATA_ERR_INVALID_TYPE; 134 } 135} 136