2006-06-27 12:22:22 +04:00
/*
* Copyright (c) International Business Machines Corp., 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
/* Here we keep miscellaneous functions which are used all over the UBI code */
#include "ubi.h"
/**
* calc_data_len - calculate how much real data is stored in a buffer.
* @ubi: UBI device description object
* @buf: a buffer with the contents of the physical eraseblock
* @length: the buffer length
*
* This function calculates how much "real data" is stored in @buf and returnes
* the length. Continuous 0xFF bytes at the end of the buffer are not
* considered as "real data".
*/
int ubi_calc_data_len ( const struct ubi_device * ubi , const void * buf ,
int length )
{
int i ;
2008-05-22 10:32:18 +09:00
ubi_assert ( ! ( length & ( ubi -> min_io_size - 1 )));
2006-06-27 12:22:22 +04:00
for ( i = length - 1 ; i >= 0 ; i -- )
if ((( const uint8_t * ) buf )[ i ] != 0xFF )
break ;
/* The resulting length must be aligned to the minimum flash I/O size */
length = ALIGN ( i + 1 , ubi -> min_io_size );
return length ;
}
/**
* ubi_check_volume - check the contents of a static volume.
* @ubi: UBI device description object
* @vol_id: ID of the volume to check
*
* This function checks if static volume @vol_id is corrupted by fully reading
* it and checking data CRC. This function returns %0 if the volume is not
* corrupted, %1 if it is corrupted and a negative error code in case of
* failure. Dynamic volumes are not checked and zero is returned immediately.
*/
int ubi_check_volume ( struct ubi_device * ubi , int vol_id )
{
void * buf ;
int err = 0 , i ;
struct ubi_volume * vol = ubi -> volumes [ vol_id ];
if ( vol -> vol_type != UBI_STATIC_VOLUME )
return 0 ;
2007-05-06 16:12:54 +03:00
buf = vmalloc ( vol -> usable_leb_size );
2006-06-27 12:22:22 +04:00
if ( ! buf )
return - ENOMEM ;
for ( i = 0 ; i < vol -> used_ebs ; i ++ ) {
int size ;
2014-12-30 11:56:09 +08:00
cond_resched ();
2006-06-27 12:22:22 +04:00
if ( i == vol -> used_ebs - 1 )
size = vol -> last_eb_bytes ;
else
size = vol -> usable_leb_size ;
2007-12-16 20:00:38 +02:00
err = ubi_eba_read_leb ( ubi , vol , i , buf , 0 , size , 1 );
2006-06-27 12:22:22 +04:00
if ( err ) {
2011-09-20 18:34:25 -07:00
if ( mtd_is_eccerr ( err ))
2006-06-27 12:22:22 +04:00
err = 1 ;
break ;
}
}
2007-05-06 16:12:54 +03:00
vfree ( buf );
2006-06-27 12:22:22 +04:00
return err ;
}
2012-07-04 11:06:04 +03:00
/**
* ubi_update_reserved - update bad eraseblock handling accounting data.
* @ubi: UBI device description object
*
* This function calculates the gap between current number of PEBs reserved for
* bad eraseblock handling and the required level of PEBs that must be
* reserved, and if necessary, reserves more PEBs to fill that gap, according
* to availability. Should be called with ubi->volumes_lock held.
*/
void ubi_update_reserved ( struct ubi_device * ubi )
{
int need = ubi -> beb_rsvd_level - ubi -> beb_rsvd_pebs ;
if ( need <= 0 || ubi -> avail_pebs == 0 )
return ;
need = min_t ( int , need , ubi -> avail_pebs );
ubi -> avail_pebs -= need ;
ubi -> rsvd_pebs += need ;
ubi -> beb_rsvd_pebs += need ;
2014-10-20 19:57:00 +03:00
ubi_msg ( ubi , "reserved more %d PEBs for bad PEB handling" , need );
2012-07-04 11:06:04 +03:00
}
2006-06-27 12:22:22 +04:00
/**
2012-07-04 11:06:03 +03:00
* ubi_calculate_reserved - calculate how many PEBs must be reserved for bad
2006-06-27 12:22:22 +04:00
* eraseblock handling.
* @ubi: UBI device description object
*/
void ubi_calculate_reserved ( struct ubi_device * ubi )
{
2012-07-04 11:06:01 +03:00
/*
* Calculate the actual number of PEBs currently needed to be reserved
* for future bad eraseblock handling.
*/
ubi -> beb_rsvd_level = ubi -> bad_peb_limit - ubi -> bad_peb_count ;
if ( ubi -> beb_rsvd_level < 0 ) {
ubi -> beb_rsvd_level = 0 ;
2014-10-20 19:57:00 +03:00
ubi_warn ( ubi , "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)" ,
2012-07-04 11:06:01 +03:00
ubi -> bad_peb_count , ubi -> bad_peb_limit );
}
2006-06-27 12:22:22 +04:00
}
2010-07-31 09:37:34 +03:00
/**
* ubi_check_pattern - check if buffer contains only a certain byte pattern.
* @buf: buffer to check
* @patt: the pattern to check
* @size: buffer size in bytes
*
* This function returns %1 in there are only @patt bytes in @buf, and %0 if
* something else was also found.
*/
int ubi_check_pattern ( const void * buf , uint8_t patt , int size )
{
int i ;
for ( i = 0 ; i < size ; i ++ )
if ((( const uint8_t * ) buf )[ i ] != patt )
return 0 ;
return 1 ;
}
2016-02-25 09:25:20 -08:00
/* Normal UBI messages */
void ubi_msg ( const struct ubi_device * ubi , const char * fmt , ...)
{
struct va_format vaf ;
va_list args ;
va_start ( args , fmt );
vaf . fmt = fmt ;
vaf . va = & args ;
pr_notice ( UBI_NAME_STR "%d: %pV \n " , ubi -> ubi_num , & vaf );
va_end ( args );
}
/* UBI warning messages */
void ubi_warn ( const struct ubi_device * ubi , const char * fmt , ...)
{
struct va_format vaf ;
va_list args ;
va_start ( args , fmt );
vaf . fmt = fmt ;
vaf . va = & args ;
pr_warn ( UBI_NAME_STR "%d warning: %ps: %pV \n " ,
ubi -> ubi_num , __builtin_return_address ( 0 ), & vaf );
va_end ( args );
}
/* UBI error messages */
void ubi_err ( const struct ubi_device * ubi , const char * fmt , ...)
{
struct va_format vaf ;
va_list args ;
va_start ( args , fmt );
vaf . fmt = fmt ;
vaf . va = & args ;
pr_err ( UBI_NAME_STR "%d error: %ps: %pV \n " ,
ubi -> ubi_num , __builtin_return_address ( 0 ), & vaf );
va_end ( args );
}