1 /* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
2 *
3 * Copyright (c) 2014-2015 Datalight, Inc.
4 * All Rights Reserved Worldwide.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; use version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /* Businesses and individuals that for commercial or other reasons cannot
21 * comply with the terms of the GPLv2 license may obtain a commercial license
22 * before incorporating Reliance Edge into proprietary software for
23 * distribution in any form. Visit http://www.datalight.com/reliance-edge for
24 * more information.
25 */
26
27 /** @file
28 * @brief Implements block device I/O using logical blocks as the units.
29 *
30 * The OS block device implementations operate on sectors. The core does I/O
31 * in terms of logical blocks: this module translates from logical blocks to
32 * sectors.
33 *
34 * If bBlockIoRetries is greater than 0 for the current volume, then this
35 * module will retry block device calls on failure up to the configured number
36 * of times. This behavior caters to the type of unreliable hardware and
37 * drivers that are sometimes found in the IoT world, where one operation may
38 * fail but the next may still succeed.
39 */
40 #include <redfs.h>
41 #include <redcore.h>
42
43
44 /** @brief Read a range of logical blocks.
45 *
46 * @param bVolNum The volume whose block device is being read from.
47 * @param ulBlockStart The first block to read.
48 * @param ulBlockCount The number of blocks to read.
49 * @param pBuffer The buffer to populate with the data read.
50 *
51 * @return A negated ::REDSTATUS code indicating the operation result.
52 *
53 * @retval 0 Operation was successful.
54 * @retval -RED_EIO A disk I/O error occurred.
55 * @retval -RED_EINVAL Invalid parameters.
56 */
RedIoRead(uint8_t bVolNum,uint32_t ulBlockStart,uint32_t ulBlockCount,void * pBuffer)57 REDSTATUS RedIoRead( uint8_t bVolNum,
58 uint32_t ulBlockStart,
59 uint32_t ulBlockCount,
60 void * pBuffer )
61 {
62 REDSTATUS ret = 0;
63
64 if( ( bVolNum >= REDCONF_VOLUME_COUNT ) ||
65 ( ulBlockStart >= gaRedVolume[ bVolNum ].ulBlockCount ) ||
66 ( ( gaRedVolume[ bVolNum ].ulBlockCount - ulBlockStart ) < ulBlockCount ) ||
67 ( ulBlockCount == 0U ) ||
68 ( pBuffer == NULL ) )
69 {
70 REDERROR();
71 ret = -RED_EINVAL;
72 }
73 else
74 {
75 uint8_t bSectorShift = gaRedVolume[ bVolNum ].bBlockSectorShift;
76 uint64_t ullSectorStart = ( uint64_t ) ulBlockStart << bSectorShift;
77 uint32_t ulSectorCount = ulBlockCount << bSectorShift;
78 uint8_t bRetryIdx;
79
80 REDASSERT( bSectorShift < 32U );
81 REDASSERT( ( ulSectorCount >> bSectorShift ) == ulBlockCount );
82
83 for( bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++ )
84 {
85 ret = RedOsBDevRead( bVolNum, ullSectorStart, ulSectorCount, pBuffer );
86
87 if( ret == 0 )
88 {
89 break;
90 }
91 }
92 }
93
94 CRITICAL_ASSERT( ret == 0 );
95
96 return ret;
97 }
98
99
100 #if REDCONF_READ_ONLY == 0
101
102 /** @brief Write a range of logical blocks.
103 *
104 * @param bVolNum The volume whose block device is being written to.
105 * @param ulBlockStart The first block to write.
106 * @param ulBlockCount The number of blocks to write.
107 * @param pBuffer The buffer containing the data to write.
108 *
109 * @return A negated ::REDSTATUS code indicating the operation result.
110 *
111 * @retval 0 Operation was successful.
112 * @retval -RED_EIO A disk I/O error occurred.
113 * @retval -RED_EINVAL Invalid parameters.
114 */
RedIoWrite(uint8_t bVolNum,uint32_t ulBlockStart,uint32_t ulBlockCount,const void * pBuffer)115 REDSTATUS RedIoWrite( uint8_t bVolNum,
116 uint32_t ulBlockStart,
117 uint32_t ulBlockCount,
118 const void * pBuffer )
119 {
120 REDSTATUS ret = 0;
121
122 if( ( bVolNum >= REDCONF_VOLUME_COUNT ) ||
123 ( ulBlockStart >= gaRedVolume[ bVolNum ].ulBlockCount ) ||
124 ( ( gaRedVolume[ bVolNum ].ulBlockCount - ulBlockStart ) < ulBlockCount ) ||
125 ( ulBlockCount == 0U ) ||
126 ( pBuffer == NULL ) )
127 {
128 REDERROR();
129 ret = -RED_EINVAL;
130 }
131 else
132 {
133 uint8_t bSectorShift = gaRedVolume[ bVolNum ].bBlockSectorShift;
134 uint64_t ullSectorStart = ( uint64_t ) ulBlockStart << bSectorShift;
135 uint32_t ulSectorCount = ulBlockCount << bSectorShift;
136 uint8_t bRetryIdx;
137
138 REDASSERT( bSectorShift < 32U );
139 REDASSERT( ( ulSectorCount >> bSectorShift ) == ulBlockCount );
140
141 for( bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++ )
142 {
143 ret = RedOsBDevWrite( bVolNum, ullSectorStart, ulSectorCount, pBuffer );
144
145 if( ret == 0 )
146 {
147 break;
148 }
149 }
150 }
151
152 CRITICAL_ASSERT( ret == 0 );
153
154 return ret;
155 }
156
157
158 /** @brief Flush any caches beneath the file system.
159 *
160 * @param bVolNum The volume number of the volume whose block device is being
161 * flushed.
162 *
163 * @return A negated ::REDSTATUS code indicating the operation result.
164 *
165 * @retval 0 Operation was successful.
166 * @retval -RED_EINVAL @p bVolNum is an invalid volume number.
167 * @retval -RED_EIO A disk I/O error occurred.
168 */
RedIoFlush(uint8_t bVolNum)169 REDSTATUS RedIoFlush( uint8_t bVolNum )
170 {
171 REDSTATUS ret = 0;
172
173 if( bVolNum >= REDCONF_VOLUME_COUNT )
174 {
175 REDERROR();
176 ret = -RED_EINVAL;
177 }
178 else
179 {
180 uint8_t bRetryIdx;
181
182 for( bRetryIdx = 0U; bRetryIdx <= gpRedVolConf->bBlockIoRetries; bRetryIdx++ )
183 {
184 ret = RedOsBDevFlush( bVolNum );
185
186 if( ret == 0 )
187 {
188 break;
189 }
190 }
191 }
192
193 CRITICAL_ASSERT( ret == 0 );
194
195 return ret;
196 }
197 #endif /* REDCONF_READ_ONLY == 0 */
198