? nand.c.brett
? nand.c.good
? nand_id.c
Index: files.nand
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/files.nand,v
retrieving revision 1.5
diff -u -r1.5 files.nand
--- files.nand	31 Oct 2012 18:58:08 -0000	1.5
+++ files.nand	4 Nov 2012 16:48:21 -0000
@@ -10,6 +10,7 @@
 file	dev/nand/nand_crc.c	nand
 file	dev/nand/nand_micron.c	nand
 file	dev/nand/nand_samsung.c	nand
+file	dev/nand/nand_id.c	nand
 
 defpseudodev	nandemulator: nandbus
 file	dev/nand/nandemulator.c	nandemulator
Index: nand.c
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand.c,v
retrieving revision 1.22
diff -u -r1.22 nand.c
--- nand.c	3 Nov 2012 12:45:28 -0000	1.22
+++ nand.c	4 Nov 2012 16:48:21 -0000
@@ -73,6 +73,7 @@
 
 #ifdef NAND_DEBUG
 int	nanddebug = NAND_DEBUG;
+static void nand_chip_dump(struct nand_chip *);
 #endif
 
 struct flash_interface nand_flash_if = {
@@ -289,7 +290,7 @@
 	interface->write_buf_2 = NULL;
 	interface->write_1 = NULL;
 	interface->write_2 = NULL;
-	interface->busy = NULL;
+	interface->busy = &nand_default_busy;
 
 	/*-
 	 * most drivers dont want to change this, but some implement
@@ -332,10 +333,10 @@
 	switch (chip->nc_manf_id) {
 	case NAND_MFR_MICRON:
 		return nand_read_parameters_micron(self, chip);
-	case NAND_MFR_SAMSUNG:
-		return nand_read_parameters_samsung(self, chip);
+//	case NAND_MFR_SAMSUNG:
+//		return nand_read_parameters_samsung(self, chip);
 	default:
-		return 1;
+		return nand_match_parameters_legacy(self, chip);
 	}
 
 	return 0;
@@ -354,6 +355,7 @@
 
 	nand_select(self, true);
 	nand_command(self, ONFI_RESET);
+	delay(1000);		/* allow time for reset */
 	nand_select(self, false);
 
 	/* check if the device implements the ONFI standard */
@@ -474,6 +476,10 @@
 	/* look for quirks here if needed in future */
 	/* nand_quirks(self, chip); */
 
+#ifdef NAND_DEBUG
+	nand_chip_dump(chip);
+#endif
+
 	return 0;
 }
 
@@ -536,6 +542,7 @@
 	uint8_t	vendor[13], model[21];
 	int i;
 
+	/* Reminder: multibyte ONFI params as read are little endian */
 	if (nand_read_parameter_page(self, &params)) {
 		return 1;
 	}
@@ -574,6 +581,8 @@
 		chip->nc_flags |= NC_EXTENDED_PARAM;
 	}
 
+	chip->nc_read_time = le16toh(params.param_t_r);
+
 	return 0;
 }
 
@@ -628,6 +637,7 @@
 {
 	uint8_t status;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_READ_STATUS);
 	nand_busy(self);
 	nand_read_1(self, &status);
@@ -647,6 +657,8 @@
 static void
 nand_prepare_read(device_t self, flash_off_t row, flash_off_t column)
 {
+	/* chip select/deselect -- should be done by caller */
+
 	nand_command(self, ONFI_READ);
 	nand_address_column(self, row, column);
 	nand_command(self, ONFI_READ_START);
@@ -664,6 +676,7 @@
 	uint8_t *ecc;
 	int result;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_prepare_read(self, offset, 0);
 
 	bs = chip->nc_ecc->necc_block_size;
@@ -749,13 +762,15 @@
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
 	size_t bs, cs, e, b;
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 	uint8_t *ecc;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_PAGE_PROGRAM);
 	nand_address_column(self, page, 0);
 
-	nand_busy(self);
+	nand_busy(self);	/* XXXX why here ? */
 
 	bs = chip->nc_ecc->necc_block_size;
 	cs = chip->nc_ecc->necc_code_size;
@@ -785,7 +800,29 @@
 
 	nand_command(self, ONFI_PAGE_PROGRAM_START);
 
-	nand_busy(self);
+//	if (sc->nand_if->busy == NULL) {
+	if (1) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_default_program_page() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
 
 	/* for debugging ecc */
 #if 0
@@ -800,7 +837,6 @@
 	printf("--------------\n");
 #endif
 
