vpnor: implement init_flash_dev

The vpnor version needs to set the erase block size as 4K.
That's the size hostboot expects in the FFS structure.

This change also requires moving code from mboxd_flash.c to
mboxd_flash_physical.c, else there will be 3 symbols per flash function.

It should suffice to just have mboxd_flash_physical.c and
mboxd_flash_virtual.cpp.

Change-Id: I35442a0c1dbee7f66b278cbf094be78e870b6c86
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 4e59529..59146ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,6 @@
 	mboxd.c \
 	common.c \
 	mboxd_dbus.c \
-	mboxd_flash.c \
 	mboxd_lpc.c \
 	mboxd_msg.c \
 	mboxd_windows.c \
@@ -42,21 +41,18 @@
 
 test_copy_flash_SOURCES = \
 	test/copy_flash.c \
-	mboxd_flash.c \
 	mboxd_flash_physical.c \
 	common.c mtd.c \
 	test/tmpf.c
 
 test_erase_flash_SOURCES = \
 	test/erase_flash.c \
-	mboxd_flash.c \
 	mboxd_flash_physical.c \
 	common.c \
 	test/tmpf.c
 
 test_write_flash_SOURCES = \
 	test/write_flash.c \
-	mboxd_flash.c \
 	mboxd_flash_physical.c \
 	common.c \
 	test/tmpf.c
@@ -65,7 +61,6 @@
 	mboxd_msg.c \
 	mboxd_windows.c \
 	mboxd_lpc.c \
-	mboxd_flash.c \
 	common.c \
 	mboxd_flash_physical.c
 
@@ -153,7 +148,6 @@
 	mboxd_msg.c \
 	mboxd_windows.c \
 	mboxd_lpc.c \
-	mboxd_flash.c \
 	mboxd_pnor_partition_table.cpp \
 	mboxd_flash_virtual.cpp \
 	pnor_partition.cpp \
@@ -166,7 +160,6 @@
 
 test_write_flash_vpnor_SOURCES = \
 	$(TEST_MBOX_VPNOR_SRCS) \
-	mboxd_flash.c \
 	mboxd_pnor_partition_table.cpp \
 	mboxd_flash_virtual.cpp \
 	mtd.c \
