/* -*- linux-c -*- * Copyright (c) 2004-2006 Winbond Electronics Corp. All rights reserved. * * The contents of this file are subject to the Open * Software License version 1.1 that can be found at * http://www.opensource.org/licenses/osl-1.1.txt and is included herein * by reference. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License version 2 (the "GPL") as distributed * in the kernel source COPYING file, in which case the provisions of * the GPL are applicable instead of the above. If you wish to allow * the use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under * the OSL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * Maintained by: Weiming Shuai Jin Yuan Mu Dezheng Shen $Author: sjin $ $Id: wbtable.c,v 1.5.2.5 2006/06/22 06:06:12 sjin Exp $ --- don't modify lines above --- Description: Enviornments: (1) RedHat 9 on 32-bit Intel UP/32-bit Intel dual-core (2) Fedora Core 4 (2.6.11) on 32-bit Intel/32-bit Intel dual-core/64-bit AMD/64-bit Intel dual-core (3) RedHat Enterprise Workstatin Rel 4 UP2 (2.6.9) on 32-bit Intel 32-bit Intel dual-core/64-bit AMD/64-bit Intel dual-core */ #include "wbtable.h" #include "wbdebug.h" //table operating functions static unsigned short g_table_logical_physical[WB_MAX_NUM_SEG * WB_MAX_NUM_LOGICAL]; static unsigned short g_table_physical_logical[WB_MAX_NUM_SEG * WB_MAX_NUM_PHYSICAL]; static unsigned short g_num_seg; static unsigned int g_total_physical; static unsigned int g_total_logical; static unsigned short g_num_page_per_physical; int wbtable_init(unsigned int blk_size, unsigned int total_physical) { int ret, i; ENTER(); ret = -1; switch (blk_size) { // 16KB physical block size case 0x10: g_num_page_per_physical = 32; break; // 16KB physical block size case 0x08: g_num_page_per_physical = 16; break; default: WB_PRINTK_ERROR ("two possible values are 0x10 and 0x08, blk_size = %x\n", blk_size); goto lab_out; break; } g_total_physical = total_physical; g_num_seg = g_total_physical / WB_MAX_NUM_PHYSICAL; // only 494 logical blocks are allowed in segment 0 g_total_logical = g_num_seg * WB_MAX_NUM_LOGICAL - 2; for (i = 0; i < g_total_physical; i++) { g_table_physical_logical[i] = WB_TABLE_UNUSED; } for (i = 0; i < g_total_logical; i++) { g_table_logical_physical[i] = WB_TABLE_UNUSED; } ret = 0; lab_out: LEAVE(); return ret; } int wbtable_add_link_physical_logical(unsigned int physical, unsigned int logical) { int ret; ENTER(); if ((ret = wbtable_chk_limit(0, physical, logical))) goto lab_out; g_table_physical_logical[physical] = logical; lab_out: LEAVE(); return ret; } int wbtable_add_link_logical_physical(unsigned int logical, unsigned int physical) { int ret; ENTER(); if ((ret = wbtable_chk_limit(0, physical, logical))) goto lab_out; g_table_logical_physical[logical] = physical; lab_out: LEAVE(); return ret; } // precondition: int wbtable_del_link(unsigned int physical, unsigned int logical) { int ret; ENTER(); if ((ret = wbtable_chk_limit(0, physical, logical))) goto lab_out; if ((WB_TABLE_DEFECT == g_table_physical_logical[physical]) || (WB_TABLE_UNUSED == g_table_physical_logical[physical])) { WB_PRINTK_ERROR ("physical block address mapping doesn't make sense\n"); ret = 1; goto lab_out; } if ((WB_TABLE_UNUSED == g_table_logical_physical[logical])) { WB_PRINTK_ERROR ("logical block address mapping doesn't make sense\n"); ret = 1; goto lab_out; } g_table_physical_logical[physical] = WB_TABLE_UNUSED; g_table_logical_physical[logical] = WB_TABLE_UNUSED; lab_out: LEAVE(); return ret; } // never fails int wbtable_sanity_chk(void) { int physical, logical; ENTER(); for (physical = 0; physical < g_total_physical; physical++) { logical = g_table_physical_logical[physical]; if ((WB_TABLE_UNUSED == logical) || (WB_TABLE_DEFECT == logical)) continue; else { if (g_table_logical_physical[logical] != physical) WB_PRINTK_ERROR ("inconsistency in transformation table, " "physical = %d logical = %d ", physical, logical); } } LEAVE(); return 0; } // never fails int wbtable_dump(void) { int physical, newLine; ENTER(); newLine = 0; for (physical = 0; physical < 0x20; physical++) { WB_PRINTK("[%X]=", physical); if (WB_TABLE_UNUSED == g_table_physical_logical[physical]) WB_PRINTK("%s", "UN,"); else if (WB_TABLE_DEFECT == g_table_physical_logical[physical]) WB_PRINTK("%s", "DE,"); else WB_PRINTK("%X,", g_table_physical_logical[physical]); if (0 == (newLine++ % 5)) { WB_PRINTK("\n"); schedule(); } } LEAVE(); return 0; } int wbtable_chk_limit(unsigned int seg, unsigned int physical, unsigned int logical) { int ret; ENTER(); ret = 0; if (WB_MAX_NUM_SEG < seg) { ret = 1; WB_PRINTK_ERROR("segment out of range, seg = %d MAX = %d\n", seg, WB_MAX_NUM_SEG); goto lab_out; } if (g_total_physical < physical) { WB_PRINTK_ERROR ("physical block address out of range, physical = %d MAX = %d\n", physical, g_total_physical); ret = 1; goto lab_out; } if ((g_total_logical < logical) && (WB_TABLE_UNUSED != logical) && (WB_TABLE_DEFECT != logical)) { WB_PRINTK_ERROR ("logical block address out of range, logical = %d \n", logical); ret = 1; goto lab_out; } lab_out: LEAVE(); return ret; } unsigned int wbtable_get_logical(unsigned int physical) { ENTER(); LEAVE(); return g_table_physical_logical[physical]; } unsigned int wbtable_get_physical(unsigned int logical) { ENTER(); LEAVE(); return g_table_logical_physical[logical]; } unsigned int wbtable_get_seg(unsigned int lba) { unsigned int seg, logical; ENTER(); return (lba / g_num_page_per_physical + 2) / 496; logical = lba / g_num_page_per_physical; if (logical < 494) seg = 0; else { seg = (logical - 494) / 496 + 1; } LEAVE(); return seg; } // the returned physical block is not erased yet unsigned int wbtable_get_unused_physical(unsigned int seg) { int index, low, high; ENTER(); low = seg * WB_MAX_NUM_PHYSICAL; high = low + 512; for (index = low; index < high; index++) { if (WB_TABLE_UNUSED == g_table_physical_logical[index]) break; } if (high == index) WB_PRINTK_ERROR ("danger!! can't find any unused physical block\n"); LEAVE(); return index; } unsigned int wbtable_add_link(unsigned int logical, unsigned int physical) { ENTER(); wbtable_add_link_logical_physical(logical, physical); wbtable_add_link_physical_logical(physical, logical); LEAVE(); return 0; }