static void read_random_writes_cache(int bank, int phys_segment) { int page = 0; short log_segment; unsigned char spare_buf[16]; nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), SECTOR_SIZE, /* offset to first sector's spare */ 16, spare_buf); log_segment = get_log_segment_id(phys_segment, spare_buf); if (log_segment == -1) return; /* Find which cache this is related to */ int cache_no = find_write_cache(log_segment); if (cache_no == -1) { if (write_caches_in_use < MAX_WRITE_CACHES) { cache_no = write_caches_in_use; write_caches_in_use++; } else { panicf("Max NAND write caches reached"); } } write_caches[cache_no].log_segment = log_segment; write_caches[cache_no].random_bank = bank; write_caches[cache_no].random_phys_segment = phys_segment; #ifndef FTL_V1 /* Loop over each page in the phys segment (from page 1 onwards). Read spare for 1st sector, store location of page in array. */ for (page = 1; page < (nand_data->pages_per_block * nand_data->planes); page++) { unsigned short cached_page; nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), SECTOR_SIZE, /* offset to first sector's spare */ 16, spare_buf); cached_page = get_cached_page_id(spare_buf); if (cached_page != 0xFFFF) write_caches[cache_no].page_map[cached_page] = page; } #endif /* !FTL_V1 */ }
static void read_inplace_writes_cache(int bank, int phys_segment) { int page = 0; short log_segment; unsigned char spare_buf[16]; nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), SECTOR_SIZE, /* offset to first sector's spare */ 16, spare_buf); log_segment = get_log_segment_id(phys_segment, spare_buf); if (log_segment == -1) return; /* Find which cache this is related to */ int cache_no = find_write_cache(log_segment); if (cache_no == -1) { if (write_caches_in_use < MAX_WRITE_CACHES) { cache_no = write_caches_in_use; write_caches_in_use++; } else { panicf("Max NAND write caches reached"); } } write_caches[cache_no].log_segment = log_segment; /* Find how many pages have been written to the new segment */ while (log_segment != -1 && page < (nand_data->pages_per_block * nand_data->planes) - 1) { page++; nand_read_raw(bank, phys_segment_to_page_addr(phys_segment, page), SECTOR_SIZE, 16, spare_buf); log_segment = get_log_segment_id(phys_segment, spare_buf); } if (page != 0) { write_caches[cache_no].inplace_bank = bank; write_caches[cache_no].inplace_phys_segment = phys_segment; write_caches[cache_no].inplace_pages_used = page; } }
static void nand_io_proc(void *arg, int pending) { struct nand_chip *chip = arg; struct bio *bp; int err = 0; for (;;) { mtx_lock(&chip->qlock); bp = bioq_takefirst(&chip->bioq); mtx_unlock(&chip->qlock); if (bp == NULL) break; if (bp->bio_driver1 == BIO_NAND_STD) { if (bp->bio_cmd == BIO_READ) { err = nand_read(chip, bp->bio_offset & 0xffffffff, bp->bio_data, bp->bio_bcount); } else if (bp->bio_cmd == BIO_WRITE) { err = nand_write(chip, bp->bio_offset & 0xffffffff, bp->bio_data, bp->bio_bcount); } } else if (bp->bio_driver1 == BIO_NAND_RAW) { if (bp->bio_cmd == BIO_READ) { err = nand_read_raw(chip, bp->bio_offset & 0xffffffff, bp->bio_data, bp->bio_bcount); } else if (bp->bio_cmd == BIO_WRITE) { err = nand_write_raw(chip, bp->bio_offset & 0xffffffff, bp->bio_data, bp->bio_bcount); } } else panic("Unknown access type in bio->bio_driver1\n"); if (bp->bio_cmd == BIO_DELETE) { nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " "length %ld\n", chip->num, bp->bio_offset, bp->bio_bcount); err = nand_erase_blocks(chip, bp->bio_offset & 0xffffffff, bp->bio_bcount); } if (err == 0 || err == ECC_CORRECTABLE) bp->bio_resid = 0; else { nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " "error: %d\n", err); bp->bio_error = EIO; bp->bio_flags |= BIO_ERROR; bp->bio_resid = bp->bio_bcount; } biodone(bp); } }
/* * The legacy NAND code saved the environment in the first NAND device i.e., * nand_dev_desc + 0. This is also the behaviour using the new NAND code. */ void env_relocate_spec (void) { #if !defined(ENV_IS_EMBEDDED) ulong total; int ret; #if defined(CFG_ENV_OFFSET_OOB) struct mtd_info *mtd = &nand_info[0]; struct nand_chip *this = mtd->priv; int buf_len; uint8_t *buf; buf_len = (1 << this->bbt_erase_shift); buf_len += (buf_len >> this->page_shift) * mtd->oobsize; buf = malloc(buf_len); if (!buf) return; nand_read_raw(mtd, buf, 0, mtd->oobblock, mtd->oobsize); if (buf[mtd->oobblock + 8 + 0] == 'E' && buf[mtd->oobblock + 8 + 1] == 'N' && buf[mtd->oobblock + 8 + 2] == 'V' && buf[mtd->oobblock + 8 + 3] == '0') { CFG_ENV_OFFSET = *((unsigned long *) &buf[mtd->oobblock + 8 + 4]); /* fall through to the normal environment reading code below */ free(buf); puts("Found Environment offset in OOB..\n"); } else { free(buf); return use_default(); } #endif total = CFG_ENV_SIZE; ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr); if (ret || total != CFG_ENV_SIZE) return use_default(); if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) return use_default(); #endif /* ! ENV_IS_EMBEDDED */ }
static void nand_get_chip_info(void) { unsigned char manuf_id; unsigned char id_buf[8]; /* Read chip id from bank 0 */ nand_read_id(0, id_buf); manuf_id = id_buf[0]; /* Identify the chip geometry */ nand_data = nand_identify(id_buf); if (nand_data == NULL) { panicf("Unknown NAND: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", id_buf[0],id_buf[1],id_buf[2],id_buf[3],id_buf[4]); } pages_per_bank = nand_data->blocks_per_bank * nand_data->pages_per_block; segments_per_bank = nand_data->blocks_per_bank / nand_data->planes; bytes_per_segment = nand_data->page_size * nand_data->pages_per_block * nand_data->planes; sectors_per_page = nand_data->page_size / SECTOR_SIZE; sectors_per_segment = bytes_per_segment / SECTOR_SIZE; pages_per_segment = sectors_per_segment / sectors_per_page; /* Establish how many banks are present */ nand_read_id(1, id_buf); if (id_buf[0] == manuf_id) { /* Bank 1 is populated, now check if banks 2/3 are valid */ nand_read_id(2, id_buf); if (id_buf[0] == manuf_id) { /* Bank 2 returned matching id - check if 2/3 are shadowing 0/1 */ unsigned int uid_buf0[8]; unsigned int uid_buf2[8]; nand_read_uid(0, uid_buf0); nand_read_uid(2, uid_buf2); if (memcmp(uid_buf0, uid_buf2, 32) == 0) { /* UIDs match, assume banks 2/3 are shadowing 0/1 */ total_banks = 2; } else { /* UIDs differ, assume banks 2/3 are valid */ total_banks = 4; } } else { /* Bank 2 returned differing id - assume 2/3 are junk */ total_banks = 2; } } else { /* Bank 1 returned differing id - assume it is junk */ total_banks = 1; } /* Sanity checks: 1. "BMP" tag at block 0, page 0, offset <page_size> [always present] 2. On most D2s, <page_size>+3 is 'M' and <page_size>+4 is no. of banks. This is not present on some older players (formatted with early FW?) */ nand_read_raw(0, 0, /* bank, page */ nand_data->page_size, /* offset */ 8, id_buf); /* length, dest */ if (strncmp(id_buf, "BMP", 3)) panicf("BMP tag not present"); if (id_buf[3] == 'M') { if (id_buf[4] != total_banks) panicf("BMPM total_banks mismatch"); } }