diff --git a/avrdude/avr.c b/avrdude/avr.c
index 8df586a..fa46f49 100644
--- a/avrdude/avr.c
+++ b/avrdude/avr.c
@@ -438,11 +438,15 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
     {
       rc = pgm->read_byte(pgm, p, mem, i, mem->buf + i);
       if (rc != 0) {
-	avrdude_message(MSG_INFO, "avr_read(): error reading address 0x%04lx\n", i);
-	if (rc == -1)
-	  avrdude_message(MSG_INFO, "    read operation not supported for memory \"%s\"\n",
+        avrdude_message(MSG_INFO, "avr_read(): error reading address 0x%04lx\n", i);
+        if (rc == -1) {
+          avrdude_message(MSG_INFO, "    read operation not supported for memory \"%s\"\n",
                           memtype);
-	return -2;
+          return -2;
+        }
+        avrdude_message(MSG_INFO, "    read operation failed for memory \"%s\"\n",
+                        memtype);
+        return rc;
       }
     }
     report_progress(i, mem->size, NULL);
@@ -1051,7 +1055,7 @@ int avr_signature(PROGRAMMER * pgm, AVRPART * p)
   if (rc < 0) {
     avrdude_message(MSG_INFO, "%s: error reading signature data for part \"%s\", rc=%d\n",
                     progname, p->desc, rc);
-    return -1;
+    return rc;
   }
   report_progress (1,1,NULL);
 
diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y
index 21dccb0..0b50064 100644
--- a/avrdude/config_gram.y
+++ b/avrdude/config_gram.y
@@ -80,6 +80,7 @@ static int pin_name;
 %token K_DEFAULT_SAFEMODE
 %token K_DEFAULT_SERIAL
 %token K_DESC
+%token K_FAMILY_ID
 %token K_DEVICECODE
 %token K_STK500_DEVCODE
 %token K_AVR910_DEVCODE
@@ -676,6 +677,13 @@ part_parm :
       free_token($3);
     } |
 
+  K_FAMILY_ID TKN_EQUAL TKN_STRING
+    {
+      strncpy(current_part->family_id, $3->value.string, AVR_FAMILYIDLEN);
+      current_part->family_id[AVR_FAMILYIDLEN] = 0;
+      free_token($3);
+    } |
+
   K_DEVICECODE TKN_EQUAL TKN_NUMBER {
     {
       yyerror("devicecode is deprecated, use "
diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi
index 161c647..227399f 100644
--- a/avrdude/doc/avrdude.texi
+++ b/avrdude/doc/avrdude.texi
@@ -1437,6 +1437,7 @@ Following programmer types are currently implemented:
 part
     id               = <id> ;                 # quoted string
     desc             = <description> ;        # quoted string
+    family_id        = <description> ;        # quoted string
     has_jtag         = <yes/no> ;             # part has JTAG i/f
     has_debugwire    = <yes/no> ;             # part has debugWire i/f
     has_pdi          = <yes/no> ;             # part has PDI i/f
diff --git a/avrdude/jtag3.c b/avrdude/jtag3.c
index 57d87b4..4ab96b5 100644
--- a/avrdude/jtag3.c
+++ b/avrdude/jtag3.c
@@ -842,15 +842,16 @@ int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg) {
   if ((c & RSP3_STATUS_MASK) != RSP3_OK) {
     if ((c == RSP3_FAILED) && ((*resp)[3] == RSP3_FAIL_OCD_LOCKED)) {
       avrdude_message(MSG_INFO,
-		      "%s: Device is locked! Chip erase required to unlock.\n",
-		      progname);
+             "\n%s: Device is locked! Chip erase required to unlock.\n",
+             progname);
     } else {
       avrdude_message(MSG_INFO, "%s: bad response to %s command: 0x%02x\n",
 		      progname, descr, c);
     }
+    status = (*resp)[3];
     free(*resp);
     resp = 0;
-    return -1;
+    return -status;
   }
 
   return status;
@@ -949,6 +950,7 @@ static int jtag3_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p)
 static int jtag3_program_enable(PROGRAMMER * pgm)
 {
   unsigned char buf[3], *resp;
+  int status;
 
   if (PDATA(pgm)->prog_enabled)
     return 0;
@@ -957,14 +959,14 @@ static int jtag3_program_enable(PROGRAMMER * pgm)
   buf[1] = CMD3_ENTER_PROGMODE;
   buf[2] = 0;
 
-  if (jtag3_command(pgm, buf, 3, &resp, "enter progmode") >= 0) {
+  if ((status = jtag3_command(pgm, buf, 3, &resp, "enter progmode")) >= 0) {
     free(resp);
     PDATA(pgm)->prog_enabled = 1;
 
     return 0;
   }
 
-  return -1;
+  return status;
 }
 
 static int jtag3_program_disable(PROGRAMMER * pgm)
@@ -1286,17 +1288,28 @@ static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p)
   }
 
   /*
-   * Depending on the target connection, there are two different
+   * Depending on the target connection, there are three different
    * possible replies of the ICE.  For a JTAG connection, the reply
    * format is RSP3_DATA, followed by 4 bytes of the JTAG ID read from
-   * the device (followed by a trailing 0).  For all other connections
+   * the device (followed by a trailing 0).
+   * For a UPDI connection the reply format is RSP3_DATA, followed by
+   * 4 bytes of the SIB Family_ID read from the device (followed by a
+   * trailing 0).
+   * For all other connections
    * (except ISP which is handled completely differently, but that
    * doesn't apply here anyway), the response is just RSP_OK.
    */
