1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * 2017 by Marek Behun <marek.behun@nic.cz>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Derived from code in ext4/dev.c, which was based on reiserfs/dev.c
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <compiler.h>
11*4882a593Smuzhiyun #include <part.h>
12*4882a593Smuzhiyun #include <memalign.h>
13*4882a593Smuzhiyun
fs_devread(struct blk_desc * blk,disk_partition_t * partition,lbaint_t sector,int byte_offset,int byte_len,char * buf)14*4882a593Smuzhiyun int fs_devread(struct blk_desc *blk, disk_partition_t *partition,
15*4882a593Smuzhiyun lbaint_t sector, int byte_offset, int byte_len, char *buf)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun unsigned block_len;
18*4882a593Smuzhiyun int log2blksz;
19*4882a593Smuzhiyun ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, (blk ? blk->blksz : 0));
20*4882a593Smuzhiyun if (blk == NULL) {
21*4882a593Smuzhiyun printf("** Invalid Block Device Descriptor (NULL)\n");
22*4882a593Smuzhiyun return 0;
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun log2blksz = blk->log2blksz;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* Check partition boundaries */
27*4882a593Smuzhiyun if ((sector + ((byte_offset + byte_len - 1) >> log2blksz))
28*4882a593Smuzhiyun >= partition->size) {
29*4882a593Smuzhiyun printf("%s read outside partition " LBAFU "\n", __func__,
30*4882a593Smuzhiyun sector);
31*4882a593Smuzhiyun return 0;
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /* Get the read to the beginning of a partition */
35*4882a593Smuzhiyun sector += byte_offset >> log2blksz;
36*4882a593Smuzhiyun byte_offset &= blk->blksz - 1;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun debug(" <" LBAFU ", %d, %d>\n", sector, byte_offset, byte_len);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (byte_offset != 0) {
41*4882a593Smuzhiyun int readlen;
42*4882a593Smuzhiyun /* read first part which isn't aligned with start of sector */
43*4882a593Smuzhiyun if (blk_dread(blk, partition->start + sector, 1,
44*4882a593Smuzhiyun (void *)sec_buf) != 1) {
45*4882a593Smuzhiyun printf(" ** %s read error **\n", __func__);
46*4882a593Smuzhiyun return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun readlen = min((int)blk->blksz - byte_offset,
49*4882a593Smuzhiyun byte_len);
50*4882a593Smuzhiyun memcpy(buf, sec_buf + byte_offset, readlen);
51*4882a593Smuzhiyun buf += readlen;
52*4882a593Smuzhiyun byte_len -= readlen;
53*4882a593Smuzhiyun sector++;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun if (byte_len == 0)
57*4882a593Smuzhiyun return 1;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* read sector aligned part */
60*4882a593Smuzhiyun block_len = byte_len & ~(blk->blksz - 1);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (block_len == 0) {
63*4882a593Smuzhiyun ALLOC_CACHE_ALIGN_BUFFER(u8, p, blk->blksz);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun block_len = blk->blksz;
66*4882a593Smuzhiyun blk_dread(blk, partition->start + sector, 1,
67*4882a593Smuzhiyun (void *)p);
68*4882a593Smuzhiyun memcpy(buf, p, byte_len);
69*4882a593Smuzhiyun return 1;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (blk_dread(blk, partition->start + sector,
73*4882a593Smuzhiyun block_len >> log2blksz, (void *)buf) !=
74*4882a593Smuzhiyun block_len >> log2blksz) {
75*4882a593Smuzhiyun printf(" ** %s read error - block\n", __func__);
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun block_len = byte_len & ~(blk->blksz - 1);
79*4882a593Smuzhiyun buf += block_len;
80*4882a593Smuzhiyun byte_len -= block_len;
81*4882a593Smuzhiyun sector += block_len / blk->blksz;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (byte_len != 0) {
84*4882a593Smuzhiyun /* read rest of data which are not in whole sector */
85*4882a593Smuzhiyun if (blk_dread(blk, partition->start + sector, 1,
86*4882a593Smuzhiyun (void *)sec_buf) != 1) {
87*4882a593Smuzhiyun printf("* %s read error - last part\n", __func__);
88*4882a593Smuzhiyun return 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun memcpy(buf, sec_buf, byte_len);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun return 1;
93*4882a593Smuzhiyun }
94