Пример #1
0
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 */
}
Пример #2
0
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;
    }
}
Пример #3
0
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);
	}
}
Пример #4
0
/*
 * 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 */
}
Пример #5
0
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");
    }
}