--- linux-2.4.19-orig/drivers/scsi/constants.c	Thu Oct 25 16:53:50 2001
+++ linux-2.4.19/drivers/scsi/constants.c	Wed Oct  2 09:57:15 2002
@@ -703,79 +703,100 @@
     int i, s;
     int sense_class, valid, code, info;
     const char * error = NULL;
+    int key, asc, ascq;
+    char pstr[80];  
     
     sense_class = (sense_buffer[0] >> 4) & 0x07;
     code = sense_buffer[0] & 0xf;
     valid = sense_buffer[0] & 0x80;
+    key = sense_buffer[2] & 0x0f;
     
     if (sense_class == 7) {	/* extended sense data */
 	s = sense_buffer[7] + 8;
 	if(s > SCSI_SENSE_BUFFERSIZE)
 	   s = SCSI_SENSE_BUFFERSIZE;
-	
+
+        if (s < 14) {  /* too short to include asc/ascq */
+            asc = 0; ascq = 0;
+            }
+         else {
+            asc = sense_buffer[12];
+            ascq = sense_buffer[13];
+            }    
+
+#if (CONSTANTS & CONST_SENSE)
+        printk("%s %s: sense error %02x;%02x;%02x %s\n", devclass,
+               kdevname(dev), key, asc, ascq, snstext[key]);
+ 
+        /* Check to see if additional sense information is meaningful. */
+        if (!(asc == 0 && ascq == 0))  {
+        for(i=0; additional[i].text; i++)
+            if(additional[i].code1 == asc && additional[i].code2 == ascq)
+                printk("Additional sense indicates %s\n", additional[i].text);
+ 
+        for(i=0; additional2[i].text; i++)
+            if(additional2[i].code1 == asc &&
+               additional2[i].code2_min >= ascq  &&
+               additional2[i].code2_max <= ascq) {
+                printk("Additional sense indicates ");
+                printk(additional2[i].text, ascq);     
+                printk("\n");
+            };
+        }
+ 
+        /* Illegal Request & SKSV is set (Sense-Key Specific Field Valid bit)*/
+        if (key == ILLEGAL_REQUEST && (sense_buffer[15] & 0x80) == 0x80) {
+            char bitstr[40];
+            /* Now find the invalid byte in CDB or parameter list */
+            if ((sense_buffer[15] & 0x40) == 0x40) error = "Error in CDB:";
+            else error = "Error in Parameter List:";
+            sprintf(pstr,"%s Byte #%d", error,
+                    (sense_buffer[16] * 0x100 + sense_buffer[17]));
+            if ((sense_buffer[15] & 0x08) == 0x08) /*BPV(Bit Pointer Valid)?*/
+                sprintf(bitstr,", Bit #%d is in error.\n",
+                        sense_buffer[15] & 0x07);
+            else sprintf(bitstr," is in error.\n");
+            printk("%s%s",pstr,bitstr);
+            }
+#else
+        printk("%s %s: sense error, class=%2x Key=%02x ASC=%02x ASCQ=%02x\n",
+               devclass, kdevname(dev), sense_buffer[0], sense_buffer[2],
+               asc, ascq);
+#endif
+	/* Compose flags and info strings. */
 	info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
 		(sense_buffer[5] << 8) | sense_buffer[6]);
 	if (info || valid) {
-		printk("Info fld=0x%x", info);
-		if (!valid)	/* info data not according to standard */
-			printk(" (nonstd)");
-		printk(", ");
-	}
-	if (sense_buffer[2] & 0x80)
-           printk( "FMK ");	/* current command has read a filemark */
-	if (sense_buffer[2] & 0x40)
-           printk( "EOM ");	/* end-of-medium condition exists */
-	if (sense_buffer[2] & 0x20)
-           printk( "ILI ");	/* incorrect block length requested */
-	
-	switch (code) {
-	case 0x0:
-	    error = "Current";	/* error concerns current command */
-	    break;
-	case 0x1:
-	    error = "Deferred";	/* error concerns some earlier command */
-            	/* e.g., an earlier write to disk cache succeeded, but
+           if (!valid) error = "(nonstd)";
+           else error = "";
+           sprintf(pstr,"sense info fld=0x%x %s, ", info, error);
+	   }
+        else
+           strcpy(pstr,"flags: ");
+        if (sense_buffer[2] & 0x80)
+           strcat(pstr, "FMK ");    /* current command has read a filemark */
+        if (sense_buffer[2] & 0x40)
+           strcat(pstr, "EOM ");    /* end-of-medium condition exists */
+        if (sense_buffer[2] & 0x20)
+           strcat(pstr, "ILI ");    /* incorrect block length requested */
+        switch (code) {
+        case 0x0:
+            error = "Current";  /* error concerns current command */
+            break;
+        case 0x1:
+            error = "Deferred"; /* error concerns some earlier command */
+                /* e.g., an earlier write to disk cache succeeded, but
                    now the disk discovers that it cannot write the data */
-	    break;
-	default:
-	    error = "Invalid";
-	}
-	
-	printk("%s ", error);
-	
-#if (CONSTANTS & CONST_SENSE)
-	printk( "%s%s: sense key %s\n", devclass,
-	       kdevname(dev), snstext[sense_buffer[2] & 0x0f]);
-#else
-	printk("%s%s: sns = %2x %2x\n", devclass,
-	       kdevname(dev), sense_buffer[0], sense_buffer[2]);
-#endif
-	
-	/* Check to see if additional sense information is available */
-	if(sense_buffer[7] + 7 < 13 ||
-	   (sense_buffer[12] == 0  && sense_buffer[13] ==  0)) goto done;
-	
-#if (CONSTANTS & CONST_XSENSE)
-	for(i=0; additional[i].text; i++)
-	    if(additional[i].code1 == sense_buffer[12] &&
-	       additional[i].code2 == sense_buffer[13])
-		printk("Additional sense indicates %s\n", additional[i].text);
-	
-	for(i=0; additional2[i].text; i++)
-	    if(additional2[i].code1 == sense_buffer[12] &&
-	       additional2[i].code2_min >= sense_buffer[13]  &&
-	       additional2[i].code2_max <= sense_buffer[13]) {
-		printk("Additional sense indicates ");
-		printk(additional2[i].text, sense_buffer[13]);
-		printk("\n");
-	    };
-#else
-	printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]);
-#endif
+            break;
+        default:
+            error = "Invalid";
+        }
+        printk("%s %s\n",pstr,error);  /* show flags & info */
+
     } else {	/* non-extended sense data */
 
          /*
-          * Standard says:
+          * SCSI-1 Standard says:
           *    sense_buffer[0] & 0200 : address valid
           *    sense_buffer[0] & 0177 : vendor-specific error code
           *    sense_buffer[1] & 0340 : vendor-specific
@@ -797,10 +818,16 @@
     
  done:
 #if !(CONSTANTS & CONST_SENSE)
-    printk("Raw sense data:");
-    for (i = 0; i < s; ++i) 
-	printk("0x%02x ", sense_buffer[i]);
-    printk("\n");
+    printk("Raw sense data: \n");
+    error = pstr; *error = 0;
+    for (i = 0; i < s; ++i) {
+	sprintf(error,"%02x ", sense_buffer[i]);
+	if (i > 0 && (i % 16) == 0) {
+		printk("%s\n",pstr);
+		error = pstr; *error = 0;
+	} else error += 3;
+    }
+    printk("%s\n",pstr);
 #endif
     return;
 }
--- linux-2.4.19-orig/drivers/scsi/scsi.h	Wed Oct  2 09:56:51 2002
+++ linux-2.4.19/drivers/scsi/scsi.h	Wed Oct  2 09:57:15 2002
@@ -584,6 +584,7 @@
 	char type;
 	char scsi_level;
 	char vendor[8], model[16], rev[4];
+	char sdev_serial[8];            /* disk serial number for uniqueness */
 	unsigned char current_tag;	/* current tag */
 	unsigned char sync_min_period;	/* Not less than this period */
 	unsigned char sync_max_offset;	/* Not greater than this offset */
@@ -621,6 +622,13 @@
 
 	// Flag to allow revalidate to succeed in sd_open
 	int allow_revalidate;
+	// Tallies of scsi device errors
+	int sdev_timeouts;
+	int sdev_resets;
+	int sdev_par_errs;
+	int sdev_disk_errs;   /* sense keys 1, 3, 4, b, e */
+	int sdev_trans_errs;  /* sense keys 2, 5, 6, 8, a */
+	int sdev_user_errs;   /* sense keys 7, 9, c, d, f */
 };
 
 