-	status = nand_get_status(self);
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL) {
 		aprint_error_dev(self, "page program failed!\n");
@@ -817,6 +853,7 @@
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_prepare_read(self, page, chip->nc_page_size);
 
 	if (chip->nc_flags & NC_BUSWIDTH_16)
@@ -837,20 +874,43 @@
 {
 	struct nand_softc *sc = device_private(self);
 	struct nand_chip *chip = &sc->sc_chip;
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_PAGE_PROGRAM);
 	nand_address_column(self, offset, chip->nc_page_size);
-	nand_command(self, ONFI_PAGE_PROGRAM_START);
-
-	nand_busy(self);
 
 	if (chip->nc_flags & NC_BUSWIDTH_16)
 		nand_write_buf_2(self, oob, chip->nc_spare_size);
 	else
 		nand_write_buf_1(self, oob, chip->nc_spare_size);
 
-	status = nand_get_status(self);
+	nand_command(self, ONFI_PAGE_PROGRAM_START);
+
+	if (sc->nand_if->busy == NULL) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_write_oob() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
+
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL)
 		return EIO;
@@ -987,17 +1047,40 @@
 int
 nand_erase_block(device_t self, size_t offset)
 {
+	struct nand_softc *sc = device_private(self);
+	int timeout = 1000000;	/* XXXXbds what is good here ? */
 	uint8_t status;
 
 	/* xxx calculate first page of block for address? */
 
+	/* XXXXbds missing chip select/deselect */
 	nand_command(self, ONFI_BLOCK_ERASE);
 	nand_address_row(self, offset);
 	nand_command(self, ONFI_BLOCK_ERASE_START);
 
-	nand_busy(self);
+	if (sc->nand_if->busy == NULL) {
+		/*
+		 * no hardware status line -- loop checking status till
+		 * ready or timeout
+		 */
+		while (timeout) {
+			nand_command(self, ONFI_READ_STATUS);
+			delay(1);
+			nand_read_1(self, &status);
+			if (status & ONFI_STATUS_RDY)
+				break;
+			timeout--;
+		}
+		if (timeout == 0) {
+			aprint_error_dev(self,
+			    "nand_erase_block() chip timeout!\n");
+		}
+	}
+	else {
+		nand_busy(self);
+		status = nand_get_status(self);
+	}
 
-	status = nand_get_status(self);
 	KASSERT(status & ONFI_STATUS_RDY);
 	if (status & ONFI_STATUS_FAIL) {
 		aprint_error_dev(self, "block erase failed!\n");
@@ -1033,6 +1116,28 @@
 	return;
 }
 
+void
+nand_default_busy(device_t self)
+{
+	struct nand_softc *sc = device_private(self);
+
+	switch (sc->sc_last_command) {
+	case ONFI_READ:
+	case ONFI_READ_START:
+		delay(sc->sc_chip.nc_read_time);
+		break;
+	case ONFI_READ_PARAMETER_PAGE:
+		/*
+		 * ONFI specifies an initial tR of 200 us for
+		 * reading the parameter page.
+		 */
+		delay(200);
+		break;
+	default:
+		break;
+	}
+}
+
 /* implementation of the block device API */
 
 int
@@ -1521,3 +1626,34 @@
 		return ENOTTY;
 	}
 }
+
+#ifdef NAND_DEBUG
+static void
+nand_chip_dump(struct nand_chip *chip)
+{
+	printf("nc_ecc\t*%p\n",chip->nc_ecc);
+	printf("nc_oob_cache\t*%p\n",chip->nc_oob_cache);
+	printf("nc_page_cache\t*%p\n",chip->nc_page_cache);
+	printf("nc_ecc_cache\t*%p\n",chip->nc_ecc_cache);
+	printf("nc_size\t%" PRIu64 "\n",chip->nc_size);
+	printf("nc_page_size\t%" PRIu32 "\n",chip->nc_page_size);
+	printf("nc_block_size\t%" PRIu32 "\n",chip->nc_block_size);
+	printf("nc_spare_size\t%" PRIu32 "\n",chip->nc_spare_size);
+	printf("nc_lun_blocks\t%" PRIu32 "\n",chip->nc_lun_blocks);
+	printf("nc_flags\t0x%" PRIx32 "\n",chip->nc_flags);
+	printf("nc_quirks\t0x%" PRIx32 "\n",chip->nc_quirks);
+	printf("nc_page_shift\t0x%" PRIx32 "\n",chip->nc_page_shift);
+	printf("nc_page_mask\t0x%" PRIx32 "\n",chip->nc_page_mask);
+	printf("nc_block_shift\t0x%" PRIx32 "\n",chip->nc_block_shift);
+	printf("nc_block_mask\t0x%" PRIx32 "\n",chip->nc_block_mask);
+	printf("nc_num_luns\t%hhu\n",chip->nc_num_luns);
+	printf("nc_manf_id\t%#hhx\n",chip->nc_manf_id);
+	printf("nc_dev_id\t%#hhx\n",chip->nc_dev_id);
+	printf("nc_addr_cycles_row\t%hhu\n",chip->nc_addr_cycles_row);
+	printf("nc_addr_cycles_column\t%hhu\n",chip->nc_addr_cycles_column);
+	printf("nc_badmarker_offs\t%hhu\n",chip->nc_badmarker_offs);
+	printf("nc_isonfi\t%s\n",chip->nc_isonfi?"true":"false");
+	printf("nc_read_time\t%u\n",chip->nc_read_time);
+	printf("chip pointer:\t%p\n",chip);
+}
+#endif
Index: nand.h
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand.h,v
retrieving revision 1.16
diff -u -r1.16 nand.h
--- nand.h	3 Nov 2012 12:12:48 -0000	1.16
+++ nand.h	4 Nov 2012 16:48:21 -0000
@@ -129,6 +129,9 @@
 	uint8_t nc_addr_cycles_column;	/* column cycles for addressing */
 	uint8_t nc_badmarker_offs;	/* offset for marking bad blocks */
 	bool nc_isonfi;			/* if the device is onfi compliant */