-  if (resp[1] == RSP3_DATA && status >= 7)
-    /* JTAG ID has been returned */
-    avrdude_message(MSG_NOTICE, "%s: JTAG ID returned: 0x%02x 0x%02x 0x%02x 0x%02x\n",
-	    progname, resp[3], resp[4], resp[5], resp[6]);
+  if (resp[1] == RSP3_DATA && status >= 7) {
+    if (p->flags & AVRPART_HAS_UPDI) {
+      /* Partial Family_ID has been returned */
+      avrdude_message(MSG_NOTICE, "%s: Partial Family_ID returned: \"%c%c%c%c\"\n",
+	      progname, resp[3], resp[4], resp[5], resp[6]);
+    }
+    else
+      /* JTAG ID has been returned */
+      avrdude_message(MSG_NOTICE, "%s: JTAG ID returned: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+	      progname, resp[3], resp[4], resp[5], resp[6]);
+  }
 
   free(resp);
 
@@ -1806,8 +1819,9 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
   avrdude_message(MSG_NOTICE2, "%s: jtag3_read_byte(.., %s, 0x%lx, ...)\n",
 	    progname, mem->desc, addr);
 
-  if (!(pgm->flag & PGM_FL_IS_DW) && jtag3_program_enable(pgm) < 0)
-    return -1;
+  if (!(pgm->flag & PGM_FL_IS_DW))
+    if ((status = jtag3_program_enable(pgm)) < 0)
+      return status;
 
   cmd[0] = SCOPE_AVR;
   cmd[1] = CMD3_READ_MEMORY;
@@ -1886,7 +1900,7 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
 
     if (addr == 0) {
       if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0)
-	return -1;
+	return status;
 
       signature_cache[0] = resp[4];
       signature_cache[1] = resp[5];
@@ -1935,7 +1949,7 @@ static int jtag3_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
   }
 
   if ((status = jtag3_command(pgm, cmd, 12, &resp, "read memory")) < 0)