--- linux-2.4.19-orig/drivers/scsi/scsi_error.c	Fri Aug  2 20:39:44 2002
+++ linux-2.4.19/drivers/scsi/scsi_error.c	Wed Oct  2 09:57:15 2002
@@ -220,6 +220,7 @@
 
 	SCpnt->host->in_recovery = 1;
 	SCpnt->host->host_failed++;
+	SCpnt->device->sdev_timeouts++;
 
 	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d failed=%d\n",
 				   atomic_read(&SCpnt->host->host_active),
@@ -654,6 +655,9 @@
 		 * protection here, since we would end up waiting in the actual low
 		 * level driver, we don't know how to wake it up.
 		 */
+		SCSI_LOG_ERROR_RECOVERY(5, 
+			printk("send_eh_cmnd: cant queue, %p eh_state:%x\n",
+				SCpnt, SCpnt->eh_state)); 
 		spin_lock_irqsave(&io_request_lock, flags);
 		temp = host->hostt->command(SCpnt);
 		spin_unlock_irqrestore(&io_request_lock, flags);
@@ -812,8 +816,10 @@
 	rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	if (rtn == SUCCESS)
+	if (rtn == SUCCESS) {
 		SCpnt->eh_state = SUCCESS;
+		// SCpnt->device->sdev_resets++;
+		}
 
 	return SCpnt->eh_state;
 }