diff --git a/mboxd_flash.c b/mboxd_flash.c
deleted file mode 100644
index 4b6c1f7..0000000
--- a/mboxd_flash.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Mailbox Daemon Flash Helpers
- *
- * Copyright 2016 IBM
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define _GNU_SOURCE
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/timerfd.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <mtd/mtd-abi.h>
-
-#include "mbox.h"
-#include "common.h"
-#include "mboxd_flash.h"
-
-int init_flash_dev(struct mbox_context *context)
-{
-	char *filename = get_dev_mtd();
-	int fd, rc = 0;
-
-	if (!filename) {
-		MSG_ERR("Couldn't find the PNOR /dev/mtd partition\n");
-		return -1;
-	}
-
-	MSG_DBG("Opening %s\n", filename);
-
-	/* Open Flash Device */
-	fd = open(filename, O_RDWR);
-	if (fd < 0) {
-		MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
-			filename, strerror(errno));
-		rc = -errno;
-		goto out;
-	}
-	context->fds[MTD_FD].fd = fd;
-
-	/* Read the Flash Info */
-	if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1) {
-		MSG_ERR("Couldn't get information about MTD: %s\n",
-			strerror(errno));
-		rc = -1;
-		goto out;
-	}
-
-	if (context->flash_size == 0) {
-		/*
-		 * PNOR images for current OpenPOWER systems are at most 64MB
-		 * despite the PNOR itself sometimes being as big as 128MB. To
-		 * ensure the image read from the PNOR is exposed in the LPC
-		 * address space at the location expected by the host firmware,
-		 * it is required that the image size be used for
-		 * context->flash_size, and not the size of the flash device.
-		 *
-		 * However, the test cases specify the flash size via special
-		 * test APIs (controlling flash behaviour) which don't have
-		 * access to the mbox context. Rather than requiring
-		 * error-prone assignments in every test case, we instead rely
-		 * on context->flash_size being set to the size reported by the
-		 * MEMINFO ioctl().
-		 *
-		 * As this case should never be hit in production (i.e. outside
-		 * the test environment), log an error. As a consequence, this
-		 * error is expected in the test case output.
-		 */
-		MSG_ERR("Flash size MUST be supplied on the commandline. However, continuing by assuming flash is %u bytes\n",
-				context->mtd_info.size);
-		context->flash_size = context->mtd_info.size;
-	}
-
-	/* We know the erase size so we can allocate the flash_erased bytemap */
-	context->erase_size_shift = log_2(context->mtd_info.erasesize);
-	context->flash_bmap = calloc(context->flash_size >>
-				     context->erase_size_shift,
-				     sizeof(*context->flash_bmap));
-	MSG_DBG("Flash erase size: 0x%.8x\n", context->mtd_info.erasesize);
-
-out:
-	free(filename);
-	return rc;
-}
-
-void free_flash_dev(struct mbox_context *context)
-{
-	free(context->flash_bmap);
-	close(context->fds[MTD_FD].fd);
-}
-
-/* Flash Functions */
-
-/*
- * flash_is_erased() - Check if an offset into flash is erased
- * @context:	The mbox context pointer
- * @offset:	The flash offset to check (bytes)
- *
- * Return:	true if erased otherwise false
- */
-static inline bool flash_is_erased(struct mbox_context *context,
-				   uint32_t offset)
-{
-	return context->flash_bmap[offset >> context->erase_size_shift]
-			== FLASH_ERASED;
-}
-
-/*
- * set_flash_bytemap() - Set the flash erased bytemap
- * @context:	The mbox context pointer
- * @offset:	The flash offset to set (bytes)
- * @count:	Number of bytes to set
- * @val:	Value to set the bytemap to
- *
- * The flash bytemap only tracks the erased status at the erase block level so
- * this will update the erased state for an (or many) erase blocks
- *
- * Return:	0 if success otherwise negative error code
- */
-int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
-		      uint32_t count, uint8_t val)
-{
-	if ((offset + count) > context->flash_size) {
-		return -MBOX_R_PARAM_ERROR;
-	}
-
-	MSG_DBG("Set flash bytemap @ 0x%.8x for 0x%.8x to %s\n",
-		offset, count, val ? "ERASED" : "DIRTY");
-	memset(context->flash_bmap + (offset >> context->erase_size_shift),
-	       val,
-	       align_up(count, 1 << context->erase_size_shift) >>
-	       context->erase_size_shift);
-
-	return 0;
-}
-
-/*
- * erase_flash() - Erase the flash
- * @context:	The mbox context pointer
- * @offset:	The flash offset to erase (bytes)
- * @size:	The number of bytes to erase
- *
- * Return:	0 on success otherwise negative error code
- */
-int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
-{
-	const uint32_t erase_size = 1 << context->erase_size_shift;
-	struct erase_info_user erase_info = { 0 };
-	int rc;
-
-	MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count);
-
-	/*
-	 * We have an erased_bytemap for the flash so we want to avoid erasing
-	 * blocks which we already know to be erased. Look for runs of blocks
-	 * which aren't erased and erase the entire run at once to avoid how
-	 * often we have to call the erase ioctl. If the block is already
-	 * erased then there's nothing we need to do.
-	 */
-	while (count) {
-		if (!flash_is_erased(context, offset)) { /* Need to erase */
-			if (!erase_info.length) { /* Start of not-erased run */
-				erase_info.start = offset;
-			}
-			erase_info.length += erase_size;
-		} else if (erase_info.length) { /* Already erased|end of run? */
-			/* Erase the previous run which just ended */
-			MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
-				erase_info.start, erase_info.length);
-			rc = ioctl(context->fds[MTD_FD].fd, MEMERASE,
-				   &erase_info);
-			if (rc < 0) {
-				MSG_ERR("Couldn't erase flash at 0x%.8x\n",
-						erase_info.start);
-				return -MBOX_R_SYSTEM_ERROR;
-			}
-			/* Mark ERASED where we just erased */
-			set_flash_bytemap(context, erase_info.start,
-					  erase_info.length, FLASH_ERASED);
-			erase_info.start = 0;
-			erase_info.length = 0;
-		}
-
-		offset += erase_size;
-		count -= erase_size;
-	}
-
-	if (erase_info.length) {
-		MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
-			erase_info.start, erase_info.length);
-		rc = ioctl(context->fds[MTD_FD].fd, MEMERASE, &erase_info);
-		if (rc < 0) {
-			MSG_ERR("Couldn't erase flash at 0x%.8x\n",
-					erase_info.start);
-			return -MBOX_R_SYSTEM_ERROR;
-		}
-		/* Mark ERASED where we just erased */
-		set_flash_bytemap(context, erase_info.start, erase_info.length,
-				  FLASH_ERASED);
-	}
-
-	return 0;
-}
diff --git a/mboxd_flash_physical.c b/mboxd_flash_physical.c
index 16f2363..55624d9 100644
--- a/mboxd_flash_physical.c
+++ b/mboxd_flash_physical.c
@@ -18,11 +18,27 @@
  */
 
 #define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <syslog.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/timerfd.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
