--- 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);