@@ -845,8 +851,10 @@
 	rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	if (rtn == SUCCESS)
+	if (rtn == SUCCESS) {
 		SCpnt->eh_state = SUCCESS;
+		// SCpnt->device->sdev_resets++;
+		}
 
 	/*
 	 * If we had a successful bus reset, mark the command blocks to expect
@@ -891,8 +899,10 @@
 	rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
-	if (rtn == SUCCESS)
+	if (rtn == SUCCESS) {
 		SCpnt->eh_state = SUCCESS;
+		SCpnt->device->sdev_resets++;
+		}
 
 	/*
 	 * If we had a successful host reset, mark the command blocks to expect
@@ -909,6 +919,21 @@
 	return SCpnt->eh_state;
 }
 
+int sense_err_type(Scsi_Cmnd * SCpnt)
+{
+   unsigned char key, sense_class;
+   unsigned char rgkeyt[15] = {1, 2, 1, 1, 2, 2, 3, 2, 3, 2, 1, 3, 3, 1, 3};
+        /* 1) sdev_disk_errs:  sense keys 1, 3, 4, b, e */
+        /* 2) sdev_trans_errs: sense keys 2, 5, 6, 8, a */
+        /* 3) sdev_user_errs:  sense keys 7, 9, c, d, f */ 
+   sense_class = (SCpnt->sense_buffer[0] >> 4) & 0x07;
+   if (sense_class != 7)   /* SCSI-1, non-extended sense */
+      key = SCpnt->sense_buffer[0] & 0x0f;
+   else
+      key = SCpnt->sense_buffer[2] & 0x0f;
+   return((int)rgkeyt[key]);   
+}
+
 /*
  * Function:  scsi_decide_disposition
  *
@@ -995,7 +1020,9 @@
 		/* FALLTHROUGH */
 
 	case DID_BUS_BUSY:
+		goto maybe_retry;
 	case DID_PARITY:
+		SCpnt->device->sdev_par_errs++;
 		goto maybe_retry;
 	case DID_TIME_OUT:
 		/*
@@ -1043,6 +1070,13 @@
 	case COMMAND_TERMINATED:
 		return SUCCESS;
 	case CHECK_CONDITION:
+		/* increment tallies, then check if needs retry */
+		switch (sense_err_type(SCpnt)) {
+		  case 1:  SCpnt->device->sdev_disk_errs++;   break;
+		  case 2:  SCpnt->device->sdev_trans_errs++;  break;
+		  case 3:  
+		  default: SCpnt->device->sdev_user_errs++;
+		}
 		rtn = scsi_check_sense(SCpnt);
 		if (rtn == NEEDS_RETRY) {
 			goto maybe_retry;
@@ -1530,6 +1564,8 @@
 
 		if (rtn == SUCCESS) {
 			rtn = scsi_test_unit_ready(SCloop);
+                        /* Try another TUR to clear check condition if needed.*/                        if (rtn != SUCCESS)
+                           rtn = scsi_test_unit_ready(SCloop);
 
 			if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
 				rtn = scsi_eh_retry_command(SCloop);
@@ -1618,6 +1654,9 @@
 							continue;
 						}
 						rtn = scsi_test_unit_ready(SCloop);
+		 				/* Try another TUR to clear check condition if needed.*/
+						if (rtn != SUCCESS)
+						   rtn = scsi_test_unit_ready(SCloop);
 
 						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
 							rtn = scsi_eh_retry_command(SCloop);
@@ -1716,6 +1755,9 @@
 							continue;
 						}
 						rtn = scsi_test_unit_ready(SCloop);
+		 				/* Try another TUR to clear check condition if needed.*/
+						if (rtn != SUCCESS)
+						   rtn = scsi_test_unit_ready(SCloop);
 
 						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
 							rtn = scsi_eh_retry_command(SCloop);
--- linux-2.4.19-orig/drivers/scsi/scsi_lib.c	Wed Oct  2 09:56:51 2002
+++ linux-2.4.19/drivers/scsi/scsi_lib.c	Wed Oct  2 09:59:18 2002
@@ -749,12 +749,15 @@
 		struct Scsi_Device_Template *STpnt;
 
 		STpnt = scsi_get_request_dev(&SCpnt->request);
-		printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n",
+		printk("SCSI %s error : (scsi%d:%d:%d:%d), sense %x:%x:%x, return code = %x\n",
 		       (STpnt ? STpnt->name : "device"),
 		       SCpnt->device->host->host_no,
 		       SCpnt->device->channel,
 		       SCpnt->device->id,
-		       SCpnt->device->lun, result);
+		       SCpnt->device->lun,
+		       SCpnt->sense_buffer[2],
+		       SCpnt->sense_buffer[12],
+		       SCpnt->sense_buffer[13], result);    
 
 		if (driver_byte(result) & DRIVER_SENSE)
 			print_sense("sd", SCpnt);
@@ -1248,6 +1251,12 @@
 	Scsi_Device *SDloop;
 	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
 		if (channel == SDloop->channel) {
+			/*
+			 * Sometimes we get here repeatedly, so only
+			 * increment the tally if this is the start
+			 * of a reset.
+			 */
+			if (SDloop->was_reset == 0) SDloop->sdev_resets++;
 			SDloop->was_reset = 1;
 			SDloop->expecting_cc_ua = 1;
 		}
--- linux-2.4.19-orig/drivers/scsi/scsi_merge.c	Mon Feb 25 14:38:04 2002
+++ linux-2.4.19/drivers/scsi/scsi_merge.c	Wed Oct  2 09:57:15 2002
@@ -97,7 +97,7 @@
 		       bh->b_size >> 9,
 		       virt_to_phys(bh->b_data - 1));
 	}
-	panic("Ththththaats all folks.  Too dangerous to continue.\n");
+	panic("Inconsistency detected in scsi, cannot continue.\n");
 }
 
 
@@ -814,7 +814,7 @@
 		 * Typically used for swapping, but this isn't how we do
 		 * swapping any more.
 		 */
-		panic("I believe this is dead code.  If we hit this, I was wrong");
+		panic("scsi/init_io: Invalid request buffer_head, should never get here.");
 #if 0
 		SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9;
 		SCpnt->request_buffer = SCpnt->request.buffer;
--- linux-2.4.19-orig/drivers/scsi/scsi_proc.c	Wed Jun 27 20:10:55 2001
+++ linux-2.4.19/drivers/scsi/scsi_proc.c	Wed Oct  2 09:57:15 2002
@@ -285,6 +285,14 @@
 		else
 			y += sprintf(buffer + len + y, " ");
 	}
+        y += sprintf(buffer + len + y, "  Ser#: ");
+        for (x = 0; x < 8; x++) {
+                register char c1;
+                if (scd->sdev_serial[x] >= 0x20) c1 = scd->sdev_serial[x];
+                else c1 = ' ';
+                buffer[len + y++] = c1;
+        }
+        buffer[len + y] = 0;   /* stringify */ 
 	y += sprintf(buffer + len + y, "\n");
 
 	y += sprintf(buffer + len + y, "  Type:   %s ",
@@ -297,6 +305,11 @@
 	else
 		y += sprintf(buffer + len + y, "\n");
 
+        y += sprintf(buffer + len + y, "  Tallies: timeouts %d resets %d "
+		"par_errs %d disk_errs %d trans_errs %d user_errs %d\n",
+                scd->sdev_timeouts,   scd->sdev_resets,
+                scd->sdev_par_errs,   scd->sdev_disk_errs,
+		scd->sdev_trans_errs, scd->sdev_user_errs);
 	*size = y;
 	return;
 }
--- linux-2.4.19-orig/drivers/scsi/scsi_scan.c	Wed Oct  2 09:56:51 2002
+++ linux-2.4.19/drivers/scsi/scsi_scan.c	Wed Oct  2 09:57:15 2002
@@ -249,6 +249,16 @@
 			printk(" ");
 	}
 
+        if ((data[0] & 0x1f) == 0) {     /* if type == disk */
+           printk("  Ser#: ");
+           for (i = 36; i < 44; i++) {
+                if (data[i] >= 0x20 && i < data[4] + 5)
+                        printk("%c", data[i]);
+                else
+                        printk(" ");
+           }
+        }
+
 	printk("\n");
 
 	i = data[0] & 0x1f;
@@ -679,6 +689,7 @@
 	memcpy(SDpnt->vendor, scsi_result + 8, 8);
 	memcpy(SDpnt->model, scsi_result + 16, 16);
 	memcpy(SDpnt->rev, scsi_result + 32, 4);
+	memcpy(SDpnt->sdev_serial, scsi_result + 36, 8);
 
 	SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
 	/* Use the peripheral qualifier field to determine online/offline */
@@ -721,6 +732,13 @@
 	    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
 	SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
 	SDpnt->type = (type & 0x1f);
+
+	SDpnt->sdev_timeouts = 0;
+	SDpnt->sdev_resets = 0;
+	SDpnt->sdev_par_errs = 0;
+	SDpnt->sdev_disk_errs = 0;
+	SDpnt->sdev_trans_errs = 0;
+	SDpnt->sdev_user_errs = 0;
 
 	print_inquiry(scsi_result);
 