+#include <inttypes.h>
 #include <errno.h>
 #include <mtd/mtd-abi.h>
 
@@ -30,6 +46,192 @@
 #include "common.h"
 #include "mboxd_flash.h"
 
+int init_flash_dev(struct mbox_context *context)
+{
+	char *filename = get_dev_mtd();
+	int fd, rc = 0;
+
+	if (!filename) {
+		MSG_ERR("Couldn't find the PNOR /dev/mtd partition\n");
+		return -1;
+	}
+
+	MSG_DBG("Opening %s\n", filename);
+
+	/* Open Flash Device */
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
+			filename, strerror(errno));
+		rc = -errno;
+		goto out;
+	}
+	context->fds[MTD_FD].fd = fd;
+
+	/* Read the Flash Info */
+	if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1) {
+		MSG_ERR("Couldn't get information about MTD: %s\n",
+			strerror(errno));
+		rc = -1;
+		goto out;
+	}
+
+	if (context->flash_size == 0) {
+		/*
+		 * PNOR images for current OpenPOWER systems are at most 64MB
+		 * despite the PNOR itself sometimes being as big as 128MB. To
+		 * ensure the image read from the PNOR is exposed in the LPC
+		 * address space at the location expected by the host firmware,
+		 * it is required that the image size be used for
+		 * context->flash_size, and not the size of the flash device.
+		 *
+		 * However, the test cases specify the flash size via special
+		 * test APIs (controlling flash behaviour) which don't have
+		 * access to the mbox context. Rather than requiring
+		 * error-prone assignments in every test case, we instead rely
+		 * on context->flash_size being set to the size reported by the
+		 * MEMINFO ioctl().
+		 *
+		 * As this case should never be hit in production (i.e. outside
+		 * the test environment), log an error. As a consequence, this
+		 * error is expected in the test case output.
+		 */
+		MSG_ERR("Flash size MUST be supplied on the commandline. However, continuing by assuming flash is %u bytes\n",
+				context->mtd_info.size);
+		context->flash_size = context->mtd_info.size;
+	}
+
+	/* We know the erase size so we can allocate the flash_erased bytemap */
+	context->erase_size_shift = log_2(context->mtd_info.erasesize);
+	context->flash_bmap = calloc(context->flash_size >>
+				     context->erase_size_shift,
+				     sizeof(*context->flash_bmap));
+	MSG_DBG("Flash erase size: 0x%.8x\n", context->mtd_info.erasesize);
+
+out:
+	free(filename);
+	return rc;
+}
+
+void free_flash_dev(struct mbox_context *context)
+{
+	free(context->flash_bmap);
+	close(context->fds[MTD_FD].fd);
+}
+
+/* Flash Functions */
+
+/*
+ * flash_is_erased() - Check if an offset into flash is erased
+ * @context:	The mbox context pointer
+ * @offset:	The flash offset to check (bytes)
+ *
+ * Return:	true if erased otherwise false
+ */
+static inline bool flash_is_erased(struct mbox_context *context,
+				   uint32_t offset)
+{
+	return context->flash_bmap[offset >> context->erase_size_shift]
+			== FLASH_ERASED;
+}
+
+/*
+ * set_flash_bytemap() - Set the flash erased bytemap
+ * @context:	The mbox context pointer
+ * @offset:	The flash offset to set (bytes)
+ * @count:	Number of bytes to set
+ * @val:	Value to set the bytemap to
+ *
+ * The flash bytemap only tracks the erased status at the erase block level so
+ * this will update the erased state for an (or many) erase blocks
+ *
+ * Return:	0 if success otherwise negative error code
+ */
+int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
+		      uint32_t count, uint8_t val)
+{
+	if ((offset + count) > context->flash_size) {
+		return -MBOX_R_PARAM_ERROR;
+	}
+
+	MSG_DBG("Set flash bytemap @ 0x%.8x for 0x%.8x to %s\n",
+		offset, count, val ? "ERASED" : "DIRTY");
+	memset(context->flash_bmap + (offset >> context->erase_size_shift),
+	       val,
+	       align_up(count, 1 << context->erase_size_shift) >>
+	       context->erase_size_shift);
+
+	return 0;
+}
+
+/*
+ * erase_flash() - Erase the flash
+ * @context:	The mbox context pointer
+ * @offset:	The flash offset to erase (bytes)
+ * @size:	The number of bytes to erase
+ *
+ * Return:	0 on success otherwise negative error code
+ */
+int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
+{
+	const uint32_t erase_size = 1 << context->erase_size_shift;
+	struct erase_info_user erase_info = { 0 };
+	int rc;
+
+	MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count);
+
+	/*
+	 * We have an erased_bytemap for the flash so we want to avoid erasing
+	 * blocks which we already know to be erased. Look for runs of blocks
+	 * which aren't erased and erase the entire run at once to avoid how
+	 * often we have to call the erase ioctl. If the block is already
+	 * erased then there's nothing we need to do.
+	 */
+	while (count) {
+		if (!flash_is_erased(context, offset)) { /* Need to erase */
+			if (!erase_info.length) { /* Start of not-erased run */
+				erase_info.start = offset;
+			}
+			erase_info.length += erase_size;
+		} else if (erase_info.length) { /* Already erased|end of run? */
+			/* Erase the previous run which just ended */
+			MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
+				erase_info.start, erase_info.length);
+			rc = ioctl(context->fds[MTD_FD].fd, MEMERASE,
+				   &erase_info);
+			if (rc < 0) {
+				MSG_ERR("Couldn't erase flash at 0x%.8x\n",
+						erase_info.start);
+				return -MBOX_R_SYSTEM_ERROR;
+			}
+			/* Mark ERASED where we just erased */
+			set_flash_bytemap(context, erase_info.start,
+					  erase_info.length, FLASH_ERASED);
+			erase_info.start = 0;
+			erase_info.length = 0;
+		}
+
+		offset += erase_size;
+		count -= erase_size;
+	}
+
+	if (erase_info.length) {
+		MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
+			erase_info.start, erase_info.length);
+		rc = ioctl(context->fds[MTD_FD].fd, MEMERASE, &erase_info);
+		if (rc < 0) {
+			MSG_ERR("Couldn't erase flash at 0x%.8x\n",
+					erase_info.start);
+			return -MBOX_R_SYSTEM_ERROR;
+		}
+		/* Mark ERASED where we just erased */
+		set_flash_bytemap(context, erase_info.start, erase_info.length,
+				  FLASH_ERASED);
+	}
+
+	return 0;
+}
+
 #define CHUNKSIZE (64 * 1024)
 
 /*
diff --git a/mboxd_flash_virtual.cpp b/mboxd_flash_virtual.cpp
index 3c83f02..6e3af71 100644
--- a/mboxd_flash_virtual.cpp
+++ b/mboxd_flash_virtual.cpp
@@ -23,6 +23,7 @@
 #include <syslog.h>
 #include <sys/mman.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
 
 extern "C" {
 #include "common.h"
@@ -36,10 +37,87 @@
 #include <phosphor-logging/log.hpp>
 #include <phosphor-logging/elog-errors.hpp>
 
+#include <memory>
 #include <string>
 #include <exception>
 #include <stdexcept>
 
+/** @brief unique_ptr functor to release a char* reference. */
+struct StringDeleter
+{
+    void operator()(char* ptr) const
+    {
+        free(ptr);
+    }
+};
+using StringPtr = std::unique_ptr<char, StringDeleter>;
+
+int init_flash_dev(struct mbox_context *context)
+{
+    StringPtr filename(get_dev_mtd());
+    int fd = 0;
+    int rc = 0;
+
+    if (!filename)
+    {
+        MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
+        return -1;
+    }
+
+    MSG_DBG("Opening %s\n", filename.get());
+
+    fd = open(filename.get(), O_RDWR);
+    if (fd < 0)
+    {
+        MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
+                filename.get(), strerror(errno));
+        return -errno;
+    }
+
+    // Read the Flash Info
+    if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
+    {
+        MSG_ERR("Couldn't get information about MTD: %s\n",
+                strerror(errno));
+        close(fd);
+        return -errno;
+    }
+
+    if (context->flash_size == 0)
+    {
+        // See comment in mboxd_flash_physical.c on why
+        // this is needed.
+        context->flash_size = context->mtd_info.size;
+    }
+
+    // Hostboot requires a 4K block-size to be used in the FFS flash structure
+    context->mtd_info.erasesize = 4096;
+    context->erase_size_shift = log_2(context->mtd_info.erasesize);
+    context->flash_bmap = NULL;
+    context->fds[MTD_FD].fd = -1;
+
+    close(fd);
+    return rc;
+}
+
+void free_flash_dev(struct mbox_context *context)
+{
+    // No-op
+}
+
+int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
+                      uint32_t count, uint8_t val)
+{
+    // No-op
+    return 0;
+}
+
+int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
+{
+    // No-op
+    return 0;
+}
+
 /*
  * copy_flash() - Copy data from the virtual pnor into a provided buffer
  * @context:    The mbox context pointer