+	uint16_t nc_read_time;		/* chip maximum read time tR (us) */
+	uint16_t nc_prog_time;		/* chip max page program time (us) */
+	uint16_t nc_block_erase_time;	/* chip max block erase time (us) */
 };
 
 struct nand_write_cache {
@@ -155,6 +158,7 @@
 	size_t sc_part_offset;
 	size_t sc_part_size;
 	kmutex_t sc_device_lock; /* serialize access to chip */
+	uint8_t sc_last_command; /* last command issued */
 	struct flash_io sc_flash_io;
 };
 
@@ -197,6 +201,17 @@
 	struct nand_interface *naa_nand_if;
 };
 
+/*
+ * default functions for driver development
+ */
+void nand_default_select(device_t, bool);
+int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
+int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
+    const uint8_t *);
+int nand_default_read_page(device_t, size_t, uint8_t *);
+int nand_default_program_page(device_t, size_t, const uint8_t *);
+void nand_default_busy(device_t);
+
 static inline void
 nand_busy(device_t device)
 {
@@ -207,9 +222,10 @@
 
 	sc->nand_if->select(sc->controller_dev, true);
 
-	if (sc->nand_if->busy != NULL) {
+	if (sc->nand_if->busy != &nand_default_busy)
 		sc->nand_if->busy(sc->controller_dev);
-	}
+	else
+		sc->nand_if->busy(device);
 
 	sc->nand_if->select(sc->controller_dev, false);
 }
@@ -245,6 +261,7 @@
 	KASSERT(sc->controller_dev != NULL);
 
 	sc->nand_if->command(sc->controller_dev, command);
+	sc->sc_last_command = command;
 }
 
 static inline void
@@ -429,6 +446,12 @@
 int nand_read_parameters_micron(device_t, struct nand_chip *);
 int nand_read_parameters_samsung(device_t, struct nand_chip *);
 
+/* match out of legacy device table */
+int nand_match_parameters_legacy(device_t, struct nand_chip *);
+
+/* match out of legacy device table */
+int nand_match_parameters_legacy(device_t, struct nand_chip *);
+
 /* debug inlines */
 
 static inline void
@@ -472,16 +495,6 @@
 void nand_read_id(device_t, uint8_t *, uint8_t *);
 int nand_read_parameter_page(device_t, struct onfi_parameter_page *);
 
-/*
- * default functions for driver development
- */
-void nand_default_select(device_t, bool);
-int nand_default_ecc_compute(device_t, const uint8_t *, uint8_t *);
-int nand_default_ecc_correct(device_t, uint8_t *, const uint8_t *,
-    const uint8_t *);
-int nand_default_read_page(device_t, size_t, uint8_t *);
-int nand_default_program_page(device_t, size_t, const uint8_t *);
-
 static inline void nand_busy(device_t);
 static inline void nand_select(device_t, bool);
 static inline void nand_command(device_t, uint8_t);
Index: nand_samsung.c
===================================================================
RCS file: /cvsroot/src/sys/dev/nand/nand_samsung.c,v
retrieving revision 1.9
diff -u -r1.9 nand_samsung.c
--- nand_samsung.c	3 Nov 2012 12:12:48 -0000	1.9
+++ nand_samsung.c	4 Nov 2012 16:48:21 -0000
@@ -81,6 +81,9 @@
 	aprint_debug_dev(self,
 	    "ID Definition table: 0x%2.x 0x%2.x 0x%2.x 0x%2.x 0x%2.x\n",
 	    mfgrid, devid, params1, params2, params3);
+	printf(
+	    "ID Definition table: 0x%2.x 0x%2.x 0x%2.x 0x%2.x 0x%2.x\n",
+	    mfgrid, devid, params1, params2, params3);
 
 	/* K9XXG08UXA */
 	if (devid == 0xdc) {
