1*832e988bSandvar /* $NetBSD: ebh.c,v 1.11 2025/01/08 11:39:50 andvar Exp $ */ 2288addd0Sahoka 3288addd0Sahoka /*- 4288addd0Sahoka * Copyright (c) 2010 Department of Software Engineering, 5288addd0Sahoka * University of Szeged, Hungary 6288addd0Sahoka * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu> 7288addd0Sahoka * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu> 8288addd0Sahoka * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu> 9288addd0Sahoka * Copyright (C) 2009 Tamas Toth <ttoth@inf.u-szeged.hu> 10288addd0Sahoka * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org> 11288addd0Sahoka * All rights reserved. 12288addd0Sahoka * 13288addd0Sahoka * This code is derived from software contributed to The NetBSD Foundation 14288addd0Sahoka * by the Department of Software Engineering, University of Szeged, Hungary 15288addd0Sahoka * 16288addd0Sahoka * Redistribution and use in source and binary forms, with or without 17288addd0Sahoka * modification, are permitted provided that the following conditions 18288addd0Sahoka * are met: 19288addd0Sahoka * 1. Redistributions of source code must retain the above copyright 20288addd0Sahoka * notice, this list of conditions and the following disclaimer. 21288addd0Sahoka * 2. Redistributions in binary form must reproduce the above copyright 22288addd0Sahoka * notice, this list of conditions and the following disclaimer in the 23288addd0Sahoka * documentation and/or other materials provided with the distribution. 24288addd0Sahoka * 25288addd0Sahoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26288addd0Sahoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27288addd0Sahoka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28288addd0Sahoka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29288addd0Sahoka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30288addd0Sahoka * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31288addd0Sahoka * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32288addd0Sahoka * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33288addd0Sahoka * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34288addd0Sahoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35288addd0Sahoka * SUCH DAMAGE. 36288addd0Sahoka */ 37288addd0Sahoka 38288addd0Sahoka #include "ebh.h" 39288addd0Sahoka 40288addd0Sahoka /*****************************************************************************/ 41288addd0Sahoka /* Flash specific operations */ 42288addd0Sahoka /*****************************************************************************/ 43288addd0Sahoka int nor_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr); 44288addd0Sahoka int nand_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr); 45288addd0Sahoka int nor_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset); 46288addd0Sahoka int nand_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset); 47288addd0Sahoka int nor_read_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr); 48288addd0Sahoka int nand_read_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr); 49288addd0Sahoka int nor_write_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr); 50288addd0Sahoka int nand_write_eb_hdr(struct chfs_ebh *ebh, int pebnr,struct chfs_eb_hdr *ebhdr); 51288addd0Sahoka int nor_check_eb_hdr(struct chfs_ebh *ebh, void *buf); 52288addd0Sahoka int nand_check_eb_hdr(struct chfs_ebh *ebh, void *buf); 53288addd0Sahoka int nor_mark_eb_hdr_dirty_flash(struct chfs_ebh *ebh, int pebnr, int lid); 54288addd0Sahoka int nor_invalidate_eb_hdr(struct chfs_ebh *ebh, int pebnr); 55288addd0Sahoka int mark_eb_hdr_free(struct chfs_ebh *ebh, int pebnr, int ec); 56288addd0Sahoka 57288addd0Sahoka int ltree_entry_cmp(struct chfs_ltree_entry *le1, struct chfs_ltree_entry *le2); 58288addd0Sahoka int peb_in_use_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2); 59288addd0Sahoka int peb_free_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2); 60288addd0Sahoka int add_peb_to_erase_queue(struct chfs_ebh *ebh, int pebnr, int ec,struct peb_queue *queue); 61288addd0Sahoka struct chfs_peb * find_peb_in_use(struct chfs_ebh *ebh, int pebnr); 62288addd0Sahoka int add_peb_to_free(struct chfs_ebh *ebh, int pebnr, int ec); 63288addd0Sahoka int add_peb_to_in_use(struct chfs_ebh *ebh, int pebnr, int ec); 64288addd0Sahoka void erase_callback(struct flash_erase_instruction *ei); 65288addd0Sahoka int free_peb(struct chfs_ebh *ebh); 66288addd0Sahoka int release_peb(struct chfs_ebh *ebh, int pebnr); 67288addd0Sahoka void erase_thread(void *data); 68288addd0Sahoka static void erase_thread_start(struct chfs_ebh *ebh); 69288addd0Sahoka static void erase_thread_stop(struct chfs_ebh *ebh); 70288addd0Sahoka int scan_leb_used_cmp(struct chfs_scan_leb *sleb1, struct chfs_scan_leb *sleb2); 71288addd0Sahoka int nor_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,struct chfs_eb_hdr *ebhdr, int pebnr, int leb_status); 72288addd0Sahoka int nor_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si, 73288addd0Sahoka int pebnr, struct chfs_eb_hdr *ebhdr); 74288addd0Sahoka int nand_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,struct chfs_eb_hdr *ebhdr, int pebnr); 75288addd0Sahoka int nand_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si, 76288addd0Sahoka int pebnr, struct chfs_eb_hdr *ebhdr); 77288addd0Sahoka struct chfs_scan_info *chfs_scan(struct chfs_ebh *ebh); 78288addd0Sahoka void scan_info_destroy(struct chfs_scan_info *si); 79288addd0Sahoka int scan_media(struct chfs_ebh *ebh); 80288addd0Sahoka int get_peb(struct chfs_ebh *ebh); 81288addd0Sahoka /** 82288addd0Sahoka * nor_create_eb_hdr - creates an eraseblock header for NOR flash 83288addd0Sahoka * @ebhdr: ebhdr to set 84288addd0Sahoka * @lnr: LEB number 85288addd0Sahoka */ 86288addd0Sahoka int 87288addd0Sahoka nor_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr) 88288addd0Sahoka { 89288addd0Sahoka ebhdr->u.nor_hdr.lid = htole32(lnr); 90288addd0Sahoka return 0; 91288addd0Sahoka } 92288addd0Sahoka 93288addd0Sahoka /** 94288addd0Sahoka * nand_create_eb_hdr - creates an eraseblock header for NAND flash 95288addd0Sahoka * @ebhdr: ebhdr to set 96288addd0Sahoka * @lnr: LEB number 97288addd0Sahoka */ 98288addd0Sahoka int 99288addd0Sahoka nand_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr) 100288addd0Sahoka { 101288addd0Sahoka ebhdr->u.nand_hdr.lid = htole32(lnr); 102288addd0Sahoka return 0; 103288addd0Sahoka } 104288addd0Sahoka 105288addd0Sahoka /** 106288addd0Sahoka * nor_calc_data_offs - calculates data offset on NOR flash 107288addd0Sahoka * @ebh: chfs eraseblock handler 108288addd0Sahoka * @pebnr: eraseblock number 109288addd0Sahoka * @offset: offset within the eraseblock 110288addd0Sahoka */ 111288addd0Sahoka int 112288addd0Sahoka nor_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset) 113288addd0Sahoka { 114288addd0Sahoka return pebnr * ebh->flash_if->erasesize + offset + 115288addd0Sahoka CHFS_EB_EC_HDR_SIZE + CHFS_EB_HDR_NOR_SIZE; 116288addd0Sahoka } 117288addd0Sahoka 118288addd0Sahoka /** 119288addd0Sahoka * nand_calc_data_offs - calculates data offset on NAND flash 120288addd0Sahoka * @ebh: chfs eraseblock handler 121288addd0Sahoka * @pebnr: eraseblock number 122288addd0Sahoka * @offset: offset within the eraseblock 123288addd0Sahoka */ 124288addd0Sahoka int 125288addd0Sahoka nand_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset) 126288addd0Sahoka { 127288addd0Sahoka return pebnr * ebh->flash_if->erasesize + offset + 128288addd0Sahoka 2 * ebh->flash_if->page_size; 129288addd0Sahoka } 130288addd0Sahoka 131288addd0Sahoka /** 132f273a7a1Sandvar * nor_read_eb_hdr - read eraseblock header from NOR flash 133288addd0Sahoka * 134288addd0Sahoka * @ebh: chfs eraseblock handler 135288addd0Sahoka * @pebnr: eraseblock number 136288addd0Sahoka * @ebhdr: whereto store the data 137288addd0Sahoka * 138288addd0Sahoka * Reads the eraseblock header from media. 139288addd0Sahoka * Returns zero in case of success, error code in case of fail. 140288addd0Sahoka */ 141288addd0Sahoka int 142288addd0Sahoka nor_read_eb_hdr(struct chfs_ebh *ebh, 143288addd0Sahoka int pebnr, struct chfs_eb_hdr *ebhdr) 144288addd0Sahoka { 145288addd0Sahoka int ret; 146288addd0Sahoka size_t retlen; 147288addd0Sahoka off_t ofs = pebnr * ebh->flash_if->erasesize; 148288addd0Sahoka 149288addd0Sahoka KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr); 150288addd0Sahoka 151288addd0Sahoka ret = flash_read(ebh->flash_dev, 152288addd0Sahoka ofs, CHFS_EB_EC_HDR_SIZE, 153288addd0Sahoka &retlen, (unsigned char *) &ebhdr->ec_hdr); 154288addd0Sahoka 155288addd0Sahoka if (ret || retlen != CHFS_EB_EC_HDR_SIZE) 156288addd0Sahoka return ret; 157288addd0Sahoka 158288addd0Sahoka ofs += CHFS_EB_EC_HDR_SIZE; 159288addd0Sahoka ret = flash_read(ebh->flash_dev, 160288addd0Sahoka ofs, CHFS_EB_HDR_NOR_SIZE, 161288addd0Sahoka &retlen, (unsigned char *) &ebhdr->u.nor_hdr); 162288addd0Sahoka 163288addd0Sahoka if (ret || retlen != CHFS_EB_HDR_NOR_SIZE) 164288addd0Sahoka return ret; 165288addd0Sahoka 166288addd0Sahoka return 0; 167288addd0Sahoka } 168288addd0Sahoka 169288addd0Sahoka /** 170f273a7a1Sandvar * nand_read_eb_hdr - read eraseblock header from NAND flash 171288addd0Sahoka * 172288addd0Sahoka * @ebh: chfs eraseblock handler 173288addd0Sahoka * @pebnr: eraseblock number 174288addd0Sahoka * @ebhdr: whereto store the data 175288addd0Sahoka * 176288addd0Sahoka * Reads the eraseblock header from media. It is on the first two page. 177288addd0Sahoka * Returns zero in case of success, error code in case of fail. 178288addd0Sahoka */ 179288addd0Sahoka int 180288addd0Sahoka nand_read_eb_hdr(struct chfs_ebh *ebh, int pebnr, 181288addd0Sahoka struct chfs_eb_hdr *ebhdr) 182288addd0Sahoka { 183288addd0Sahoka int ret; 184288addd0Sahoka size_t retlen; 185288addd0Sahoka off_t ofs; 186288addd0Sahoka 187288addd0Sahoka KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr); 188288addd0Sahoka 189288addd0Sahoka /* Read erase counter header from the first page. */ 190288addd0Sahoka ofs = pebnr * ebh->flash_if->erasesize; 191288addd0Sahoka ret = flash_read(ebh->flash_dev, 192288addd0Sahoka ofs, CHFS_EB_EC_HDR_SIZE, &retlen, 193288addd0Sahoka (unsigned char *) &ebhdr->ec_hdr); 194288addd0Sahoka if (ret || retlen != CHFS_EB_EC_HDR_SIZE) 195288addd0Sahoka return ret; 196288addd0Sahoka 197288addd0Sahoka /* Read NAND eraseblock header from the second page */ 198288addd0Sahoka ofs += ebh->flash_if->page_size; 199288addd0Sahoka ret = flash_read(ebh->flash_dev, 200288addd0Sahoka ofs, CHFS_EB_HDR_NAND_SIZE, &retlen, 201288addd0Sahoka (unsigned char *) &ebhdr->u.nand_hdr); 202288addd0Sahoka if (ret || retlen != CHFS_EB_HDR_NAND_SIZE) 203288addd0Sahoka return ret; 204288addd0Sahoka 205288addd0Sahoka return 0; 206288addd0Sahoka } 207288addd0Sahoka 208288addd0Sahoka /** 209f273a7a1Sandvar * nor_write_eb_hdr - write eraseblock header to NOR flash 210288addd0Sahoka * 211288addd0Sahoka * @ebh: chfs eraseblock handler 212288addd0Sahoka * @pebnr: eraseblock number whereto write 213288addd0Sahoka * @ebh: ebh to write 214288addd0Sahoka * 215288addd0Sahoka * Writes the eraseblock header to media. 216288addd0Sahoka * Returns zero in case of success, error code in case of fail. 217288addd0Sahoka */ 218288addd0Sahoka int 219288addd0Sahoka nor_write_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr) 220288addd0Sahoka { 221288addd0Sahoka int ret, crc; 222288addd0Sahoka size_t retlen; 223288addd0Sahoka 224288addd0Sahoka off_t ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE; 225288addd0Sahoka 226288addd0Sahoka ebhdr->u.nor_hdr.lid = ebhdr->u.nor_hdr.lid 227288addd0Sahoka | htole32(CHFS_LID_NOT_DIRTY_BIT); 228288addd0Sahoka 229288addd0Sahoka crc = crc32(0, (uint8_t *)&ebhdr->u.nor_hdr + 4, 230288addd0Sahoka CHFS_EB_HDR_NOR_SIZE - 4); 231288addd0Sahoka ebhdr->u.nand_hdr.crc = htole32(crc); 232288addd0Sahoka 233288addd0Sahoka KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr); 234288addd0Sahoka 235288addd0Sahoka ret = flash_write(ebh->flash_dev, 236288addd0Sahoka ofs, CHFS_EB_HDR_NOR_SIZE, &retlen, 237288addd0Sahoka (unsigned char *) &ebhdr->u.nor_hdr); 238288addd0Sahoka 239288addd0Sahoka if (ret || retlen != CHFS_EB_HDR_NOR_SIZE) 240288addd0Sahoka return ret; 241288addd0Sahoka 242288addd0Sahoka return 0; 243288addd0Sahoka } 244288addd0Sahoka 245288addd0Sahoka /** 246f273a7a1Sandvar * nand_write_eb_hdr - write eraseblock header to NAND flash 247288addd0Sahoka * 248288addd0Sahoka * @ebh: chfs eraseblock handler 249288addd0Sahoka * @pebnr: eraseblock number whereto write 250288addd0Sahoka * @ebh: ebh to write 251288addd0Sahoka * 252288addd0Sahoka * Writes the eraseblock header to media. 253288addd0Sahoka * Returns zero in case of success, error code in case of fail. 254288addd0Sahoka */ 255288addd0Sahoka int 256288addd0Sahoka nand_write_eb_hdr(struct chfs_ebh *ebh, int pebnr, 257288addd0Sahoka struct chfs_eb_hdr *ebhdr) 258288addd0Sahoka { 259288addd0Sahoka int ret, crc; 260288addd0Sahoka size_t retlen; 261288addd0Sahoka flash_off_t ofs; 262288addd0Sahoka 263288addd0Sahoka KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr); 264288addd0Sahoka 265288addd0Sahoka ofs = pebnr * ebh->flash_if->erasesize + 266288addd0Sahoka ebh->flash_if->page_size; 267288addd0Sahoka 268288addd0Sahoka ebhdr->u.nand_hdr.serial = htole64(++(*ebh->max_serial)); 269288addd0Sahoka 270288addd0Sahoka crc = crc32(0, (uint8_t *)&ebhdr->u.nand_hdr + 4, 271288addd0Sahoka CHFS_EB_HDR_NAND_SIZE - 4); 272288addd0Sahoka ebhdr->u.nand_hdr.crc = htole32(crc); 273288addd0Sahoka 274288addd0Sahoka ret = flash_write(ebh->flash_dev, ofs, 275288addd0Sahoka CHFS_EB_HDR_NAND_SIZE, &retlen, 276288addd0Sahoka (unsigned char *) &ebhdr->u.nand_hdr); 277288addd0Sahoka 278288addd0Sahoka if (ret || retlen != CHFS_EB_HDR_NAND_SIZE) 279288addd0Sahoka return ret; 280288addd0Sahoka 281288addd0Sahoka return 0; 282288addd0Sahoka } 283288addd0Sahoka 284288addd0Sahoka /** 285f273a7a1Sandvar * nor_check_eb_hdr - check eraseblock header read from NOR flash 286288addd0Sahoka * 287288addd0Sahoka * @ebh: chfs eraseblock handler 288288addd0Sahoka * @buf: eraseblock header to check 289288addd0Sahoka * 290288addd0Sahoka * Returns eraseblock header status. 291288addd0Sahoka */ 292288addd0Sahoka int 293288addd0Sahoka nor_check_eb_hdr(struct chfs_ebh *ebh, void *buf) 294288addd0Sahoka { 295288addd0Sahoka uint32_t magic, crc, hdr_crc; 296288addd0Sahoka struct chfs_eb_hdr *ebhdr = buf; 297288addd0Sahoka le32 lid_save; 298288addd0Sahoka 299288addd0Sahoka //check is there a header 300288addd0Sahoka if (check_pattern((void *) &ebhdr->ec_hdr, 301288addd0Sahoka 0xFF, 0, CHFS_EB_EC_HDR_SIZE)) { 302288addd0Sahoka dbg_ebh("no header found\n"); 303288addd0Sahoka return EBHDR_LEB_NO_HDR; 304288addd0Sahoka } 305288addd0Sahoka 306288addd0Sahoka // check magic 307288addd0Sahoka magic = le32toh(ebhdr->ec_hdr.magic); 308288addd0Sahoka if (magic != CHFS_MAGIC_BITMASK) { 309288addd0Sahoka dbg_ebh("bad magic bitmask(exp: %x found %x)\n", 310288addd0Sahoka CHFS_MAGIC_BITMASK, magic); 311288addd0Sahoka return EBHDR_LEB_BADMAGIC; 312288addd0Sahoka } 313288addd0Sahoka 314288addd0Sahoka // check CRC_EC 315288addd0Sahoka hdr_crc = le32toh(ebhdr->ec_hdr.crc_ec); 316288addd0Sahoka crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4); 317288addd0Sahoka if (hdr_crc != crc) { 318288addd0Sahoka dbg_ebh("bad crc_ec found\n"); 319288addd0Sahoka return EBHDR_LEB_BADCRC; 320288addd0Sahoka } 321288addd0Sahoka 322288addd0Sahoka /* check if the PEB is free: magic, crc_ec and erase_cnt is good and 323288addd0Sahoka * everything else is FFF.. 324288addd0Sahoka */ 325288addd0Sahoka if (check_pattern((void *) &ebhdr->u.nor_hdr, 0xFF, 0, 326288addd0Sahoka CHFS_EB_HDR_NOR_SIZE)) { 327288addd0Sahoka dbg_ebh("free peb found\n"); 328288addd0Sahoka return EBHDR_LEB_FREE; 329288addd0Sahoka } 330288addd0Sahoka 331288addd0Sahoka // check invalidated (CRC == LID == 0) 332288addd0Sahoka if (ebhdr->u.nor_hdr.crc == 0 && ebhdr->u.nor_hdr.lid == 0) { 333288addd0Sahoka dbg_ebh("invalidated ebhdr found\n"); 334288addd0Sahoka return EBHDR_LEB_INVALIDATED; 335288addd0Sahoka } 336288addd0Sahoka 337288addd0Sahoka // check CRC 338288addd0Sahoka hdr_crc = le32toh(ebhdr->u.nor_hdr.crc); 339288addd0Sahoka lid_save = ebhdr->u.nor_hdr.lid; 340288addd0Sahoka 341288addd0Sahoka // mark lid as not dirty for crc calc 342288addd0Sahoka ebhdr->u.nor_hdr.lid = ebhdr->u.nor_hdr.lid | htole32( 343288addd0Sahoka CHFS_LID_NOT_DIRTY_BIT); 344288addd0Sahoka crc = crc32(0, (uint8_t *) &ebhdr->u.nor_hdr + 4, 345288addd0Sahoka CHFS_EB_HDR_NOR_SIZE - 4); 346288addd0Sahoka // restore the original lid value in ebh 347288addd0Sahoka ebhdr->u.nor_hdr.lid = lid_save; 348288addd0Sahoka 349288addd0Sahoka if (crc != hdr_crc) { 350288addd0Sahoka dbg_ebh("bad crc found\n"); 351288addd0Sahoka return EBHDR_LEB_BADCRC; 352288addd0Sahoka } 353288addd0Sahoka 354288addd0Sahoka // check dirty 355288addd0Sahoka if (!(le32toh(lid_save) & CHFS_LID_NOT_DIRTY_BIT)) { 356288addd0Sahoka dbg_ebh("dirty ebhdr found\n"); 357288addd0Sahoka return EBHDR_LEB_DIRTY; 358288addd0Sahoka } 359288addd0Sahoka 360288addd0Sahoka return EBHDR_LEB_OK; 361288addd0Sahoka } 362288addd0Sahoka 363288addd0Sahoka /** 364f273a7a1Sandvar * nand_check_eb_hdr - check eraseblock header read from NAND flash 365288addd0Sahoka * 366288addd0Sahoka * @ebh: chfs eraseblock handler 367288addd0Sahoka * @buf: eraseblock header to check 368288addd0Sahoka * 369288addd0Sahoka * Returns eraseblock header status. 370288addd0Sahoka */ 371288addd0Sahoka int 372288addd0Sahoka nand_check_eb_hdr(struct chfs_ebh *ebh, void *buf) 373288addd0Sahoka { 374288addd0Sahoka uint32_t magic, crc, hdr_crc; 375288addd0Sahoka struct chfs_eb_hdr *ebhdr = buf; 376288addd0Sahoka 377288addd0Sahoka //check is there a header 378288addd0Sahoka if (check_pattern((void *) &ebhdr->ec_hdr, 379288addd0Sahoka 0xFF, 0, CHFS_EB_EC_HDR_SIZE)) { 380288addd0Sahoka dbg_ebh("no header found\n"); 381288addd0Sahoka return EBHDR_LEB_NO_HDR; 382288addd0Sahoka } 383288addd0Sahoka 384288addd0Sahoka // check magic 385288addd0Sahoka magic = le32toh(ebhdr->ec_hdr.magic); 386288addd0Sahoka if (magic != CHFS_MAGIC_BITMASK) { 387288addd0Sahoka dbg_ebh("bad magic bitmask(exp: %x found %x)\n", 388288addd0Sahoka CHFS_MAGIC_BITMASK, magic); 389288addd0Sahoka return EBHDR_LEB_BADMAGIC; 390288addd0Sahoka } 391288addd0Sahoka 392288addd0Sahoka // check CRC_EC 393288addd0Sahoka hdr_crc = le32toh(ebhdr->ec_hdr.crc_ec); 394288addd0Sahoka crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4); 395288addd0Sahoka if (hdr_crc != crc) { 396288addd0Sahoka dbg_ebh("bad crc_ec found\n"); 397288addd0Sahoka return EBHDR_LEB_BADCRC; 398288addd0Sahoka } 399288addd0Sahoka 400288addd0Sahoka /* check if the PEB is free: magic, crc_ec and erase_cnt is good and 401288addd0Sahoka * everything else is FFF.. 402288addd0Sahoka */ 403288addd0Sahoka if (check_pattern((void *) &ebhdr->u.nand_hdr, 0xFF, 0, 404288addd0Sahoka CHFS_EB_HDR_NAND_SIZE)) { 405288addd0Sahoka dbg_ebh("free peb found\n"); 406288addd0Sahoka return EBHDR_LEB_FREE; 407288addd0Sahoka } 408288addd0Sahoka 409288addd0Sahoka // check CRC 410288addd0Sahoka hdr_crc = le32toh(ebhdr->u.nand_hdr.crc); 411288addd0Sahoka 412288addd0Sahoka crc = crc32(0, (uint8_t *) &ebhdr->u.nand_hdr + 4, 413288addd0Sahoka CHFS_EB_HDR_NAND_SIZE - 4); 414288addd0Sahoka 415288addd0Sahoka if (crc != hdr_crc) { 416288addd0Sahoka dbg_ebh("bad crc found\n"); 417288addd0Sahoka return EBHDR_LEB_BADCRC; 418288addd0Sahoka } 419288addd0Sahoka 420288addd0Sahoka return EBHDR_LEB_OK; 421288addd0Sahoka } 422288addd0Sahoka 423288addd0Sahoka /** 424f273a7a1Sandvar * nor_mark_eb_hdr_dirty_flash- mark eraseblock header dirty on NOR flash 425288addd0Sahoka * 426288addd0Sahoka * @ebh: chfs eraseblock handler 427288addd0Sahoka * @pebnr: eraseblock number 428f0a7346dSsnj * @lid: leb id (its bit number 31 will be set to 0) 429288addd0Sahoka * 430288addd0Sahoka * It pulls the CHFS_LID_NOT_DIRTY_BIT to zero on flash. 431288addd0Sahoka * 432288addd0Sahoka * Returns zero in case of success, error code in case of fail. 433288addd0Sahoka */ 434288addd0Sahoka int 435288addd0Sahoka nor_mark_eb_hdr_dirty_flash(struct chfs_ebh *ebh, int pebnr, int lid) 436288addd0Sahoka { 437288addd0Sahoka int ret; 438288addd0Sahoka size_t retlen; 439288addd0Sahoka off_t ofs; 440288addd0Sahoka 441288addd0Sahoka /* mark leb id dirty */ 442288addd0Sahoka lid = htole32(lid & CHFS_LID_DIRTY_BIT_MASK); 443288addd0Sahoka 444288addd0Sahoka /* calculate position */ 445288addd0Sahoka ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE 446288addd0Sahoka + CHFS_GET_MEMBER_POS(struct chfs_nor_eb_hdr , lid); 447288addd0Sahoka 448288addd0Sahoka ret = flash_write(ebh->flash_dev, ofs, sizeof(lid), &retlen, 449288addd0Sahoka (unsigned char *) &lid); 450288addd0Sahoka if (ret || retlen != sizeof(lid)) { 451288addd0Sahoka chfs_err("can't mark peb dirty"); 452288addd0Sahoka return ret; 453288addd0Sahoka } 454288addd0Sahoka 455288addd0Sahoka return 0; 456288addd0Sahoka } 457288addd0Sahoka 458288addd0Sahoka /** 459f273a7a1Sandvar * nor_invalidate_eb_hdr - invalidate eraseblock header on NOR flash 460288addd0Sahoka * 461288addd0Sahoka * @ebh: chfs eraseblock handler 462288addd0Sahoka * @pebnr: eraseblock number 463288addd0Sahoka * 464288addd0Sahoka * Sets crc and lip field to zero. 465288addd0Sahoka * Returns zero in case of success, error code in case of fail. 466288addd0Sahoka */ 467288addd0Sahoka int 468288addd0Sahoka nor_invalidate_eb_hdr(struct chfs_ebh *ebh, int pebnr) 469288addd0Sahoka { 470288addd0Sahoka int ret; 471288addd0Sahoka size_t retlen; 472288addd0Sahoka off_t ofs; 473288addd0Sahoka char zero_buf[CHFS_INVALIDATE_SIZE]; 474288addd0Sahoka 475288addd0Sahoka /* fill with zero */ 476288addd0Sahoka memset(zero_buf, 0x0, CHFS_INVALIDATE_SIZE); 477288addd0Sahoka 478288addd0Sahoka /* calculate position (!!! lid is directly behind crc !!!) */ 479288addd0Sahoka ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE 480288addd0Sahoka + CHFS_GET_MEMBER_POS(struct chfs_nor_eb_hdr, crc); 481288addd0Sahoka 482288addd0Sahoka ret = flash_write(ebh->flash_dev, 483288addd0Sahoka ofs, CHFS_INVALIDATE_SIZE, &retlen, 484288addd0Sahoka (unsigned char *) &zero_buf); 485288addd0Sahoka if (ret || retlen != CHFS_INVALIDATE_SIZE) { 486288addd0Sahoka chfs_err("can't invalidate peb"); 487288addd0Sahoka return ret; 488288addd0Sahoka } 489288addd0Sahoka 490288addd0Sahoka return 0; 491288addd0Sahoka } 492288addd0Sahoka 493288addd0Sahoka /** 494f273a7a1Sandvar * mark_eb_hdr_free - free eraseblock header on NOR or NAND flash 495288addd0Sahoka * 496288addd0Sahoka * @ebh: chfs eraseblock handler 497288addd0Sahoka * @pebnr: eraseblock number 498288addd0Sahoka * @ec: erase counter of PEB 499288addd0Sahoka * 500288addd0Sahoka * Write out the magic and erase counter to the physical eraseblock. 501288addd0Sahoka * Returns zero in case of success, error code in case of fail. 502288addd0Sahoka */ 503288addd0Sahoka int 504288addd0Sahoka mark_eb_hdr_free(struct chfs_ebh *ebh, int pebnr, int ec) 505288addd0Sahoka { 506288addd0Sahoka int ret, crc; 507288addd0Sahoka size_t retlen; 508288addd0Sahoka off_t ofs; 509288addd0Sahoka struct chfs_eb_hdr *ebhdr; 510288addd0Sahoka ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP); 511288addd0Sahoka 512288addd0Sahoka ebhdr->ec_hdr.magic = htole32(CHFS_MAGIC_BITMASK); 513288addd0Sahoka ebhdr->ec_hdr.erase_cnt = htole32(ec); 514288addd0Sahoka crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4); 515288addd0Sahoka ebhdr->ec_hdr.crc_ec = htole32(crc); 516288addd0Sahoka 517288addd0Sahoka ofs = pebnr * ebh->flash_if->erasesize; 518288addd0Sahoka 519288addd0Sahoka KASSERT(sizeof(ebhdr->ec_hdr) == CHFS_EB_EC_HDR_SIZE); 520288addd0Sahoka 521288addd0Sahoka ret = flash_write(ebh->flash_dev, 522288addd0Sahoka ofs, CHFS_EB_EC_HDR_SIZE, &retlen, 523288addd0Sahoka (unsigned char *) &ebhdr->ec_hdr); 524288addd0Sahoka 525288addd0Sahoka if (ret || retlen != CHFS_EB_EC_HDR_SIZE) { 526288addd0Sahoka chfs_err("can't mark peb as free: %d\n", pebnr); 527288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 528288addd0Sahoka return ret; 529288addd0Sahoka } 530288addd0Sahoka 531288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 532288addd0Sahoka return 0; 533288addd0Sahoka } 534288addd0Sahoka 535288addd0Sahoka /*****************************************************************************/ 536288addd0Sahoka /* End of Flash specific operations */ 537288addd0Sahoka /*****************************************************************************/ 538288addd0Sahoka 539288addd0Sahoka /*****************************************************************************/ 540288addd0Sahoka /* Lock Tree */ 541288addd0Sahoka /*****************************************************************************/ 542288addd0Sahoka 543288addd0Sahoka int 544288addd0Sahoka ltree_entry_cmp(struct chfs_ltree_entry *le1, 545288addd0Sahoka struct chfs_ltree_entry *le2) 546288addd0Sahoka { 547288addd0Sahoka return (le1->lnr - le2->lnr); 548288addd0Sahoka } 549288addd0Sahoka 550288addd0Sahoka /* Generate functions for Lock tree's red-black tree */ 551288addd0Sahoka RB_PROTOTYPE( ltree_rbtree, chfs_ltree_entry, rb, ltree_entry_cmp); 552288addd0Sahoka RB_GENERATE( ltree_rbtree, chfs_ltree_entry, rb, ltree_entry_cmp); 553288addd0Sahoka 554288addd0Sahoka 555288addd0Sahoka /** 556288addd0Sahoka * ltree_lookup - looks up a logical eraseblock in the lock tree 557288addd0Sahoka * @ebh: chfs eraseblock handler 558288addd0Sahoka * @lid: identifier of the logical eraseblock 559288addd0Sahoka * 560288addd0Sahoka * This function returns a pointer to the wanted &struct chfs_ltree_entry 561288addd0Sahoka * if the logical eraseblock is in the lock tree, so it is locked, NULL 562288addd0Sahoka * otherwise. 563288addd0Sahoka * @ebh->ltree_lock has to be locked! 564288addd0Sahoka */ 565288addd0Sahoka static struct chfs_ltree_entry * 566288addd0Sahoka ltree_lookup(struct chfs_ebh *ebh, int lnr) 567288addd0Sahoka { 568288addd0Sahoka struct chfs_ltree_entry le, *result; 569288addd0Sahoka le.lnr = lnr; 570288addd0Sahoka result = RB_FIND(ltree_rbtree, &ebh->ltree, &le); 571288addd0Sahoka return result; 572288addd0Sahoka } 573288addd0Sahoka 574288addd0Sahoka /** 575288addd0Sahoka * ltree_add_entry - add an entry to the lock tree 576288addd0Sahoka * @ebh: chfs eraseblock handler 577288addd0Sahoka * @lnr: identifier of the logical eraseblock 578288addd0Sahoka * 579288addd0Sahoka * This function adds a new logical eraseblock entry identified with @lnr to the 580288addd0Sahoka * lock tree. If the entry is already in the tree, it increases the user 581288addd0Sahoka * counter. 582288addd0Sahoka * Returns NULL if can not allocate memory for lock tree entry, or a pointer 583288addd0Sahoka * to the inserted entry otherwise. 584288addd0Sahoka */ 585288addd0Sahoka static struct chfs_ltree_entry * 586288addd0Sahoka ltree_add_entry(struct chfs_ebh *ebh, int lnr) 587288addd0Sahoka { 588288addd0Sahoka struct chfs_ltree_entry *le, *result; 589288addd0Sahoka 590288addd0Sahoka le = kmem_alloc(sizeof(struct chfs_ltree_entry), KM_SLEEP); 591288addd0Sahoka 592288addd0Sahoka le->lnr = lnr; 593288addd0Sahoka le->users = 1; 594288addd0Sahoka rw_init(&le->mutex); 595288addd0Sahoka 596288addd0Sahoka //dbg_ebh("enter ltree lock\n"); 597288addd0Sahoka mutex_enter(&ebh->ltree_lock); 598288addd0Sahoka //dbg_ebh("insert\n"); 599288addd0Sahoka result = RB_INSERT(ltree_rbtree, &ebh->ltree, le); 600288addd0Sahoka //dbg_ebh("inserted\n"); 601288addd0Sahoka if (result) { 602288addd0Sahoka //The entry is already in the tree 603288addd0Sahoka result->users++; 604288addd0Sahoka kmem_free(le, sizeof(struct chfs_ltree_entry)); 605288addd0Sahoka } 606288addd0Sahoka else { 607288addd0Sahoka result = le; 608288addd0Sahoka } 609288addd0Sahoka mutex_exit(&ebh->ltree_lock); 610288addd0Sahoka 611288addd0Sahoka return result; 612288addd0Sahoka } 613288addd0Sahoka 614288addd0Sahoka /** 615288addd0Sahoka * leb_read_lock - lock a logical eraseblock for read 616288addd0Sahoka * @ebh: chfs eraseblock handler 617288addd0Sahoka * @lnr: identifier of the logical eraseblock 618288addd0Sahoka * 619288addd0Sahoka * Returns zero in case of success, error code in case of fail. 620288addd0Sahoka */ 621288addd0Sahoka static int 622288addd0Sahoka leb_read_lock(struct chfs_ebh *ebh, int lnr) 623288addd0Sahoka { 624288addd0Sahoka struct chfs_ltree_entry *le; 625288addd0Sahoka 626288addd0Sahoka le = ltree_add_entry(ebh, lnr); 627288addd0Sahoka if (!le) 628288addd0Sahoka return ENOMEM; 629288addd0Sahoka 630288addd0Sahoka rw_enter(&le->mutex, RW_READER); 631288addd0Sahoka return 0; 632288addd0Sahoka } 633288addd0Sahoka 634288addd0Sahoka /** 635288addd0Sahoka * leb_read_unlock - unlock a logical eraseblock from read 636288addd0Sahoka * @ebh: chfs eraseblock handler 637288addd0Sahoka * @lnr: identifier of the logical eraseblock 638288addd0Sahoka * 639288addd0Sahoka * This function unlocks a logical eraseblock from read and delete it from the 640288addd0Sahoka * lock tree is there are no more users of it. 641288addd0Sahoka */ 642288addd0Sahoka static void 643288addd0Sahoka leb_read_unlock(struct chfs_ebh *ebh, int lnr) 644288addd0Sahoka { 645288addd0Sahoka struct chfs_ltree_entry *le; 646288addd0Sahoka 647288addd0Sahoka mutex_enter(&ebh->ltree_lock); 648288addd0Sahoka //dbg_ebh("LOCK: ebh->ltree_lock spin locked in leb_read_unlock()\n"); 649288addd0Sahoka le = ltree_lookup(ebh, lnr); 650288addd0Sahoka if (!le) 651288addd0Sahoka goto out; 652288addd0Sahoka 653288addd0Sahoka le->users -= 1; 654288addd0Sahoka KASSERT(le->users >= 0); 655288addd0Sahoka rw_exit(&le->mutex); 656288addd0Sahoka if (le->users == 0) { 657288addd0Sahoka le = RB_REMOVE(ltree_rbtree, &ebh->ltree, le); 658288addd0Sahoka if (le) { 659288addd0Sahoka rw_destroy(&le->mutex); 660288addd0Sahoka 661288addd0Sahoka kmem_free(le, sizeof(struct chfs_ltree_entry)); 662288addd0Sahoka } 663288addd0Sahoka } 664288addd0Sahoka 665288addd0Sahoka out: 666288addd0Sahoka mutex_exit(&ebh->ltree_lock); 667288addd0Sahoka //dbg_ebh("UNLOCK: ebh->ltree_lock spin unlocked in leb_read_unlock()\n"); 668288addd0Sahoka } 669288addd0Sahoka 670288addd0Sahoka /** 671288addd0Sahoka * leb_write_lock - lock a logical eraseblock for write 672288addd0Sahoka * @ebh: chfs eraseblock handler 673288addd0Sahoka * @lnr: identifier of the logical eraseblock 674288addd0Sahoka * 675288addd0Sahoka * Returns zero in case of success, error code in case of fail. 676288addd0Sahoka */ 677288addd0Sahoka static int 678288addd0Sahoka leb_write_lock(struct chfs_ebh *ebh, int lnr) 679288addd0Sahoka { 680288addd0Sahoka struct chfs_ltree_entry *le; 681288addd0Sahoka 682288addd0Sahoka le = ltree_add_entry(ebh, lnr); 683288addd0Sahoka if (!le) 684288addd0Sahoka return ENOMEM; 685288addd0Sahoka 686288addd0Sahoka rw_enter(&le->mutex, RW_WRITER); 687288addd0Sahoka return 0; 688288addd0Sahoka } 689288addd0Sahoka 690288addd0Sahoka /** 691288addd0Sahoka * leb_write_unlock - unlock a logical eraseblock from write 692288addd0Sahoka * @ebh: chfs eraseblock handler 693288addd0Sahoka * @lnr: identifier of the logical eraseblock 694288addd0Sahoka * 695288addd0Sahoka * This function unlocks a logical eraseblock from write and delete it from the 696288addd0Sahoka * lock tree is there are no more users of it. 697288addd0Sahoka */ 698288addd0Sahoka static void 699288addd0Sahoka leb_write_unlock(struct chfs_ebh *ebh, int lnr) 700288addd0Sahoka { 701288addd0Sahoka struct chfs_ltree_entry *le; 702288addd0Sahoka 703288addd0Sahoka mutex_enter(&ebh->ltree_lock); 704288addd0Sahoka //dbg_ebh("LOCK: ebh->ltree_lock spin locked in leb_write_unlock()\n"); 705288addd0Sahoka le = ltree_lookup(ebh, lnr); 706288addd0Sahoka if (!le) 707288addd0Sahoka goto out; 708288addd0Sahoka 709288addd0Sahoka le->users -= 1; 710288addd0Sahoka KASSERT(le->users >= 0); 711288addd0Sahoka rw_exit(&le->mutex); 712288addd0Sahoka if (le->users == 0) { 713288addd0Sahoka RB_REMOVE(ltree_rbtree, &ebh->ltree, le); 714288addd0Sahoka 715288addd0Sahoka rw_destroy(&le->mutex); 716288addd0Sahoka 717288addd0Sahoka kmem_free(le, sizeof(struct chfs_ltree_entry)); 718288addd0Sahoka } 719288addd0Sahoka 720288addd0Sahoka out: 721288addd0Sahoka mutex_exit(&ebh->ltree_lock); 722288addd0Sahoka //dbg_ebh("UNLOCK: ebh->ltree_lock spin unlocked in leb_write_unlock()\n"); 723288addd0Sahoka } 724288addd0Sahoka 725288addd0Sahoka /*****************************************************************************/ 726288addd0Sahoka /* End of Lock Tree */ 727288addd0Sahoka /*****************************************************************************/ 728288addd0Sahoka 729288addd0Sahoka /*****************************************************************************/ 730288addd0Sahoka /* Erase related operations */ 731288addd0Sahoka /*****************************************************************************/ 732288addd0Sahoka 733288addd0Sahoka /** 734288addd0Sahoka * If the first argument is smaller than the second, the function 735288addd0Sahoka * returns a value smaller than zero. If they are equal, the function re- 736288addd0Sahoka * turns zero. Otherwise, it should return a value greater than zero. 737288addd0Sahoka */ 738288addd0Sahoka int 739288addd0Sahoka peb_in_use_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2) 740288addd0Sahoka { 741288addd0Sahoka return (peb1->pebnr - peb2->pebnr); 742288addd0Sahoka } 743288addd0Sahoka 744288addd0Sahoka int 745288addd0Sahoka peb_free_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2) 746288addd0Sahoka { 747288addd0Sahoka int comp; 748288addd0Sahoka 749288addd0Sahoka comp = peb1->erase_cnt - peb2->erase_cnt; 750288addd0Sahoka if (0 == comp) 751288addd0Sahoka comp = peb1->pebnr - peb2->pebnr; 752288addd0Sahoka 753288addd0Sahoka return comp; 754288addd0Sahoka } 755288addd0Sahoka 756288addd0Sahoka /* Generate functions for in use PEB's red-black tree */ 757288addd0Sahoka RB_PROTOTYPE(peb_in_use_rbtree, chfs_peb, u.rb, peb_in_use_cmp); 758288addd0Sahoka RB_GENERATE(peb_in_use_rbtree, chfs_peb, u.rb, peb_in_use_cmp); 759288addd0Sahoka RB_PROTOTYPE(peb_free_rbtree, chfs_peb, u.rb, peb_free_cmp); 760288addd0Sahoka RB_GENERATE(peb_free_rbtree, chfs_peb, u.rb, peb_free_cmp); 761288addd0Sahoka 762288addd0Sahoka /** 763288addd0Sahoka * add_peb_to_erase_queue: adds a PEB to to_erase/fully_erased queue 764288addd0Sahoka * @ebh - chfs eraseblock handler 765288addd0Sahoka * @pebnr - physical eraseblock's number 766288addd0Sahoka * @ec - erase counter of PEB 767288addd0Sahoka * @queue: the queue to add to 768288addd0Sahoka * 769288addd0Sahoka * This function adds a PEB to the erase queue specified by @queue. 770288addd0Sahoka * The @ebh->erase_lock must be locked before using this. 771288addd0Sahoka * Returns zero in case of success, error code in case of fail. 772288addd0Sahoka */ 773288addd0Sahoka int 774288addd0Sahoka add_peb_to_erase_queue(struct chfs_ebh *ebh, int pebnr, int ec, 775288addd0Sahoka struct peb_queue *queue) 776288addd0Sahoka { 777288addd0Sahoka struct chfs_peb *peb; 778288addd0Sahoka 779288addd0Sahoka peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP); 780288addd0Sahoka 781288addd0Sahoka peb->erase_cnt = ec; 782288addd0Sahoka peb->pebnr = pebnr; 783288addd0Sahoka 784288addd0Sahoka TAILQ_INSERT_TAIL(queue, peb, u.queue); 785288addd0Sahoka 786288addd0Sahoka return 0; 787288addd0Sahoka 788288addd0Sahoka } 789288addd0Sahoka //TODO 790288addd0Sahoka /** 791288addd0Sahoka * find_peb_in_use - looks up a PEB in the RB-tree of used blocks 792288addd0Sahoka * @ebh - chfs eraseblock handler 793288addd0Sahoka * 794288addd0Sahoka * This function returns a pointer to the PEB found in the tree, 795288addd0Sahoka * NULL otherwise. 796288addd0Sahoka * The @ebh->erase_lock must be locked before using this. 797288addd0Sahoka */ 798288addd0Sahoka struct chfs_peb * 799288addd0Sahoka find_peb_in_use(struct chfs_ebh *ebh, int pebnr) 800288addd0Sahoka { 801288addd0Sahoka struct chfs_peb peb, *result; 802288addd0Sahoka peb.pebnr = pebnr; 803288addd0Sahoka result = RB_FIND(peb_in_use_rbtree, &ebh->in_use, &peb); 804288addd0Sahoka return result; 805288addd0Sahoka } 806288addd0Sahoka 807288addd0Sahoka /** 808288addd0Sahoka * add_peb_to_free - adds a PEB to the RB-tree of free PEBs 809288addd0Sahoka * @ebh - chfs eraseblock handler 810288addd0Sahoka * @pebnr - physical eraseblock's number 811288addd0Sahoka * @ec - erase counter of PEB 812288addd0Sahoka * 813288addd0Sahoka * 814288addd0Sahoka * This function adds a physical eraseblock to the RB-tree of free PEBs 815288addd0Sahoka * stored in the @ebh. The key is the erase counter and pebnr. 816288addd0Sahoka * The @ebh->erase_lock must be locked before using this. 817288addd0Sahoka * Returns zero in case of success, error code in case of fail. 818288addd0Sahoka */ 819288addd0Sahoka int 820288addd0Sahoka add_peb_to_free(struct chfs_ebh *ebh, int pebnr, int ec) 821288addd0Sahoka { 822288addd0Sahoka struct chfs_peb *peb, *result; 823288addd0Sahoka 824288addd0Sahoka peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP); 825288addd0Sahoka 826288addd0Sahoka peb->erase_cnt = ec; 827288addd0Sahoka peb->pebnr = pebnr; 828288addd0Sahoka result = RB_INSERT(peb_free_rbtree, &ebh->free, peb); 8297fcec1e8She if (result) { 8307fcec1e8She kmem_free(peb, sizeof(struct chfs_peb)); 831288addd0Sahoka return 1; 8327fcec1e8She } 833288addd0Sahoka 834288addd0Sahoka return 0; 835288addd0Sahoka } 836288addd0Sahoka 837288addd0Sahoka /** 838288addd0Sahoka * add_peb_to_in_use - adds a PEB to the RB-tree of used PEBs 839288addd0Sahoka * @ebh - chfs eraseblock handler 840288addd0Sahoka * @pebnr - physical eraseblock's number 841288addd0Sahoka * @ec - erase counter of PEB 842288addd0Sahoka * 843288addd0Sahoka * 844288addd0Sahoka * This function adds a physical eraseblock to the RB-tree of used PEBs 845288addd0Sahoka * stored in the @ebh. The key is pebnr. 846288addd0Sahoka * The @ebh->erase_lock must be locked before using this. 847288addd0Sahoka * Returns zero in case of success, error code in case of fail. 848288addd0Sahoka */ 849288addd0Sahoka int 850288addd0Sahoka add_peb_to_in_use(struct chfs_ebh *ebh, int pebnr, int ec) 851288addd0Sahoka { 852288addd0Sahoka struct chfs_peb *peb, *result; 853288addd0Sahoka 854288addd0Sahoka peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP); 855288addd0Sahoka 856288addd0Sahoka peb->erase_cnt = ec; 857288addd0Sahoka peb->pebnr = pebnr; 858288addd0Sahoka result = RB_INSERT(peb_in_use_rbtree, &ebh->in_use, peb); 8597fcec1e8She if (result) { 8607fcec1e8She kmem_free(peb, sizeof(struct chfs_peb)); 861288addd0Sahoka return 1; 8627fcec1e8She } 863288addd0Sahoka 864288addd0Sahoka return 0; 865288addd0Sahoka } 866288addd0Sahoka 867288addd0Sahoka /** 868288addd0Sahoka * erase_callback - callback function for flash erase 869288addd0Sahoka * @ei: erase information 870288addd0Sahoka */ 871288addd0Sahoka void 872288addd0Sahoka erase_callback(struct flash_erase_instruction *ei) 873288addd0Sahoka { 874288addd0Sahoka int err; 875288addd0Sahoka struct chfs_erase_info_priv *priv = (void *) ei->ei_priv; 876288addd0Sahoka //dbg_ebh("ERASE_CALLBACK() CALLED\n"); 877288addd0Sahoka struct chfs_ebh *ebh = priv->ebh; 878288addd0Sahoka struct chfs_peb *peb = priv->peb; 879288addd0Sahoka 880288addd0Sahoka peb->erase_cnt += 1; 881288addd0Sahoka 882288addd0Sahoka if (ei->ei_state == FLASH_ERASE_DONE) { 883288addd0Sahoka 884288addd0Sahoka /* Write out erase counter */ 885288addd0Sahoka err = ebh->ops->mark_eb_hdr_free(ebh, 886288addd0Sahoka peb->pebnr, peb->erase_cnt); 887288addd0Sahoka if (err) { 888288addd0Sahoka /* cannot mark PEB as free,so erase it again */ 889288addd0Sahoka chfs_err( 890288addd0Sahoka "cannot mark eraseblock as free, PEB: %d\n", 891288addd0Sahoka peb->pebnr); 892288addd0Sahoka mutex_enter(&ebh->erase_lock); 893288addd0Sahoka /*dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_callback() " 894288addd0Sahoka "after mark ebhdr free\n");*/ 895288addd0Sahoka add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt, 896288addd0Sahoka &ebh->to_erase); 897288addd0Sahoka mutex_exit(&ebh->erase_lock); 898288addd0Sahoka /*dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_callback() " 899288addd0Sahoka "after mark ebhdr free\n");*/ 900288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 901288addd0Sahoka return; 902288addd0Sahoka } 903288addd0Sahoka 904288addd0Sahoka mutex_enter(&ebh->erase_lock); 905288addd0Sahoka /*dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_callback()\n");*/ 906288addd0Sahoka err = add_peb_to_free(ebh, peb->pebnr, peb->erase_cnt); 907288addd0Sahoka mutex_exit(&ebh->erase_lock); 908288addd0Sahoka /*dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_callback()\n");*/ 909288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 910288addd0Sahoka } else { 911288addd0Sahoka /* 912288addd0Sahoka * Erase is finished, but there was a problem, 913288addd0Sahoka * so erase PEB again 914288addd0Sahoka */ 915288addd0Sahoka chfs_err("erase failed, state is: 0x%x\n", ei->ei_state); 916288addd0Sahoka add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt, &ebh->to_erase); 917288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 918288addd0Sahoka } 919288addd0Sahoka } 920288addd0Sahoka 921288addd0Sahoka /** 922288addd0Sahoka * free_peb: free a PEB 923288addd0Sahoka * @ebh: chfs eraseblock handler 924288addd0Sahoka * 925288addd0Sahoka * This function erases the first physical eraseblock from one of the erase 926288addd0Sahoka * lists and adds to the RB-tree of free PEBs. 9273b26fa5cSandvar * Returns zero in case of success, error code in case of fail. 928288addd0Sahoka */ 929288addd0Sahoka int 930288addd0Sahoka free_peb(struct chfs_ebh *ebh) 931288addd0Sahoka { 932288addd0Sahoka int err, retries = 0; 933288addd0Sahoka off_t ofs; 934288addd0Sahoka struct chfs_peb *peb = NULL; 935288addd0Sahoka struct flash_erase_instruction *ei; 936288addd0Sahoka 937288addd0Sahoka KASSERT(mutex_owned(&ebh->erase_lock)); 938288addd0Sahoka 939288addd0Sahoka if (!TAILQ_EMPTY(&ebh->fully_erased)) { 940288addd0Sahoka //dbg_ebh("[FREE PEB] got a fully erased block\n"); 941288addd0Sahoka peb = TAILQ_FIRST(&ebh->fully_erased); 942288addd0Sahoka TAILQ_REMOVE(&ebh->fully_erased, peb, u.queue); 943288addd0Sahoka err = ebh->ops->mark_eb_hdr_free(ebh, 944288addd0Sahoka peb->pebnr, peb->erase_cnt); 945288addd0Sahoka if (err) { 946288addd0Sahoka goto out_free; 947288addd0Sahoka } 948288addd0Sahoka err = add_peb_to_free(ebh, peb->pebnr, peb->erase_cnt); 949288addd0Sahoka goto out_free; 950288addd0Sahoka } 951288addd0Sahoka /* Erase PEB */ 952*832e988bSandvar //dbg_ebh("[FREE PEB] erasing a block\n"); 953288addd0Sahoka peb = TAILQ_FIRST(&ebh->to_erase); 954288addd0Sahoka TAILQ_REMOVE(&ebh->to_erase, peb, u.queue); 955288addd0Sahoka mutex_exit(&ebh->erase_lock); 956288addd0Sahoka //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in free_peb()\n"); 957288addd0Sahoka ofs = peb->pebnr * ebh->flash_if->erasesize; 958288addd0Sahoka 959288addd0Sahoka /* XXX where do we free this? */ 960288addd0Sahoka ei = kmem_alloc(sizeof(struct flash_erase_instruction) 961288addd0Sahoka + sizeof(struct chfs_erase_info_priv), KM_SLEEP); 962288addd0Sahoka retry: 963288addd0Sahoka memset(ei, 0, sizeof(*ei)); 964288addd0Sahoka 965288addd0Sahoka // ei->ei_if = ebh->flash_if; 966288addd0Sahoka ei->ei_addr = ofs; 967288addd0Sahoka ei->ei_len = ebh->flash_if->erasesize; 968288addd0Sahoka ei->ei_callback = erase_callback; 969288addd0Sahoka ei->ei_priv = (unsigned long) (&ei[1]); 970288addd0Sahoka 971288addd0Sahoka ((struct chfs_erase_info_priv *) ei->ei_priv)->ebh = ebh; 972288addd0Sahoka ((struct chfs_erase_info_priv *) ei->ei_priv)->peb = peb; 973288addd0Sahoka 974288addd0Sahoka err = flash_erase(ebh->flash_dev, ei); 975288addd0Sahoka dbg_ebh("erased peb: %d\n", peb->pebnr); 976288addd0Sahoka 977288addd0Sahoka /* einval would mean we did something wrong */ 978288addd0Sahoka KASSERT(err != EINVAL); 979288addd0Sahoka 980288addd0Sahoka if (err) { 981288addd0Sahoka dbg_ebh("errno: %d, ei->ei_state: %d\n", err, ei->ei_state); 982288addd0Sahoka if (CHFS_MAX_GET_PEB_RETRIES < ++retries && 983288addd0Sahoka ei->ei_state == FLASH_ERASE_FAILED) { 984288addd0Sahoka /* The block went bad mark it */ 985288addd0Sahoka dbg_ebh("ebh markbad! 0x%jx\n", (uintmax_t )ofs); 986288addd0Sahoka err = flash_block_markbad(ebh->flash_dev, ofs); 987288addd0Sahoka if (!err) { 988288addd0Sahoka ebh->peb_nr--; 989288addd0Sahoka } 990288addd0Sahoka 991288addd0Sahoka goto out; 992288addd0Sahoka } 993288addd0Sahoka chfs_err("can not erase PEB: %d, try again\n", peb->pebnr); 994288addd0Sahoka goto retry; 995288addd0Sahoka } 996288addd0Sahoka 997288addd0Sahoka out: 998288addd0Sahoka /* lock the erase_lock, because it was locked 999288addd0Sahoka * when the function was called */ 1000288addd0Sahoka mutex_enter(&ebh->erase_lock); 1001288addd0Sahoka return err; 1002288addd0Sahoka 1003288addd0Sahoka out_free: 1004288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 1005288addd0Sahoka return err; 1006288addd0Sahoka } 1007288addd0Sahoka 1008288addd0Sahoka /** 1009288addd0Sahoka * release_peb - schedule an erase for the PEB 1010288addd0Sahoka * @ebh: chfs eraseblock handler 1011288addd0Sahoka * @pebnr: physical eraseblock number 1012288addd0Sahoka * 1013288addd0Sahoka * This function get the peb identified by @pebnr from the in_use RB-tree of 1014288addd0Sahoka * @ebh, removes it and schedule an erase for it. 1015288addd0Sahoka * 1016288addd0Sahoka * Returns zero on success, error code in case of fail. 1017288addd0Sahoka */ 1018288addd0Sahoka int 1019288addd0Sahoka release_peb(struct chfs_ebh *ebh, int pebnr) 1020288addd0Sahoka { 1021288addd0Sahoka int err = 0; 1022288addd0Sahoka struct chfs_peb *peb; 1023288addd0Sahoka 1024288addd0Sahoka mutex_enter(&ebh->erase_lock); 1025288addd0Sahoka 1026288addd0Sahoka //dbg_ebh("LOCK: ebh->erase_lock spin locked in release_peb()\n"); 1027288addd0Sahoka peb = find_peb_in_use(ebh, pebnr); 1028288addd0Sahoka if (!peb) { 1029288addd0Sahoka chfs_err("LEB is mapped, but is not in the 'in_use' " 1030288addd0Sahoka "tree of ebh\n"); 1031288addd0Sahoka goto out_unlock; 1032288addd0Sahoka } 1033288addd0Sahoka err = add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt, 1034288addd0Sahoka &ebh->to_erase); 1035288addd0Sahoka 1036288addd0Sahoka if (err) 1037288addd0Sahoka goto out_unlock; 1038288addd0Sahoka 1039288addd0Sahoka RB_REMOVE(peb_in_use_rbtree, &ebh->in_use, peb); 1040288addd0Sahoka out_unlock: 1041288addd0Sahoka mutex_exit(&ebh->erase_lock); 1042288addd0Sahoka //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in release_peb()" 1043288addd0Sahoka // " at out_unlock\n"); 1044288addd0Sahoka return err; 1045288addd0Sahoka } 1046288addd0Sahoka 1047288addd0Sahoka /** 1048288addd0Sahoka * erase_thread - background thread for erasing PEBs 1049288addd0Sahoka * @data: pointer to the eraseblock handler 1050288addd0Sahoka */ 1051288addd0Sahoka /*void 1052288addd0Sahoka erase_thread(void *data) 1053288addd0Sahoka { 1054288addd0Sahoka struct chfs_ebh *ebh = data; 1055288addd0Sahoka 1056288addd0Sahoka dbg_ebh("erase thread started\n"); 1057288addd0Sahoka while (ebh->bg_erase.eth_running) { 1058288addd0Sahoka int err; 1059288addd0Sahoka 1060288addd0Sahoka mutex_enter(&ebh->erase_lock); 1061288addd0Sahoka dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_thread()\n"); 1062288addd0Sahoka if (TAILQ_EMPTY(&ebh->to_erase) && TAILQ_EMPTY(&ebh->fully_erased)) { 1063288addd0Sahoka dbg_ebh("thread has nothing to do\n"); 1064288addd0Sahoka mutex_exit(&ebh->erase_lock); 1065288addd0Sahoka mutex_enter(&ebh->bg_erase.eth_thread_mtx); 1066288addd0Sahoka cv_timedwait_sig(&ebh->bg_erase.eth_wakeup, 1067288addd0Sahoka &ebh->bg_erase.eth_thread_mtx, mstohz(100)); 1068288addd0Sahoka mutex_exit(&ebh->bg_erase.eth_thread_mtx); 1069288addd0Sahoka 1070288addd0Sahoka dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_thread()\n"); 1071288addd0Sahoka continue; 1072288addd0Sahoka } 1073288addd0Sahoka mutex_exit(&ebh->erase_lock); 1074288addd0Sahoka dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_thread()\n"); 1075288addd0Sahoka 1076288addd0Sahoka err = free_peb(ebh); 1077288addd0Sahoka if (err) 1078288addd0Sahoka chfs_err("freeing PEB failed in the background thread: %d\n", err); 1079288addd0Sahoka 1080288addd0Sahoka } 1081288addd0Sahoka dbg_ebh("erase thread stopped\n"); 1082288addd0Sahoka kthread_exit(0); 1083288addd0Sahoka }*/ 1084288addd0Sahoka 1085288addd0Sahoka /** 1086288addd0Sahoka * erase_thread - background thread for erasing PEBs 1087288addd0Sahoka * @data: pointer to the eraseblock handler 1088288addd0Sahoka */ 1089288addd0Sahoka void 1090288addd0Sahoka erase_thread(void *data) { 1091288addd0Sahoka dbg_ebh("[EBH THREAD] erase thread started\n"); 1092288addd0Sahoka 1093288addd0Sahoka struct chfs_ebh *ebh = data; 1094288addd0Sahoka int err; 1095288addd0Sahoka 1096288addd0Sahoka mutex_enter(&ebh->erase_lock); 1097288addd0Sahoka while (ebh->bg_erase.eth_running) { 1098288addd0Sahoka if (TAILQ_EMPTY(&ebh->to_erase) && 1099288addd0Sahoka TAILQ_EMPTY(&ebh->fully_erased)) { 1100288addd0Sahoka cv_timedwait_sig(&ebh->bg_erase.eth_wakeup, 1101288addd0Sahoka &ebh->erase_lock, mstohz(100)); 1102288addd0Sahoka } else { 1103288addd0Sahoka /* XXX exiting this mutex is a bit odd here as 1104288addd0Sahoka * free_peb instantly reenters it... 1105288addd0Sahoka */ 1106288addd0Sahoka err = free_peb(ebh); 1107288addd0Sahoka mutex_exit(&ebh->erase_lock); 1108288addd0Sahoka if (err) { 1109288addd0Sahoka chfs_err("freeing PEB failed in the" 1110288addd0Sahoka " background thread: %d\n", err); 1111288addd0Sahoka } 1112288addd0Sahoka mutex_enter(&ebh->erase_lock); 1113288addd0Sahoka } 1114288addd0Sahoka } 1115288addd0Sahoka mutex_exit(&ebh->erase_lock); 1116288addd0Sahoka 1117288addd0Sahoka dbg_ebh("[EBH THREAD] erase thread stopped\n"); 1118288addd0Sahoka kthread_exit(0); 1119288addd0Sahoka } 1120288addd0Sahoka 1121288addd0Sahoka /** 1122288addd0Sahoka * erase_thread_start - init and start erase thread 1123288addd0Sahoka * @ebh: eraseblock handler 1124288addd0Sahoka */ 1125288addd0Sahoka static void 1126288addd0Sahoka erase_thread_start(struct chfs_ebh *ebh) 1127288addd0Sahoka { 1128288addd0Sahoka cv_init(&ebh->bg_erase.eth_wakeup, "ebheracv"); 1129288addd0Sahoka 1130288addd0Sahoka ebh->bg_erase.eth_running = true; 1131288addd0Sahoka kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL, 1132288addd0Sahoka erase_thread, ebh, &ebh->bg_erase.eth_thread, "ebherase"); 1133288addd0Sahoka } 1134288addd0Sahoka 1135288addd0Sahoka /** 1136288addd0Sahoka * erase_thread_stop - stop background erase thread 1137288addd0Sahoka * @ebh: eraseblock handler 1138288addd0Sahoka */ 1139288addd0Sahoka static void 1140288addd0Sahoka erase_thread_stop(struct chfs_ebh *ebh) 1141288addd0Sahoka { 1142288addd0Sahoka ebh->bg_erase.eth_running = false; 1143288addd0Sahoka cv_signal(&ebh->bg_erase.eth_wakeup); 1144288addd0Sahoka dbg_ebh("[EBH THREAD STOP] signaled\n"); 1145288addd0Sahoka 1146288addd0Sahoka kthread_join(ebh->bg_erase.eth_thread); 1147288addd0Sahoka #ifdef BROKEN_KTH_JOIN 1148288addd0Sahoka kpause("chfsebhjointh", false, mstohz(1000), NULL); 1149288addd0Sahoka #endif 1150288addd0Sahoka 1151288addd0Sahoka cv_destroy(&ebh->bg_erase.eth_wakeup); 1152288addd0Sahoka } 1153288addd0Sahoka 1154288addd0Sahoka /*****************************************************************************/ 1155288addd0Sahoka /* End of Erase related operations */ 1156288addd0Sahoka /*****************************************************************************/ 1157288addd0Sahoka 1158288addd0Sahoka /*****************************************************************************/ 1159288addd0Sahoka /* Scan related operations */ 1160288addd0Sahoka /*****************************************************************************/ 1161288addd0Sahoka int 1162288addd0Sahoka scan_leb_used_cmp(struct chfs_scan_leb *sleb1, struct chfs_scan_leb *sleb2) 1163288addd0Sahoka { 1164288addd0Sahoka return (sleb1->lnr - sleb2->lnr); 1165288addd0Sahoka } 1166288addd0Sahoka 1167288addd0Sahoka RB_PROTOTYPE(scan_leb_used_rbtree, chfs_scan_leb, u.rb, scan_leb_used_cmp); 1168288addd0Sahoka RB_GENERATE(scan_leb_used_rbtree, chfs_scan_leb, u.rb, scan_leb_used_cmp); 1169288addd0Sahoka 1170288addd0Sahoka /** 1171288addd0Sahoka * scan_add_to_queue - adds a physical eraseblock to one of the 1172288addd0Sahoka * eraseblock queue 1173288addd0Sahoka * @si: chfs scanning information 1174288addd0Sahoka * @pebnr: physical eraseblock number 1175288addd0Sahoka * @erase_cnt: erase counter of the physical eraseblock 1176288addd0Sahoka * @list: the list to add to 1177288addd0Sahoka * 1178288addd0Sahoka * This function adds a physical eraseblock to one of the lists in the scanning 1179288addd0Sahoka * information. 1180288addd0Sahoka * Returns zero in case of success, negative error code in case of fail. 1181288addd0Sahoka */ 1182288addd0Sahoka static int 1183288addd0Sahoka scan_add_to_queue(struct chfs_scan_info *si, int pebnr, int erase_cnt, 1184288addd0Sahoka struct scan_leb_queue *queue) 1185288addd0Sahoka { 1186288addd0Sahoka struct chfs_scan_leb *sleb; 1187288addd0Sahoka 1188288addd0Sahoka sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP); 1189288addd0Sahoka 1190288addd0Sahoka sleb->pebnr = pebnr; 1191288addd0Sahoka sleb->erase_cnt = erase_cnt; 1192288addd0Sahoka TAILQ_INSERT_TAIL(queue, sleb, u.queue); 1193288addd0Sahoka return 0; 1194288addd0Sahoka } 1195288addd0Sahoka 1196288addd0Sahoka /* 1197288addd0Sahoka * nor_scan_add_to_used - add a physical eraseblock to the 1198288addd0Sahoka * used tree of scan info 1199288addd0Sahoka * @ebh: chfs eraseblock handler 1200288addd0Sahoka * @si: chfs scanning information 1201288addd0Sahoka * @ebhdr: eraseblock header 1202288addd0Sahoka * @pebnr: physical eraseblock number 1203288addd0Sahoka * @leb_status: the status of the PEB's eraseblock header 1204288addd0Sahoka * 1205288addd0Sahoka * This function adds a PEB to the used tree of the scanning information. 1206288addd0Sahoka * It handles the situations if there are more physical eraseblock referencing 1207288addd0Sahoka * to the same logical eraseblock. 1208288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1209288addd0Sahoka */ 1210288addd0Sahoka int 1211288addd0Sahoka nor_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si, 1212288addd0Sahoka struct chfs_eb_hdr *ebhdr, int pebnr, int leb_status) 1213288addd0Sahoka { 1214288addd0Sahoka int err, lnr, ec; 1215288addd0Sahoka struct chfs_scan_leb *sleb, *old; 1216288addd0Sahoka 1217288addd0Sahoka lnr = CHFS_GET_LID(ebhdr->u.nor_hdr.lid); 1218288addd0Sahoka ec = le32toh(ebhdr->ec_hdr.erase_cnt); 1219288addd0Sahoka 1220288addd0Sahoka sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP); 1221288addd0Sahoka 1222288addd0Sahoka sleb->erase_cnt = ec; 1223288addd0Sahoka sleb->lnr = lnr; 1224288addd0Sahoka sleb->pebnr = pebnr; 1225288addd0Sahoka sleb->info = leb_status; 1226288addd0Sahoka 1227288addd0Sahoka old = RB_INSERT(scan_leb_used_rbtree, &si->used, sleb); 1228288addd0Sahoka if (old) { 1229288addd0Sahoka kmem_free(sleb, sizeof(struct chfs_scan_leb)); 1230288addd0Sahoka /* There is already an eraseblock in the used tree */ 1231288addd0Sahoka /* If the new one is bad */ 1232288addd0Sahoka if (EBHDR_LEB_DIRTY == leb_status && 1233288addd0Sahoka EBHDR_LEB_OK == old->info) { 1234288addd0Sahoka return scan_add_to_queue(si, pebnr, ec, &si->erase); 1235288addd0Sahoka } else { 1236288addd0Sahoka err = scan_add_to_queue(si, old->pebnr, 1237288addd0Sahoka old->erase_cnt, &si->erase); 1238288addd0Sahoka if (err) { 1239288addd0Sahoka return err; 1240288addd0Sahoka } 1241288addd0Sahoka 1242288addd0Sahoka old->erase_cnt = ec; 1243288addd0Sahoka old->lnr = lnr; 1244288addd0Sahoka old->pebnr = pebnr; 1245288addd0Sahoka old->info = leb_status; 1246288addd0Sahoka return 0; 1247288addd0Sahoka } 1248288addd0Sahoka } 1249288addd0Sahoka return 0; 1250288addd0Sahoka } 1251288addd0Sahoka 1252288addd0Sahoka /** 1253288addd0Sahoka * nor_process eb -read the headers from NOR flash, check them and add to 1254288addd0Sahoka * the scanning information 1255288addd0Sahoka * @ebh: chfs eraseblock handler 1256288addd0Sahoka * @si: chfs scanning information 1257288addd0Sahoka * @pebnr: physical eraseblock number 1258288addd0Sahoka * 1259288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1260288addd0Sahoka */ 1261288addd0Sahoka int 1262288addd0Sahoka nor_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si, 1263288addd0Sahoka int pebnr, struct chfs_eb_hdr *ebhdr) 1264288addd0Sahoka { 1265288addd0Sahoka int err, erase_cnt, leb_status; 1266288addd0Sahoka 1267288addd0Sahoka err = ebh->ops->read_eb_hdr(ebh, pebnr, ebhdr); 1268288addd0Sahoka if (err) 1269288addd0Sahoka return err; 1270288addd0Sahoka 1271288addd0Sahoka erase_cnt = le32toh(ebhdr->ec_hdr.erase_cnt); 1272288addd0Sahoka dbg_ebh("erase_cnt: %d\n", erase_cnt); 1273288addd0Sahoka leb_status = ebh->ops->check_eb_hdr(ebh, ebhdr); 1274288addd0Sahoka if (EBHDR_LEB_BADMAGIC == leb_status || 1275288addd0Sahoka EBHDR_LEB_BADCRC == leb_status) { 1276288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->corrupted); 1277288addd0Sahoka return err; 1278288addd0Sahoka } 1279288addd0Sahoka else if (EBHDR_LEB_FREE == leb_status) { 1280288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->free); 1281288addd0Sahoka goto count_mean; 1282288addd0Sahoka } 1283288addd0Sahoka else if (EBHDR_LEB_NO_HDR == leb_status) { 1284288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erased); 1285288addd0Sahoka return err; 1286288addd0Sahoka } 1287288addd0Sahoka else if (EBHDR_LEB_INVALIDATED == leb_status) { 1288288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erase); 1289288addd0Sahoka return err; 1290288addd0Sahoka } 1291288addd0Sahoka 1292288addd0Sahoka err = nor_scan_add_to_used(ebh, si, ebhdr, pebnr, leb_status); 1293288addd0Sahoka if (err) 1294288addd0Sahoka return err; 1295288addd0Sahoka 1296288addd0Sahoka 1297288addd0Sahoka count_mean: 1298288addd0Sahoka si->sum_of_ec += erase_cnt; 1299288addd0Sahoka si->num_of_eb++; 1300288addd0Sahoka 1301288addd0Sahoka return err; 1302288addd0Sahoka } 1303288addd0Sahoka 1304288addd0Sahoka /* 1305288addd0Sahoka * nand_scan_add_to_used - add a physical eraseblock to the 1306288addd0Sahoka * used tree of scan info 1307288addd0Sahoka * @ebh: chfs eraseblock handler 1308288addd0Sahoka * @si: chfs scanning information 1309288addd0Sahoka * @ebhdr: eraseblock header 1310288addd0Sahoka * @pebnr: physical eraseblock number 1311288addd0Sahoka * @leb_status: the status of the PEB's eraseblock header 1312288addd0Sahoka * 1313288addd0Sahoka * This function adds a PEB to the used tree of the scanning information. 1314288addd0Sahoka * It handles the situations if there are more physical eraseblock referencing 1315288addd0Sahoka * to the same logical eraseblock. 1316288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1317288addd0Sahoka */ 1318288addd0Sahoka int 1319288addd0Sahoka nand_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si, 1320288addd0Sahoka struct chfs_eb_hdr *ebhdr, int pebnr) 1321288addd0Sahoka { 1322288addd0Sahoka int err, lnr, ec; 1323288addd0Sahoka struct chfs_scan_leb *sleb, *old; 1324288addd0Sahoka uint64_t serial = le64toh(ebhdr->u.nand_hdr.serial); 1325288addd0Sahoka 1326288addd0Sahoka lnr = CHFS_GET_LID(ebhdr->u.nor_hdr.lid); 1327288addd0Sahoka ec = le32toh(ebhdr->ec_hdr.erase_cnt); 1328288addd0Sahoka 1329288addd0Sahoka sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP); 1330288addd0Sahoka 1331288addd0Sahoka sleb->erase_cnt = ec; 1332288addd0Sahoka sleb->lnr = lnr; 1333288addd0Sahoka sleb->pebnr = pebnr; 1334288addd0Sahoka sleb->info = serial; 1335288addd0Sahoka 1336288addd0Sahoka old = RB_INSERT(scan_leb_used_rbtree, &si->used, sleb); 1337288addd0Sahoka if (old) { 1338288addd0Sahoka kmem_free(sleb, sizeof(struct chfs_scan_leb)); 1339288addd0Sahoka /* There is already an eraseblock in the used tree */ 1340288addd0Sahoka /* If the new one is bad */ 1341288addd0Sahoka if (serial < old->info) 1342288addd0Sahoka return scan_add_to_queue(si, pebnr, ec, &si->erase); 1343288addd0Sahoka else { 1344288addd0Sahoka err = scan_add_to_queue(si, 1345288addd0Sahoka old->pebnr, old->erase_cnt, &si->erase); 1346288addd0Sahoka if (err) 1347288addd0Sahoka return err; 1348288addd0Sahoka 1349288addd0Sahoka old->erase_cnt = ec; 1350288addd0Sahoka old->lnr = lnr; 1351288addd0Sahoka old->pebnr = pebnr; 1352288addd0Sahoka old->info = serial; 1353288addd0Sahoka return 0; 1354288addd0Sahoka } 1355288addd0Sahoka } 1356288addd0Sahoka return 0; 1357288addd0Sahoka } 1358288addd0Sahoka 1359288addd0Sahoka /** 1360288addd0Sahoka * nand_process eb -read the headers from NAND flash, check them and add to the 1361288addd0Sahoka * scanning information 1362288addd0Sahoka * @ebh: chfs eraseblock handler 1363288addd0Sahoka * @si: chfs scanning information 1364288addd0Sahoka * @pebnr: physical eraseblock number 1365288addd0Sahoka * 1366288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1367288addd0Sahoka */ 1368288addd0Sahoka int 1369288addd0Sahoka nand_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si, 1370288addd0Sahoka int pebnr, struct chfs_eb_hdr *ebhdr) 1371288addd0Sahoka { 1372288addd0Sahoka int err, erase_cnt, leb_status; 1373288addd0Sahoka uint64_t max_serial; 1374f045c4d3Sahoka /* isbad() is defined on some ancient platforms, heh */ 1375f045c4d3Sahoka bool is_bad; 1376288addd0Sahoka 1377288addd0Sahoka /* Check block is bad */ 1378288addd0Sahoka err = flash_block_isbad(ebh->flash_dev, 1379f045c4d3Sahoka pebnr * ebh->flash_if->erasesize, &is_bad); 1380288addd0Sahoka if (err) { 1381288addd0Sahoka chfs_err("checking block is bad failed\n"); 1382288addd0Sahoka return err; 1383288addd0Sahoka } 1384f045c4d3Sahoka if (is_bad) { 1385288addd0Sahoka si->bad_peb_cnt++; 1386288addd0Sahoka return 0; 1387288addd0Sahoka } 1388288addd0Sahoka 1389288addd0Sahoka err = ebh->ops->read_eb_hdr(ebh, pebnr, ebhdr); 1390288addd0Sahoka if (err) 1391288addd0Sahoka return err; 1392288addd0Sahoka 1393288addd0Sahoka erase_cnt = le32toh(ebhdr->ec_hdr.erase_cnt); 1394288addd0Sahoka leb_status = ebh->ops->check_eb_hdr(ebh, ebhdr); 1395288addd0Sahoka if (EBHDR_LEB_BADMAGIC == leb_status || 1396288addd0Sahoka EBHDR_LEB_BADCRC == leb_status) { 1397288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->corrupted); 1398288addd0Sahoka return err; 1399288addd0Sahoka } 1400288addd0Sahoka else if (EBHDR_LEB_FREE == leb_status) { 1401288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->free); 1402288addd0Sahoka goto count_mean; 1403288addd0Sahoka } 1404288addd0Sahoka else if (EBHDR_LEB_NO_HDR == leb_status) { 1405288addd0Sahoka err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erased); 1406288addd0Sahoka return err; 1407288addd0Sahoka } 1408288addd0Sahoka 1409288addd0Sahoka err = nand_scan_add_to_used(ebh, si, ebhdr, pebnr); 1410288addd0Sahoka if (err) 1411288addd0Sahoka return err; 1412288addd0Sahoka 1413288addd0Sahoka max_serial = le64toh(ebhdr->u.nand_hdr.serial); 1414288addd0Sahoka if (max_serial > *ebh->max_serial) { 1415288addd0Sahoka *ebh->max_serial = max_serial; 1416288addd0Sahoka } 1417288addd0Sahoka 1418288addd0Sahoka count_mean: 1419288addd0Sahoka si->sum_of_ec += erase_cnt; 1420288addd0Sahoka si->num_of_eb++; 1421288addd0Sahoka 1422288addd0Sahoka return err; 1423288addd0Sahoka } 1424288addd0Sahoka 1425288addd0Sahoka /** 1426f273a7a1Sandvar * chfs_scan - scans the media and returns information about it 1427288addd0Sahoka * @ebh: chfs eraseblock handler 1428288addd0Sahoka * 1429288addd0Sahoka * This function scans through the media and returns information about it or if 1430288addd0Sahoka * it fails NULL will be returned. 1431288addd0Sahoka */ 1432288addd0Sahoka struct chfs_scan_info * 1433288addd0Sahoka chfs_scan(struct chfs_ebh *ebh) 1434288addd0Sahoka { 1435288addd0Sahoka struct chfs_scan_info *si; 1436288addd0Sahoka struct chfs_eb_hdr *ebhdr; 1437288addd0Sahoka int pebnr, err; 1438288addd0Sahoka 1439288addd0Sahoka si = kmem_alloc(sizeof(*si), KM_SLEEP); 1440288addd0Sahoka 1441288addd0Sahoka TAILQ_INIT(&si->corrupted); 1442288addd0Sahoka TAILQ_INIT(&si->free); 1443288addd0Sahoka TAILQ_INIT(&si->erase); 1444288addd0Sahoka TAILQ_INIT(&si->erased); 1445288addd0Sahoka RB_INIT(&si->used); 1446288addd0Sahoka si->bad_peb_cnt = 0; 1447288addd0Sahoka si->num_of_eb = 0; 1448288addd0Sahoka si->sum_of_ec = 0; 1449288addd0Sahoka 1450288addd0Sahoka ebhdr = kmem_alloc(sizeof(*ebhdr), KM_SLEEP); 1451288addd0Sahoka 1452288addd0Sahoka for (pebnr = 0; pebnr < ebh->peb_nr; pebnr++) { 1453288addd0Sahoka dbg_ebh("processing PEB %d\n", pebnr); 1454288addd0Sahoka err = ebh->ops->process_eb(ebh, si, pebnr, ebhdr); 1455288addd0Sahoka if (err < 0) 1456288addd0Sahoka goto out_ebhdr; 1457288addd0Sahoka } 1458288addd0Sahoka kmem_free(ebhdr, sizeof(*ebhdr)); 1459288addd0Sahoka dbg_ebh("[CHFS_SCAN] scanning information collected\n"); 1460288addd0Sahoka return si; 1461288addd0Sahoka 1462288addd0Sahoka out_ebhdr: 1463288addd0Sahoka kmem_free(ebhdr, sizeof(*ebhdr)); 1464288addd0Sahoka kmem_free(si, sizeof(*si)); 1465288addd0Sahoka return NULL; 1466288addd0Sahoka } 1467288addd0Sahoka 1468288addd0Sahoka /** 1469288addd0Sahoka * scan_info_destroy - frees all lists and trees in the scanning information 1470288addd0Sahoka * @si: the scanning information 1471288addd0Sahoka */ 1472288addd0Sahoka void 1473288addd0Sahoka scan_info_destroy(struct chfs_scan_info *si) 1474288addd0Sahoka { 1475288addd0Sahoka EBH_QUEUE_DESTROY(&si->corrupted, 1476288addd0Sahoka struct chfs_scan_leb, u.queue); 1477288addd0Sahoka 1478288addd0Sahoka EBH_QUEUE_DESTROY(&si->erase, 1479288addd0Sahoka struct chfs_scan_leb, u.queue); 1480288addd0Sahoka 1481288addd0Sahoka EBH_QUEUE_DESTROY(&si->erased, 1482288addd0Sahoka struct chfs_scan_leb, u.queue); 1483288addd0Sahoka 1484288addd0Sahoka EBH_QUEUE_DESTROY(&si->free, 1485288addd0Sahoka struct chfs_scan_leb, u.queue); 1486288addd0Sahoka 1487288addd0Sahoka EBH_TREE_DESTROY(scan_leb_used_rbtree, 1488288addd0Sahoka &si->used, struct chfs_scan_leb); 1489288addd0Sahoka 1490288addd0Sahoka kmem_free(si, sizeof(*si)); 1491288addd0Sahoka dbg_ebh("[SCAN_INFO_DESTROY] scanning information destroyed\n"); 1492288addd0Sahoka } 1493288addd0Sahoka 1494288addd0Sahoka /** 1495288addd0Sahoka * scan_media - scan media 1496288addd0Sahoka * 1497288addd0Sahoka * @ebh - chfs eraseblock handler 1498288addd0Sahoka * 1499288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1500288addd0Sahoka */ 1501288addd0Sahoka 1502288addd0Sahoka int 1503288addd0Sahoka scan_media(struct chfs_ebh *ebh) 1504288addd0Sahoka { 1505288addd0Sahoka int err, i, avg_ec; 1506288addd0Sahoka struct chfs_scan_info *si; 1507288addd0Sahoka struct chfs_scan_leb *sleb; 1508288addd0Sahoka 1509288addd0Sahoka si = chfs_scan(ebh); 1510288addd0Sahoka /* 1511288addd0Sahoka * Process the scan info, manage the eraseblock lists 1512288addd0Sahoka */ 1513288addd0Sahoka mutex_init(&ebh->ltree_lock, MUTEX_DEFAULT, IPL_NONE); 1514288addd0Sahoka mutex_init(&ebh->erase_lock, MUTEX_DEFAULT, IPL_NONE); 1515288addd0Sahoka RB_INIT(&ebh->ltree); 1516288addd0Sahoka RB_INIT(&ebh->free); 1517288addd0Sahoka RB_INIT(&ebh->in_use); 1518288addd0Sahoka TAILQ_INIT(&ebh->to_erase); 1519288addd0Sahoka TAILQ_INIT(&ebh->fully_erased); 1520288addd0Sahoka mutex_init(&ebh->alc_mutex, MUTEX_DEFAULT, IPL_NONE); 1521288addd0Sahoka 1522288addd0Sahoka ebh->peb_nr -= si->bad_peb_cnt; 1523288addd0Sahoka 1524288addd0Sahoka /* 1525288addd0Sahoka * Create background thread for erasing 1526288addd0Sahoka */ 1527288addd0Sahoka erase_thread_start(ebh); 1528288addd0Sahoka 1529288addd0Sahoka ebh->lmap = kmem_alloc(ebh->peb_nr * sizeof(int), KM_SLEEP); 1530288addd0Sahoka 1531288addd0Sahoka for (i = 0; i < ebh->peb_nr; i++) { 1532288addd0Sahoka ebh->lmap[i] = EBH_LEB_UNMAPPED; 1533288addd0Sahoka } 1534288addd0Sahoka 1535288addd0Sahoka if (si->num_of_eb == 0) { 1536288addd0Sahoka /* The flash contains no data. */ 1537288addd0Sahoka avg_ec = 0; 1538288addd0Sahoka } 1539288addd0Sahoka else { 1540288addd0Sahoka avg_ec = (int) (si->sum_of_ec / si->num_of_eb); 1541288addd0Sahoka } 1542288addd0Sahoka dbg_ebh("num_of_eb: %d\n", si->num_of_eb); 1543288addd0Sahoka 1544288addd0Sahoka mutex_enter(&ebh->erase_lock); 1545288addd0Sahoka 1546288addd0Sahoka RB_FOREACH(sleb, scan_leb_used_rbtree, &si->used) { 1547288addd0Sahoka ebh->lmap[sleb->lnr] = sleb->pebnr; 1548288addd0Sahoka err = add_peb_to_in_use(ebh, sleb->pebnr, sleb->erase_cnt); 1549288addd0Sahoka if (err) 1550288addd0Sahoka goto out_free; 1551288addd0Sahoka } 1552288addd0Sahoka 1553288addd0Sahoka TAILQ_FOREACH(sleb, &si->erased, u.queue) { 1554288addd0Sahoka err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec, 1555288addd0Sahoka &ebh->fully_erased); 1556288addd0Sahoka if (err) 1557288addd0Sahoka goto out_free; 1558288addd0Sahoka } 1559288addd0Sahoka 1560288addd0Sahoka TAILQ_FOREACH(sleb, &si->erase, u.queue) { 1561288addd0Sahoka err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec, 1562288addd0Sahoka &ebh->to_erase); 1563288addd0Sahoka if (err) 1564288addd0Sahoka goto out_free; 1565288addd0Sahoka } 1566288addd0Sahoka 1567288addd0Sahoka TAILQ_FOREACH(sleb, &si->free, u.queue) { 1568288addd0Sahoka err = add_peb_to_free(ebh, sleb->pebnr, sleb->erase_cnt); 1569288addd0Sahoka if (err) 1570288addd0Sahoka goto out_free; 1571288addd0Sahoka } 1572288addd0Sahoka 1573288addd0Sahoka TAILQ_FOREACH(sleb, &si->corrupted, u.queue) { 1574288addd0Sahoka err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec, 1575288addd0Sahoka &ebh->to_erase); 1576288addd0Sahoka if (err) 1577288addd0Sahoka goto out_free; 1578288addd0Sahoka } 1579288addd0Sahoka mutex_exit(&ebh->erase_lock); 1580288addd0Sahoka scan_info_destroy(si); 1581288addd0Sahoka return 0; 1582288addd0Sahoka 1583288addd0Sahoka out_free: 1584288addd0Sahoka mutex_exit(&ebh->erase_lock); 1585288addd0Sahoka kmem_free(ebh->lmap, ebh->peb_nr * sizeof(int)); 1586288addd0Sahoka scan_info_destroy(si); 1587288addd0Sahoka dbg_ebh("[SCAN_MEDIA] returning with error: %d\n", err); 1588288addd0Sahoka return err; 1589288addd0Sahoka } 1590288addd0Sahoka 1591288addd0Sahoka /*****************************************************************************/ 1592288addd0Sahoka /* End of Scan related operations */ 1593288addd0Sahoka /*****************************************************************************/ 1594288addd0Sahoka 1595288addd0Sahoka /** 1596f273a7a1Sandvar * ebh_open - opens mtd device and init eraseblock header 1597288addd0Sahoka * @ebh: eraseblock handler 1598288addd0Sahoka * @flash_nr: flash device number to use 1599288addd0Sahoka * 1600288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1601288addd0Sahoka */ 1602288addd0Sahoka int 1603288addd0Sahoka ebh_open(struct chfs_ebh *ebh, dev_t dev) 1604288addd0Sahoka { 1605288addd0Sahoka int err; 1606288addd0Sahoka 1607288addd0Sahoka ebh->flash_dev = flash_get_device(dev); 1608288addd0Sahoka if (!ebh->flash_dev) { 1609288addd0Sahoka aprint_error("ebh_open: cant get flash device\n"); 1610288addd0Sahoka return ENODEV; 1611288addd0Sahoka } 1612288addd0Sahoka 1613288addd0Sahoka ebh->flash_if = flash_get_interface(dev); 1614288addd0Sahoka if (!ebh->flash_if) { 1615288addd0Sahoka aprint_error("ebh_open: cant get flash interface\n"); 1616288addd0Sahoka return ENODEV; 1617288addd0Sahoka } 1618288addd0Sahoka 1619288addd0Sahoka ebh->flash_size = flash_get_size(dev); 1620288addd0Sahoka ebh->peb_nr = ebh->flash_size / ebh->flash_if->erasesize; 1621288addd0Sahoka // ebh->peb_nr = ebh->flash_if->size / ebh->flash_if->erasesize; 1622288addd0Sahoka /* Set up flash operations based on flash type */ 1623288addd0Sahoka ebh->ops = kmem_alloc(sizeof(struct chfs_ebh_ops), KM_SLEEP); 1624288addd0Sahoka 1625288addd0Sahoka switch (ebh->flash_if->type) { 1626288addd0Sahoka case FLASH_TYPE_NOR: 1627288addd0Sahoka ebh->eb_size = ebh->flash_if->erasesize - 1628288addd0Sahoka CHFS_EB_EC_HDR_SIZE - CHFS_EB_HDR_NOR_SIZE; 1629288addd0Sahoka 1630288addd0Sahoka ebh->ops->read_eb_hdr = nor_read_eb_hdr; 1631288addd0Sahoka ebh->ops->write_eb_hdr = nor_write_eb_hdr; 1632288addd0Sahoka ebh->ops->check_eb_hdr = nor_check_eb_hdr; 1633288addd0Sahoka ebh->ops->mark_eb_hdr_dirty_flash = 1634288addd0Sahoka nor_mark_eb_hdr_dirty_flash; 1635288addd0Sahoka ebh->ops->invalidate_eb_hdr = nor_invalidate_eb_hdr; 1636288addd0Sahoka ebh->ops->mark_eb_hdr_free = mark_eb_hdr_free; 1637288addd0Sahoka 1638288addd0Sahoka ebh->ops->process_eb = nor_process_eb; 1639288addd0Sahoka 1640288addd0Sahoka ebh->ops->create_eb_hdr = nor_create_eb_hdr; 1641288addd0Sahoka ebh->ops->calc_data_offs = nor_calc_data_offs; 1642288addd0Sahoka 1643288addd0Sahoka ebh->max_serial = NULL; 1644288addd0Sahoka break; 1645288addd0Sahoka case FLASH_TYPE_NAND: 1646288addd0Sahoka ebh->eb_size = ebh->flash_if->erasesize - 1647288addd0Sahoka 2 * ebh->flash_if->page_size; 1648288addd0Sahoka 1649288addd0Sahoka ebh->ops->read_eb_hdr = nand_read_eb_hdr; 1650288addd0Sahoka ebh->ops->write_eb_hdr = nand_write_eb_hdr; 1651288addd0Sahoka ebh->ops->check_eb_hdr = nand_check_eb_hdr; 1652288addd0Sahoka ebh->ops->mark_eb_hdr_free = mark_eb_hdr_free; 1653288addd0Sahoka ebh->ops->mark_eb_hdr_dirty_flash = NULL; 1654288addd0Sahoka ebh->ops->invalidate_eb_hdr = NULL; 1655288addd0Sahoka 1656288addd0Sahoka ebh->ops->process_eb = nand_process_eb; 1657288addd0Sahoka 1658288addd0Sahoka ebh->ops->create_eb_hdr = nand_create_eb_hdr; 1659288addd0Sahoka ebh->ops->calc_data_offs = nand_calc_data_offs; 1660288addd0Sahoka 1661288addd0Sahoka ebh->max_serial = kmem_alloc(sizeof(uint64_t), KM_SLEEP); 1662288addd0Sahoka 1663288addd0Sahoka *ebh->max_serial = 0; 1664288addd0Sahoka break; 1665288addd0Sahoka default: 1666288addd0Sahoka return 1; 1667288addd0Sahoka } 1668288addd0Sahoka printf("opening ebh: eb_size: %zu\n", ebh->eb_size); 1669288addd0Sahoka err = scan_media(ebh); 1670288addd0Sahoka if (err) { 1671288addd0Sahoka dbg_ebh("Scan failed."); 1672288addd0Sahoka kmem_free(ebh->ops, sizeof(struct chfs_ebh_ops)); 1673288addd0Sahoka kmem_free(ebh, sizeof(struct chfs_ebh)); 1674288addd0Sahoka return err; 1675288addd0Sahoka } 1676288addd0Sahoka return 0; 1677288addd0Sahoka } 1678288addd0Sahoka 1679288addd0Sahoka /** 1680288addd0Sahoka * ebh_close - close ebh 1681288addd0Sahoka * @ebh: eraseblock handler 1682288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1683288addd0Sahoka */ 1684288addd0Sahoka int 1685288addd0Sahoka ebh_close(struct chfs_ebh *ebh) 1686288addd0Sahoka { 1687288addd0Sahoka erase_thread_stop(ebh); 1688288addd0Sahoka 1689288addd0Sahoka EBH_TREE_DESTROY(peb_free_rbtree, &ebh->free, struct chfs_peb); 1690288addd0Sahoka EBH_TREE_DESTROY(peb_in_use_rbtree, &ebh->in_use, struct chfs_peb); 1691288addd0Sahoka 1692288addd0Sahoka EBH_QUEUE_DESTROY(&ebh->fully_erased, struct chfs_peb, u.queue); 1693288addd0Sahoka EBH_QUEUE_DESTROY(&ebh->to_erase, struct chfs_peb, u.queue); 1694288addd0Sahoka 1695288addd0Sahoka /* XXX HACK, see ebh.h */ 1696288addd0Sahoka EBH_TREE_DESTROY_MUTEX(ltree_rbtree, &ebh->ltree, 1697288addd0Sahoka struct chfs_ltree_entry); 1698288addd0Sahoka 1699288addd0Sahoka KASSERT(!mutex_owned(&ebh->ltree_lock)); 1700288addd0Sahoka KASSERT(!mutex_owned(&ebh->alc_mutex)); 1701288addd0Sahoka KASSERT(!mutex_owned(&ebh->erase_lock)); 1702288addd0Sahoka 1703288addd0Sahoka mutex_destroy(&ebh->ltree_lock); 1704288addd0Sahoka mutex_destroy(&ebh->alc_mutex); 1705288addd0Sahoka mutex_destroy(&ebh->erase_lock); 1706288addd0Sahoka 1707288addd0Sahoka kmem_free(ebh->ops, sizeof(struct chfs_ebh_ops)); 1708288addd0Sahoka kmem_free(ebh, sizeof(struct chfs_ebh)); 1709288addd0Sahoka 1710288addd0Sahoka return 0; 1711288addd0Sahoka } 1712288addd0Sahoka 1713288addd0Sahoka /** 1714288addd0Sahoka * ebh_read_leb - read data from leb 1715288addd0Sahoka * @ebh: eraseblock handler 1716288addd0Sahoka * @lnr: logical eraseblock number 1717288addd0Sahoka * @buf: buffer to read to 1718288addd0Sahoka * @offset: offset from where to read 1719288addd0Sahoka * @len: bytes number to read 1720288addd0Sahoka * 1721288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1722288addd0Sahoka */ 1723288addd0Sahoka int 1724288addd0Sahoka ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset, 1725288addd0Sahoka size_t len, size_t *retlen) 1726288addd0Sahoka { 1727288addd0Sahoka int err, pebnr; 1728288addd0Sahoka off_t data_offset; 1729288addd0Sahoka 1730288addd0Sahoka KASSERT(offset + len <= ebh->eb_size); 1731288addd0Sahoka 1732288addd0Sahoka err = leb_read_lock(ebh, lnr); 1733288addd0Sahoka if (err) 1734288addd0Sahoka return err; 17353fae61eeSttoth 1736288addd0Sahoka pebnr = ebh->lmap[lnr]; 1737288addd0Sahoka /* If PEB is not mapped the buffer is filled with 0xFF */ 1738288addd0Sahoka if (EBH_LEB_UNMAPPED == pebnr) { 1739288addd0Sahoka leb_read_unlock(ebh, lnr); 1740288addd0Sahoka memset(buf, 0xFF, len); 1741288addd0Sahoka return 0; 1742288addd0Sahoka } 1743288addd0Sahoka 1744288addd0Sahoka /* Read data */ 1745288addd0Sahoka data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset); 1746288addd0Sahoka err = flash_read(ebh->flash_dev, data_offset, len, retlen, 1747288addd0Sahoka (unsigned char *) buf); 1748288addd0Sahoka if (err) 1749288addd0Sahoka goto out_free; 1750288addd0Sahoka 1751288addd0Sahoka KASSERT(len == *retlen); 1752288addd0Sahoka 1753288addd0Sahoka out_free: 1754288addd0Sahoka leb_read_unlock(ebh, lnr); 1755288addd0Sahoka return err; 1756288addd0Sahoka } 1757288addd0Sahoka 1758288addd0Sahoka /** 1759288addd0Sahoka * get_peb: get a free physical eraseblock 1760288addd0Sahoka * @ebh - chfs eraseblock handler 1761288addd0Sahoka * 1762288addd0Sahoka * This function gets a free eraseblock from the ebh->free RB-tree. 176320fff34fSandvar * The first entry will be returned and deleted from the tree. 1764288addd0Sahoka * The entries sorted by the erase counters, so the PEB with the smallest 1765288addd0Sahoka * erase counter will be added back. 1766288addd0Sahoka * If something goes bad a negative value will be returned. 1767288addd0Sahoka */ 1768288addd0Sahoka int 1769288addd0Sahoka get_peb(struct chfs_ebh *ebh) 1770288addd0Sahoka { 1771288addd0Sahoka int err, pebnr; 1772288addd0Sahoka struct chfs_peb *peb; 1773288addd0Sahoka 1774288addd0Sahoka retry: 1775288addd0Sahoka mutex_enter(&ebh->erase_lock); 1776288addd0Sahoka //dbg_ebh("LOCK: ebh->erase_lock spin locked in get_peb()\n"); 1777288addd0Sahoka if (RB_EMPTY(&ebh->free)) { 1778288addd0Sahoka /*There is no more free PEBs in the tree*/ 1779288addd0Sahoka if (TAILQ_EMPTY(&ebh->to_erase) && 1780288addd0Sahoka TAILQ_EMPTY(&ebh->fully_erased)) { 1781288addd0Sahoka mutex_exit(&ebh->erase_lock); 1782288addd0Sahoka //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n"); 1783288addd0Sahoka return ENOSPC; 1784288addd0Sahoka } 1785288addd0Sahoka err = free_peb(ebh); 1786288addd0Sahoka 1787288addd0Sahoka mutex_exit(&ebh->erase_lock); 1788288addd0Sahoka //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n"); 1789288addd0Sahoka 1790288addd0Sahoka if (err) 1791288addd0Sahoka return err; 1792288addd0Sahoka goto retry; 1793288addd0Sahoka } 1794288addd0Sahoka peb = RB_MIN(peb_free_rbtree, &ebh->free); 1795288addd0Sahoka pebnr = peb->pebnr; 1796288addd0Sahoka RB_REMOVE(peb_free_rbtree, &ebh->free, peb); 1797288addd0Sahoka err = add_peb_to_in_use(ebh, peb->pebnr, peb->erase_cnt); 1798288addd0Sahoka if (err) 1799288addd0Sahoka pebnr = err; 1800288addd0Sahoka 1801288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 1802288addd0Sahoka 1803288addd0Sahoka mutex_exit(&ebh->erase_lock); 1804288addd0Sahoka //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n"); 1805288addd0Sahoka 1806288addd0Sahoka return pebnr; 1807288addd0Sahoka } 1808288addd0Sahoka 1809288addd0Sahoka /** 1810288addd0Sahoka * ebh_write_leb - write data to leb 1811288addd0Sahoka * @ebh: eraseblock handler 1812288addd0Sahoka * @lnr: logical eraseblock number 1813288addd0Sahoka * @buf: data to write 1814288addd0Sahoka * @offset: offset where to write 1815288addd0Sahoka * @len: bytes number to write 1816288addd0Sahoka * 1817288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1818288addd0Sahoka */ 1819288addd0Sahoka int 1820288addd0Sahoka ebh_write_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset, 1821288addd0Sahoka size_t len, size_t *retlen) 1822288addd0Sahoka { 1823288addd0Sahoka int err, pebnr, retries = 0; 1824288addd0Sahoka off_t data_offset; 1825288addd0Sahoka struct chfs_eb_hdr *ebhdr; 1826288addd0Sahoka 1827288addd0Sahoka dbg("offset: %d | len: %zu | (offset+len): %zu " 1828288addd0Sahoka " | ebsize: %zu\n", offset, len, (offset+len), ebh->eb_size); 1829288addd0Sahoka 1830288addd0Sahoka KASSERT(offset + len <= ebh->eb_size); 1831288addd0Sahoka 1832288addd0Sahoka err = leb_write_lock(ebh, lnr); 1833288addd0Sahoka if (err) 1834288addd0Sahoka return err; 1835288addd0Sahoka 1836288addd0Sahoka pebnr = ebh->lmap[lnr]; 1837288addd0Sahoka /* If the LEB is mapped write out data */ 1838288addd0Sahoka if (pebnr != EBH_LEB_UNMAPPED) { 1839288addd0Sahoka data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset); 1840288addd0Sahoka err = flash_write(ebh->flash_dev, data_offset, len, retlen, 1841288addd0Sahoka (unsigned char *) buf); 1842288addd0Sahoka 1843288addd0Sahoka if (err) { 1844288addd0Sahoka chfs_err("error %d while writing %zu bytes to PEB " 1845288addd0Sahoka "%d:%ju, written %zu bytes\n", 1846288addd0Sahoka err, len, pebnr, (uintmax_t )offset, *retlen); 1847288addd0Sahoka } else { 1848288addd0Sahoka KASSERT(len == *retlen); 1849288addd0Sahoka } 1850288addd0Sahoka 1851288addd0Sahoka leb_write_unlock(ebh, lnr); 1852288addd0Sahoka return err; 1853288addd0Sahoka } 1854288addd0Sahoka 1855288addd0Sahoka /* 1856288addd0Sahoka * If the LEB is unmapped, get a free PEB and write the 1857288addd0Sahoka * eraseblock header first 1858288addd0Sahoka */ 1859288addd0Sahoka ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP); 1860288addd0Sahoka 1861288addd0Sahoka /* Setting up eraseblock header properties */ 1862288addd0Sahoka ebh->ops->create_eb_hdr(ebhdr, lnr); 1863288addd0Sahoka 1864288addd0Sahoka retry: 1865288addd0Sahoka /* Getting a physical eraseblock from the wear leveling system */ 1866288addd0Sahoka pebnr = get_peb(ebh); 1867288addd0Sahoka if (pebnr < 0) { 1868288addd0Sahoka leb_write_unlock(ebh, lnr); 1869288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 1870288addd0Sahoka return pebnr; 1871288addd0Sahoka } 1872288addd0Sahoka 1873288addd0Sahoka /* Write the eraseblock header to the media */ 1874288addd0Sahoka err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr); 1875288addd0Sahoka if (err) { 1876288addd0Sahoka chfs_warn( 1877288addd0Sahoka "error writing eraseblock header: LEB %d , PEB %d\n", 1878288addd0Sahoka lnr, pebnr); 1879288addd0Sahoka goto write_error; 1880288addd0Sahoka } 1881288addd0Sahoka 1882288addd0Sahoka /* Write out data */ 1883288addd0Sahoka if (len) { 1884288addd0Sahoka data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset); 1885288addd0Sahoka err = flash_write(ebh->flash_dev, 1886288addd0Sahoka data_offset, len, retlen, (unsigned char *) buf); 1887288addd0Sahoka if (err) { 1888288addd0Sahoka chfs_err("error %d while writing %zu bytes to PEB " 1889288addd0Sahoka " %d:%ju, written %zu bytes\n", 1890288addd0Sahoka err, len, pebnr, (uintmax_t )offset, *retlen); 1891288addd0Sahoka goto write_error; 1892288addd0Sahoka } 1893288addd0Sahoka } 1894288addd0Sahoka 1895288addd0Sahoka ebh->lmap[lnr] = pebnr; 1896288addd0Sahoka leb_write_unlock(ebh, lnr); 1897288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 1898288addd0Sahoka 1899288addd0Sahoka return 0; 1900288addd0Sahoka 1901288addd0Sahoka write_error: err = release_peb(ebh, pebnr); 1902288addd0Sahoka // max retries (NOW: 2) 1903288addd0Sahoka if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) { 1904288addd0Sahoka leb_write_unlock(ebh, lnr); 1905288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 1906288addd0Sahoka return err; 1907288addd0Sahoka } 1908288addd0Sahoka goto retry; 1909288addd0Sahoka } 1910288addd0Sahoka 1911288addd0Sahoka /** 1912288addd0Sahoka * ebh_erase_leb - erase a leb 1913288addd0Sahoka * @ebh: eraseblock handler 1914288addd0Sahoka * @lnr: leb number 1915288addd0Sahoka * 1916288addd0Sahoka * Returns zero in case of success, error code in case of fail. 1917288addd0Sahoka */ 1918288addd0Sahoka int 1919288addd0Sahoka ebh_erase_leb(struct chfs_ebh *ebh, int lnr) 1920288addd0Sahoka { 1921288addd0Sahoka int err, pebnr; 1922288addd0Sahoka 1923288addd0Sahoka leb_write_lock(ebh, lnr); 1924288addd0Sahoka 1925288addd0Sahoka pebnr = ebh->lmap[lnr]; 1926288addd0Sahoka if (pebnr < 0) { 1927288addd0Sahoka leb_write_unlock(ebh, lnr); 1928288addd0Sahoka return EBH_LEB_UNMAPPED; 1929288addd0Sahoka } 1930288addd0Sahoka err = release_peb(ebh, pebnr); 1931288addd0Sahoka if (err) 1932288addd0Sahoka goto out_unlock; 1933288addd0Sahoka 1934288addd0Sahoka ebh->lmap[lnr] = EBH_LEB_UNMAPPED; 1935288addd0Sahoka cv_signal(&ebh->bg_erase.eth_wakeup); 1936288addd0Sahoka out_unlock: 1937288addd0Sahoka leb_write_unlock(ebh, lnr); 1938288addd0Sahoka return err; 1939288addd0Sahoka } 1940288addd0Sahoka 1941288addd0Sahoka /** 1942288addd0Sahoka * ebh_map_leb - maps a PEB to LEB 1943288addd0Sahoka * @ebh: eraseblock handler 1944288addd0Sahoka * @lnr: leb number 1945288addd0Sahoka * 1946288addd0Sahoka * Returns zero on success, error code in case of fail 1947288addd0Sahoka */ 1948288addd0Sahoka int 1949288addd0Sahoka ebh_map_leb(struct chfs_ebh *ebh, int lnr) 1950288addd0Sahoka { 1951288addd0Sahoka int err, pebnr, retries = 0; 1952288addd0Sahoka struct chfs_eb_hdr *ebhdr; 1953288addd0Sahoka 1954288addd0Sahoka ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP); 1955288addd0Sahoka 1956288addd0Sahoka err = leb_write_lock(ebh, lnr); 1957aad3a792Schristos if (err) { 1958aad3a792Schristos kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 1959288addd0Sahoka return err; 1960aad3a792Schristos } 1961288addd0Sahoka 1962288addd0Sahoka retry: 1963288addd0Sahoka pebnr = get_peb(ebh); 1964288addd0Sahoka if (pebnr < 0) { 1965288addd0Sahoka err = pebnr; 1966288addd0Sahoka goto out_unlock; 1967288addd0Sahoka } 1968288addd0Sahoka 1969288addd0Sahoka ebh->ops->create_eb_hdr(ebhdr, lnr); 1970288addd0Sahoka 1971288addd0Sahoka err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr); 1972288addd0Sahoka if (err) { 1973288addd0Sahoka chfs_warn( 1974288addd0Sahoka "error writing eraseblock header: LEB %d , PEB %d\n", 1975288addd0Sahoka lnr, pebnr); 1976288addd0Sahoka goto write_error; 1977288addd0Sahoka } 1978288addd0Sahoka 1979288addd0Sahoka ebh->lmap[lnr] = pebnr; 1980288addd0Sahoka 1981288addd0Sahoka out_unlock: 1982288addd0Sahoka leb_write_unlock(ebh, lnr); 1983288addd0Sahoka return err; 1984288addd0Sahoka 1985288addd0Sahoka write_error: 1986288addd0Sahoka err = release_peb(ebh, pebnr); 1987288addd0Sahoka // max retries (NOW: 2) 1988288addd0Sahoka if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) { 1989288addd0Sahoka leb_write_unlock(ebh, lnr); 1990288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 1991288addd0Sahoka return err; 1992288addd0Sahoka } 1993288addd0Sahoka goto retry; 1994288addd0Sahoka } 1995288addd0Sahoka 1996288addd0Sahoka /** 1997288addd0Sahoka * ebh_unmap_leb - 1998288addd0Sahoka * @ebh: eraseblock handler 1999288addd0Sahoka * @lnr: leb number 2000288addd0Sahoka * 2001f273a7a1Sandvar * Returns zero on success, error code in case of fail. 2002288addd0Sahoka */ 2003288addd0Sahoka int 2004288addd0Sahoka ebh_unmap_leb(struct chfs_ebh *ebh, int lnr) 2005288addd0Sahoka { 2006288addd0Sahoka int err; 2007288addd0Sahoka 2008288addd0Sahoka if (ebh_is_mapped(ebh, lnr) < 0) 2009288addd0Sahoka /* If the eraseblock already unmapped */ 2010288addd0Sahoka return 0; 2011288addd0Sahoka 2012288addd0Sahoka err = ebh_erase_leb(ebh, lnr); 2013288addd0Sahoka 2014288addd0Sahoka return err; 2015288addd0Sahoka } 2016288addd0Sahoka 2017288addd0Sahoka /** 2018288addd0Sahoka * ebh_is_mapped - check if a PEB is mapped to @lnr 2019288addd0Sahoka * @ebh: eraseblock handler 2020288addd0Sahoka * @lnr: leb number 2021288addd0Sahoka * 2022f273a7a1Sandvar * Returns 0 if the logical eraseblock is mapped, negative error code otherwise. 2023288addd0Sahoka */ 2024288addd0Sahoka int 2025288addd0Sahoka ebh_is_mapped(struct chfs_ebh *ebh, int lnr) 2026288addd0Sahoka { 2027288addd0Sahoka int err, result; 2028288addd0Sahoka err = leb_read_lock(ebh, lnr); 2029288addd0Sahoka if (err) 2030288addd0Sahoka return err; 2031288addd0Sahoka 2032288addd0Sahoka result = ebh->lmap[lnr]; 2033288addd0Sahoka leb_read_unlock(ebh, lnr); 2034288addd0Sahoka 2035288addd0Sahoka return result; 2036288addd0Sahoka } 2037288addd0Sahoka 2038288addd0Sahoka /** 2039288addd0Sahoka * ebh_change_leb - write the LEB to another PEB 2040288addd0Sahoka * @ebh: eraseblock handler 2041288addd0Sahoka * @lnr: leb number 2042288addd0Sahoka * @buf: data to write 2043288addd0Sahoka * @len: length of data 2044288addd0Sahoka * Returns zero in case of success, error code in case of fail. 2045288addd0Sahoka */ 2046288addd0Sahoka int 2047288addd0Sahoka ebh_change_leb(struct chfs_ebh *ebh, int lnr, char *buf, size_t len, 2048288addd0Sahoka size_t *retlen) 2049288addd0Sahoka { 2050288addd0Sahoka int err, pebnr, pebnr_old, retries = 0; 2051288addd0Sahoka off_t data_offset; 2052288addd0Sahoka 2053288addd0Sahoka struct chfs_peb *peb = NULL; 2054288addd0Sahoka struct chfs_eb_hdr *ebhdr; 2055288addd0Sahoka 2056288addd0Sahoka if (ebh_is_mapped(ebh, lnr) < 0) 2057288addd0Sahoka return EBH_LEB_UNMAPPED; 2058288addd0Sahoka 2059288addd0Sahoka if (len == 0) { 2060288addd0Sahoka err = ebh_unmap_leb(ebh, lnr); 2061288addd0Sahoka if (err) 2062288addd0Sahoka return err; 2063288addd0Sahoka return ebh_map_leb(ebh, lnr); 2064288addd0Sahoka } 2065288addd0Sahoka 2066288addd0Sahoka ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP); 2067288addd0Sahoka 2068288addd0Sahoka pebnr_old = ebh->lmap[lnr]; 2069288addd0Sahoka 2070288addd0Sahoka mutex_enter(&ebh->alc_mutex); 2071288addd0Sahoka err = leb_write_lock(ebh, lnr); 2072288addd0Sahoka if (err) 2073288addd0Sahoka goto out_mutex; 2074288addd0Sahoka 2075288addd0Sahoka if (ebh->ops->mark_eb_hdr_dirty_flash) { 2076288addd0Sahoka err = ebh->ops->mark_eb_hdr_dirty_flash(ebh, pebnr_old, lnr); 2077288addd0Sahoka if (err) 2078288addd0Sahoka goto out_unlock; 2079288addd0Sahoka } 2080288addd0Sahoka 2081288addd0Sahoka /* Setting up eraseblock header properties */ 2082288addd0Sahoka ebh->ops->create_eb_hdr(ebhdr, lnr); 2083288addd0Sahoka 2084288addd0Sahoka retry: 2085288addd0Sahoka /* Getting a physical eraseblock from the wear leveling system */ 2086288addd0Sahoka pebnr = get_peb(ebh); 2087288addd0Sahoka if (pebnr < 0) { 2088288addd0Sahoka leb_write_unlock(ebh, lnr); 2089288addd0Sahoka mutex_exit(&ebh->alc_mutex); 2090288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 2091288addd0Sahoka return pebnr; 2092288addd0Sahoka } 2093288addd0Sahoka 2094288addd0Sahoka err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr); 2095288addd0Sahoka if (err) { 2096288addd0Sahoka chfs_warn( 2097288addd0Sahoka "error writing eraseblock header: LEB %d , PEB %d", 2098288addd0Sahoka lnr, pebnr); 2099288addd0Sahoka goto write_error; 2100288addd0Sahoka } 2101288addd0Sahoka 2102288addd0Sahoka /* Write out data */ 2103288addd0Sahoka data_offset = ebh->ops->calc_data_offs(ebh, pebnr, 0); 2104288addd0Sahoka err = flash_write(ebh->flash_dev, data_offset, len, retlen, 2105288addd0Sahoka (unsigned char *) buf); 2106288addd0Sahoka if (err) { 2107288addd0Sahoka chfs_err("error %d while writing %zu bytes to PEB %d:%ju," 2108288addd0Sahoka " written %zu bytes", 2109288addd0Sahoka err, len, pebnr, (uintmax_t)data_offset, *retlen); 2110288addd0Sahoka goto write_error; 2111288addd0Sahoka } 2112288addd0Sahoka 2113288addd0Sahoka ebh->lmap[lnr] = pebnr; 2114288addd0Sahoka 2115288addd0Sahoka if (ebh->ops->invalidate_eb_hdr) { 2116288addd0Sahoka err = ebh->ops->invalidate_eb_hdr(ebh, pebnr_old); 2117288addd0Sahoka if (err) 2118288addd0Sahoka goto out_unlock; 2119288addd0Sahoka } 2120288addd0Sahoka peb = find_peb_in_use(ebh, pebnr_old); 2121288addd0Sahoka err = release_peb(ebh, peb->pebnr); 2122288addd0Sahoka 2123288addd0Sahoka out_unlock: 2124288addd0Sahoka leb_write_unlock(ebh, lnr); 2125288addd0Sahoka 2126288addd0Sahoka out_mutex: 2127288addd0Sahoka mutex_exit(&ebh->alc_mutex); 2128288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 2129288addd0Sahoka kmem_free(peb, sizeof(struct chfs_peb)); 2130288addd0Sahoka return err; 2131288addd0Sahoka 2132288addd0Sahoka write_error: 2133288addd0Sahoka err = release_peb(ebh, pebnr); 2134288addd0Sahoka //max retries (NOW: 2) 2135288addd0Sahoka if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) { 2136288addd0Sahoka leb_write_unlock(ebh, lnr); 2137288addd0Sahoka mutex_exit(&ebh->alc_mutex); 2138288addd0Sahoka kmem_free(ebhdr, sizeof(struct chfs_eb_hdr)); 2139288addd0Sahoka return err; 2140288addd0Sahoka } 2141288addd0Sahoka goto retry; 2142288addd0Sahoka } 2143288addd0Sahoka 2144