blob: 80178c313db05f2bca025b4cb3b75b6b789bdd31 [file] [log] [blame]
Nico Huber1f6bd942012-08-30 15:36:57 +02001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2012 secunet Security Networks AG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. 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 * 3. 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 AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <libpayload.h>
31#include <stdint.h>
32#include <string.h>
33#include <stdio.h>
34
35#include <storage/ata.h>
36
37
38/** Reads non-sector-aligned blocks of 512 bytes. */
39static ssize_t ata_read_unaligned(ata_dev_t *const dev,
40 const lba_t blk_start, size_t blk_count,
41 u8 *blk_buf)
42{
43 ssize_t ret = 0;
44 lba_t sec_start;
45 size_t blk_residue;
46
47 u8 *const sec_buf = malloc(dev->sector_size);
48 if (sec_buf == NULL)
49 return -1;
50
51 const size_t shift = dev->sector_size_shift - 9;
52 const size_t mask = (dev->sector_size >> 9) - 1;
53
54 /* Sector aligned start block. */
55 const lba_t blk_aligned = blk_start & ~mask;
56
57 /* First sector to read from. */
58 sec_start = blk_aligned >> shift;
59
60 /* Calculate and read residue before sector aligned blocks. */
61 blk_residue = MIN(blk_start - blk_aligned, blk_count);
62 if (blk_residue) {
63 if (dev->read_sectors(dev, sec_start, 1, sec_buf) != 1)
64 goto _free_ret;
65
66 const size_t bytes = blk_residue << 9;
67 memcpy(blk_buf, sec_buf + (dev->sector_size - bytes), bytes);
68 blk_count -= blk_residue;
69 blk_buf += bytes;
70 ++sec_start;
71
72 ret = blk_residue;
73 if (blk_count == 0)
74 goto _free_ret;
75 }
76
77 /* Read all sector aligned blocks. */
78 const size_t sec_count = (blk_count & ~mask) >> shift;
79 const int sec_read = dev->read_sectors(
80 dev, sec_start, sec_count, blk_buf);
81 if (sec_read < 0)
82 goto _free_ret;
83 ret += sec_read << shift;
84 if (sec_read != sec_count)
85 goto _free_ret;
86
87 /* Calculate and read residue. */
88 blk_residue = blk_count & mask;
89 if (blk_residue) {
90 sec_start += sec_read;
91 blk_buf += sec_read << dev->sector_size_shift;
92
93 if (dev->read_sectors(dev, sec_start, 1, sec_buf) != 1)
94 goto _free_ret;
95
96 const size_t bytes = blk_residue << 9;
97 memcpy(blk_buf, sec_buf, bytes);
98 ret += blk_residue;
99 }
100
101_free_ret:
102 free(sec_buf);
103 return ret;
104}
105
106static ssize_t ata_read512(storage_dev_t *_dev,
107 const lba_t start, const size_t count,
108 unsigned char *const buf)
109{
110 ata_dev_t *const dev = (ata_dev_t *)_dev;
111
112 if (dev->read_sectors == NULL) {
113 printf("ata: No read support implemented.\n");
114 return -1;
115 }
116
117 if (dev->sector_size == 512) {
118 return dev->read_sectors(dev, start, count, buf);
119 } else if (dev->sector_size > 512) {
120 /* Sector size has to be a power of two. */
121 const size_t mask = (dev->sector_size >> 9) - 1;
122 if (!(start & mask) && !(count & mask)) {
123 const size_t shift = dev->sector_size_shift - 9;
124 const ssize_t ret = dev->read_sectors(dev,
125 start >> shift, count >> shift, buf);
126 if (ret < 0)
127 return ret;
128 else
129 return ret << shift;
130 } else {
131 return ata_read_unaligned(dev, start, count, buf);
132 }
133 } else {
134 printf("ata: No support for sectors smaller than 512 bytes.\n");
135 return -1;
136 }
137}
138
139static ssize_t ata_write512(storage_dev_t *const dev,
140 const lba_t start, const size_t count,
141 const unsigned char *const buf)
142{
143 printf("ata: No write support implemented.\n");
144 return -1;
145}
146
147void ata_initialize_storage_ops(ata_dev_t *const dev)
148{
149 dev->storage_dev.read_blocks512 = ata_read512;
150 dev->storage_dev.write_blocks512 = ata_write512;
151}
152
153int ata_set_sector_size(ata_dev_t *const dev, u32 sector_size)
154{
155 if (!sector_size || (sector_size & (sector_size - 1))) {
156 printf("ata: Sector size is not a power of two (%u).\n",
157 sector_size);
158 return -1;
159 }
160 dev->sector_size = sector_size;
161 dev->sector_size_shift = 0;
162 while (sector_size >>= 1)
163 ++dev->sector_size_shift;
164
165 return 0;
166}
167
168static int ata_decode_sector_size(ata_dev_t *const dev, const u16 *const id)
169{
170 u32 size;
171 if ((id[ATA_ID_SECTOR_SIZE] & ((3 << 14) | (1 << 12)))
172 != ((1 << 14) | (1 << 12)))
173 size = DEFAULT_ATA_SECTOR_SIZE;
174 else
175 size = (id[ATA_ID_LOGICAL_SECTOR_SIZE] |
176 (id[ATA_ID_LOGICAL_SECTOR_SIZE + 1] << 16)) << 1;
177
178 return ata_set_sector_size(dev, size);
179}
180
181/**
182 * Copies n-1 bytes from src to dest swapping each two bytes, removes
183 * trailing spaces and terminates dest with '\0'.
184 */
185char *ata_strncpy(char *const dest, const u16 *const src, const size_t n)
186{
187 int i;
188
189 for (i = 0; i < (n - 1); i += 2) {
190 dest[i] = ((const char *)src)[i + 1];
191 dest[i + 1] = ((const char *)src)[i];
192 }
193
194 for (i = n - 2; i >= 0; --i)
195 if (dest[i] != ' ')
196 break;
197 dest[i + 1] = '\0';
198
199 return dest;
200}
201
202int ata_attach_device(ata_dev_t *const dev, const storage_port_t port_type)
203{
204 u16 id[256];
205
206 dev->identify_cmd = ATA_IDENTIFY_DEVICE;
207 if (dev->identify(dev, (u8 *)id))
208 return -1;
209
210 char fw[9], model[41];
211 ata_strncpy(fw, id + 23, sizeof(fw));
212 ata_strncpy(model, id + 27, sizeof(model));
213 printf("ata: Identified %s [%s]\n", model, fw);
214
Stefan Reinauer1b4d3942015-06-29 15:47:34 -0700215#if IS_ENABLED(CONFIG_LP_STORAGE_64BIT_LBA)
Nico Huber1f6bd942012-08-30 15:36:57 +0200216 if (id[ATA_CMDS_AND_FEATURE_SETS + 1] & (1 << 10)) {
217 printf("ata: Support for LBA-48 enabled.\n");
218 dev->read_cmd = ATA_READ_DMA_EXT;
219 } else {
220 dev->read_cmd = ATA_READ_DMA;
221 }
222#else
223 dev->read_cmd = ATA_READ_DMA;
224#endif
225
226 if (ata_decode_sector_size(dev, id))
227 return -1;
228
229 dev->storage_dev.port_type = port_type;
230 ata_initialize_storage_ops(dev);
231
232 return storage_attach_device(&dev->storage_dev);
233}