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