-    return -1;
+    return status;
 
   if (resp[1] != RSP3_DATA ||
       status < (pagesize? pagesize: 1) + 4) {
@@ -2061,7 +2075,7 @@ static int jtag3_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
   cmd[13] = data;
 
   if ((status = jtag3_command(pgm, cmd, 14, &resp, "write memory")) < 0)
-    return -1;
+    return status;
 
   free(resp);
 
@@ -2178,6 +2192,28 @@ int jtag3_setparm(PROGRAMMER * pgm, unsigned char scope,
   return status;
 }
 
+int jtag3_read_sib(PROGRAMMER * pgm, AVRPART * p, char * sib)
+{
+  int status;
+  unsigned char cmd[12];
+  unsigned char *resp = NULL;
+
+  cmd[0] = SCOPE_AVR;
+  cmd[1] = CMD3_READ_MEMORY;
+  cmd[2] = 0;
+  cmd[3] = MTYPE_SIB;
+  u32_to_b4(cmd + 4, 0);
+  u32_to_b4(cmd + 8, AVR_SIBLEN);
+
+  if ((status = jtag3_command(pgm, cmd, 12, &resp, "read SIB")) < 0)
+	return status;
+
+  memcpy(sib, resp+3, AVR_SIBLEN);
+  sib[AVR_SIBLEN] = 0; // Zero terminate string
+  avrdude_message(MSG_DEBUG, "%s: jtag3_read_sib(): Received SIB: \"%s\"\n", progname, sib);
+  free(resp);
+  return 0;
+}
 
 static void jtag3_display(PROGRAMMER * pgm, const char * p)
 {
@@ -2430,5 +2466,6 @@ void jtag3_updi_initpgm(PROGRAMMER * pgm)
   pgm->teardown       = jtag3_teardown;
   pgm->page_size      = 256;
   pgm->flag           = PGM_FL_IS_UPDI;
+  pgm->read_sib       = jtag3_read_sib;
 }
 
diff --git a/avrdude/lexer.l b/avrdude/lexer.l
index ab7feb7..6e930a1 100644
--- a/avrdude/lexer.l
+++ b/avrdude/lexer.l
@@ -140,6 +140,7 @@ default_safemode { yylval=NULL; return K_DEFAULT_SAFEMODE; }
 default_serial   { yylval=NULL; return K_DEFAULT_SERIAL; }
 delay            { yylval=NULL; return K_DELAY; }
 desc             { yylval=NULL; return K_DESC; }
+family_id        { yylval=NULL; return K_FAMILY_ID; }
 devicecode       { yylval=NULL; return K_DEVICECODE; }
 eecr             { yylval=NULL; return K_EECR; }
 eeprom           { yylval=NULL; return K_EEPROM; }
diff --git a/avrdude/libavrdude.h b/avrdude/libavrdude.h
index 5636f20..7ba3a71 100644
--- a/avrdude/libavrdude.h
+++ b/avrdude/libavrdude.h
@@ -203,6 +203,8 @@ typedef struct opcode {
 
 #define AVR_DESCLEN 64
 #define AVR_IDLEN   32
+#define AVR_FAMILYIDLEN 7
+#define AVR_SIBLEN 16
 #define CTL_STACK_SIZE 32
 #define FLASH_INSTR_SIZE 3
 #define EEPROM_INSTR_SIZE 20
@@ -212,6 +214,7 @@ typedef struct opcode {
 typedef struct avrpart {
   char          desc[AVR_DESCLEN];  /* long part name */
   char          id[AVR_IDLEN];      /* short part name */
+  char          family_id[AVR_FAMILYIDLEN+1]; /* family id in the SIB (avr8x) */
   int           stk500_devcode;     /* stk500 device code */
   int           avr910_devcode;     /* avr910 device code */
   int           chip_erase_delay;   /* microseconds */
@@ -666,6 +669,7 @@ typedef struct programmer_t {
   int  (*read_byte)      (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
                           unsigned long addr, unsigned char * value);
   int  (*read_sig_bytes) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
+  int  (*read_sib)       (struct programmer_t * pgm, AVRPART * p, char *sib);
   void (*print_parms)    (struct programmer_t * pgm);
   int  (*set_vtarget)    (struct programmer_t * pgm, double v);
   int  (*set_varef)      (struct programmer_t * pgm, unsigned int chan, double v);
diff --git a/avrdude/main.c b/avrdude/main.c
index abd9655..4521aea 100644
--- a/avrdude/main.c
+++ b/avrdude/main.c
@@ -1045,6 +1045,44 @@ int main(int argc, char * argv [])
     if (init_ok) {
       rc = avr_signature(pgm, p);
       if (rc != 0) {
+        // -68 == -(0x44) == -(RSP3_FAIL_OCD_LOCKED)
+        if ((rc == -68) && (p->flags & AVRPART_HAS_UPDI) && (attempt < 1)) {
+          attempt++;
+          if (pgm->read_sib) {
+             // Read SIB and compare FamilyID
+             char sib[AVR_SIBLEN + 1];
+             pgm->read_sib(pgm, p, sib);
+             avrdude_message(MSG_NOTICE, "%s: System Information Block: \"%s\"\n",
+                             progname, sib);
+            if (quell_progress < 2) {
+              avrdude_message(MSG_INFO, "%s: Received FamilyID: \"%.*s\"\n", progname, AVR_FAMILYIDLEN, sib);
+            }
+            if (strncmp(p->family_id, sib, AVR_FAMILYIDLEN)) {
+              avrdude_message(MSG_INFO, "%s: Expected FamilyID: \"%s\"\n", progname, p->family_id);
+              if (!ovsigck) {
+                avrdude_message(MSG_INFO, "%sDouble check chip, "
+                        "or use -F to override this check.\n",
+                        progbuf);
+                exitrc = 1;
+                goto main_exit;
+              }
+            }
+          }
+          if(erase) {
+            erase = 0;
+            if (uflags & UF_NOWRITE) {
+              avrdude_message(MSG_INFO, "%s: conflicting -e and -n options specified, NOT erasing chip\n",
+                              progname);
+            } else {
+              if (quell_progress < 2) {
+                avrdude_message(MSG_INFO, "%s: erasing chip\n", progname);
+              }
+              exitrc = avr_chip_erase(pgm, p);
+              if(exitrc) goto main_exit;
+              goto sig_again;
+            }
+          }
+        }
         avrdude_message(MSG_INFO, "%s: error reading signature data, rc=%d\n",
           progname, rc);
         exitrc = 1;
