diff --git a/dummyflasher.c b/dummyflasher.c
index 99f81f5f74052e4e8759da2ba139a8c4af4870f4..6281ff898f4d7572ab2efac901349d074d77d18e 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -19,6 +19,8 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
 #include "flash.h"
 #include "chipdrivers.h"
 #include "programmer.h"
@@ -55,6 +57,10 @@ static unsigned int emu_jedec_be_52_size = 0;
 static unsigned int emu_jedec_be_d8_size = 0;
 static unsigned int emu_jedec_ce_60_size = 0;
 static unsigned int emu_jedec_ce_c7_size = 0;
+unsigned char spi_blacklist[256];
+unsigned char spi_ignorelist[256];
+int spi_blacklist_size = 0;
+int spi_ignorelist_size = 0;
 #endif
 #endif
 
@@ -126,6 +132,7 @@ int dummy_init(void)
 {
 	char *bustext = NULL;
 	char *tmp = NULL;
+	int i;
 #if EMULATE_CHIP
 	struct stat image_stat;
 #endif
@@ -170,6 +177,68 @@ int dummy_init(void)
 		}
 	}
 
+	tmp = extract_programmer_param("spi_blacklist");
+	if (tmp) {
+		i = strlen(tmp);
+		if (!strncmp(tmp, "0x", 2)) {
+			i -= 2;
+			memmove(tmp, tmp + 2, i + 1);
+		}
+		if ((i > 512) || (i % 2)) {
+			msg_perr("Invalid SPI command blacklist length\n");
+			free(tmp);
+			return 1;
+		}
+		spi_blacklist_size = i / 2;
+		for (i = 0; i < spi_blacklist_size * 2; i++) {
+			if (!isxdigit((unsigned char)tmp[i])) {
+				msg_perr("Invalid char \"%c\" in SPI command "
+					 "blacklist\n", tmp[i]);
+				free(tmp);
+				return 1;
+			}
+		}
+		for (i = 0; i < spi_blacklist_size; i++) {
+			sscanf(tmp + i * 2, "%2hhx", &spi_blacklist[i]);
+		}
+		msg_pdbg("SPI blacklist is ");
+		for (i = 0; i < spi_blacklist_size; i++)
+			msg_pdbg("%02x ", spi_blacklist[i]);
+		msg_pdbg(", size %i\n", spi_blacklist_size);
+	}
+	free(tmp);
+
+	tmp = extract_programmer_param("spi_ignorelist");
+	if (tmp) {
+		i = strlen(tmp);
+		if (!strncmp(tmp, "0x", 2)) {
+			i -= 2;
+			memmove(tmp, tmp + 2, i + 1);
+		}
+		if ((i > 512) || (i % 2)) {
+			msg_perr("Invalid SPI command ignorelist length\n");
+			free(tmp);
+			return 1;
+		}
+		spi_ignorelist_size = i / 2;
+		for (i = 0; i < spi_ignorelist_size * 2; i++) {
+			if (!isxdigit((unsigned char)tmp[i])) {
+				msg_perr("Invalid char \"%c\" in SPI command "
+					 "ignorelist\n", tmp[i]);
+				free(tmp);
+				return 1;
+			}
+		}
+		for (i = 0; i < spi_ignorelist_size; i++) {
+			sscanf(tmp + i * 2, "%2hhx", &spi_ignorelist[i]);
+		}
+		msg_pdbg("SPI ignorelist is ");
+		for (i = 0; i < spi_ignorelist_size; i++)
+			msg_pdbg("%02x ", spi_ignorelist[i]);
+		msg_pdbg(", size %i\n", spi_ignorelist_size);
+	}
+	free(tmp);
+
 #if EMULATE_CHIP
 	tmp = extract_programmer_param("emulate");
 	if (!tmp) {
@@ -348,7 +417,7 @@ static int emulate_spi_chip_response(unsigned int writecnt,
 				     const unsigned char *writearr,
 				     unsigned char *readarr)
 {
-	unsigned int offs;
+	unsigned int offs, i;
 	static int unsigned aai_offs;
 	static int aai_active = 0;
 
@@ -356,7 +425,24 @@ static int emulate_spi_chip_response(unsigned int writecnt,
 		msg_perr("No command sent to the chip!\n");
 		return 1;
 	}
-	/* TODO: Implement command blacklists here. */
+	/* spi_blacklist has precedence before spi_ignorelist. */
+	for (i = 0; i < spi_blacklist_size; i++) {
+		if (writearr[0] == spi_blacklist[i]) {
+			msg_pdbg("Refusing blacklisted SPI command 0x%02x\n",
+				 spi_blacklist[i]);
+			return SPI_INVALID_OPCODE;
+		}
+	}
+	for (i = 0; i < spi_ignorelist_size; i++) {
+		if (writearr[0] == spi_ignorelist[i]) {
+			msg_cdbg("Ignoring ignorelisted SPI command 0x%02x\n",
+				 spi_ignorelist[i]);
+			/* Return success because the command does not fail,
+			 * it is simply ignored.
+			 */
+			return 0;
+		}
+	}
 	switch (writearr[0]) {
 	case JEDEC_RES:
 		if (emu_chip != EMULATE_ST_M25P10_RES)
@@ -563,7 +649,7 @@ static int dummy_spi_send_command(struct flashctx *flash, unsigned int writecnt,
 	case EMULATE_SST_SST25VF032B:
 		if (emulate_spi_chip_response(writecnt, readcnt, writearr,
 					      readarr)) {
-			msg_perr("Invalid command sent to flash chip!\n");
+			msg_pdbg("Invalid command sent to flash chip!\n");
 			return 1;
 		}
 		break;
diff --git a/flashrom.8 b/flashrom.8
index 6b25b43dc72e4b6276f5d0453f91003305105395..2f23cb80c72cf005c2a521dc7bcdb8b9983d1ad4 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -421,6 +421,28 @@ is the number of bytes (min. 1, max. 256).
 Example:
 .sp
 .B "  flashrom -p dummy:emulate=M25P10.RES,spi_write_256_chunksize=5"
+.sp
+To simulate a programmer which refuses to send certain SPI commands to the
+flash chip, you can specify a blacklist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_blacklist=commandlist"
+.sp
+syntax where commandlist is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, flashrom will behave as if the SPI
+controller refuses to run command 0x03 (READ) and command 0x02 (WRITE).
+commandlist may be up to 512 characters (256 commands) long.
+Implementation note: flashrom will detect an error during command execution.
+.sp
+To simulate a flash chip which ignores (doesn't support) certain SPI commands,
+you can specify an ignorelist of SPI commands with the
+.sp
+.B "  flashrom -p dummy:spi_ignorelist=commandlist"
+.sp
+syntax where commandlist is a list of two-digit hexadecimal representations of
+SPI commands. If commandlist is e.g. 0302, the emulated flash chip will ignore
+command 0x03 (READ) and command 0x02 (WRITE).  commandlist may be up to 512
+characters (256 commands) long.
+Implementation note: flashrom won't detect an error during command execution.
 .TP
 .BR "nic3com" , " nicrealtek" , " nicsmc1211" , " nicnatsemi" , " nicintel\
 " , " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii\