static int ch_interpret_sense(struct scsipi_xfer *xs) { struct scsipi_periph *periph = xs->xs_periph; struct scsi_sense_data *sense = &xs->sense.scsi_sense; struct ch_softc *sc = device_private(periph->periph_dev); u_int16_t asc_ascq; /* * If the periph is already recovering, just do the * normal error recovering. */ if (periph->periph_flags & PERIPH_RECOVERING) return (EJUSTRETURN); /* * If it isn't an extended or extended/deferred error, let * the generic code handle it. */ if (SSD_RCODE(sense->response_code) != SSD_RCODE_CURRENT && SSD_RCODE(sense->response_code) != SSD_RCODE_DEFERRED) return (EJUSTRETURN); /* * We're only interested in condtions that * indicate potential inventory violation. * * We use ASC/ASCQ codes for this. */ asc_ascq = (((u_int16_t) sense->asc) << 8) | sense->ascq; switch (asc_ascq) { case 0x2800: /* "Not Ready To Ready Transition (Medium May Have Changed)" */ case 0x2900: /* "Power On, Reset, or Bus Device Reset Occurred" */ sc->sc_periph->periph_flags &= ~PERIPH_MEDIA_LOADED; /* * Enqueue an Element-Status-Changed event, and wake up * any processes waiting for them. */ if ((xs->xs_control & XS_CTL_IGNORE_MEDIA_CHANGE) == 0) ch_event(sc, CHEV_ELEMENT_STATUS_CHANGED); break; default: break; } return (EJUSTRETURN); }
/* * scsi_interpret_sense: * * Look at the returned sense and act on the error, determining * the unix error number to pass back. (0 = report no error) * * NOTE: If we return ERESTART, we are expected to haved * thawed the device! * * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES. */ static int scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs) { struct scsi_sense_data *sense; u_int8_t key; int error; uint32_t info; static const char *error_mes[] = { "soft error (corrected)", "not ready", "medium error", "non-media hardware failure", "illegal request", "unit attention", "readonly device", "no data found", "vendor unique", "copy aborted", "command aborted", "search returned equal", "volume overflow", "verify miscompare", "unknown error key" }; sense = (struct scsi_sense_data *)xs->data; DPRINTF((" sense debug information:\n")); DPRINTF(("\tcode 0x%x valid %d\n", SSD_RCODE(sense->response_code), sense->response_code & SSD_RCODE_VALID ? 1 : 0)); DPRINTF(("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n", sense->segment, SSD_SENSE_KEY(sense->flags), sense->flags & SSD_ILI ? 1 : 0, sense->flags & SSD_EOM ? 1 : 0, sense->flags & SSD_FILEMARK ? 1 : 0)); DPRINTF(("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d " "extra bytes\n", sense->info[0], sense->info[1], sense->info[2], sense->info[3], sense->extra_len)); switch (SSD_RCODE(sense->response_code)) { /* * Old SCSI-1 and SASI devices respond with * codes other than 70. */ case 0x00: /* no error (command completed OK) */ return 0; case 0x04: /* drive not ready after it was selected */ if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; /* XXX - display some sort of error here? */ return EIO; case 0x20: /* invalid command */ return EINVAL; case 0x25: /* invalid LUN (Adaptec ACB-4000) */ return EACCES; /* * If it's code 70, use the extended stuff and * interpret the key */ case 0x71: /* delayed error */ key = SSD_SENSE_KEY(sense->flags); printf(" DEFERRED ERROR, key = 0x%x\n", key); /* FALLTHROUGH */ case 0x70: if ((sense->response_code & SSD_RCODE_VALID) != 0) info = _4btol(sense->info); else info = 0; key = SSD_SENSE_KEY(sense->flags); switch (key) { case SKEY_NO_SENSE: case SKEY_RECOVERED_ERROR: if (xs->resid == xs->datalen && xs->datalen) { /* * Why is this here? */ xs->resid = 0; /* not short read */ } case SKEY_EQUAL: error = 0; break; case SKEY_NOT_READY: if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; if (sense->asc == 0x3A) { error = ENODEV; /* Medium not present */ } else error = EIO; break; case SKEY_ILLEGAL_REQUEST: error = EINVAL; break; case SKEY_UNIT_ATTENTION: if (sense->asc == 0x29 && sense->ascq == 0x00) { /* device or bus reset */ return ERESTART; } if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; if (!(adp->sd->sc_flags & FLAGS_REMOVABLE)) return ERESTART; error = EIO; break; case SKEY_DATA_PROTECT: error = EROFS; break; case SKEY_BLANK_CHECK: error = 0; break; case SKEY_ABORTED_COMMAND: break; case SKEY_VOLUME_OVERFLOW: error = ENOSPC; break; default: error = EIO; break; } /* Print brief(er) sense information */ printf("%s", error_mes[key - 1]); if ((sense->response_code & SSD_RCODE_VALID) != 0) { switch (key) { case SKEY_NOT_READY: case SKEY_ILLEGAL_REQUEST: case SKEY_UNIT_ATTENTION: case SKEY_DATA_PROTECT: break; case SKEY_BLANK_CHECK: printf(", requested size: %d (decimal)", info); break; case SKEY_ABORTED_COMMAND: printf(", cmd 0x%x, info 0x%x", xs->cmd->opcode, info); break; default: printf(", info = %d (decimal)", info); } } if (sense->extra_len != 0) { int n; printf(", data ="); for (n = 0; n < sense->extra_len; n++) printf(" %x", sense->csi[n]); } printf("\n"); return error; /* * Some other code, just report it */ default: printf("Sense Error Code 0x%x", SSD_RCODE(sense->response_code)); if ((sense->response_code & SSD_RCODE_VALID) != 0) { struct scsi_sense_data_unextended *usense = (struct scsi_sense_data_unextended *)sense; printf(" at block no. %d (decimal)", _3btol(usense->block)); } printf("\n"); return EIO; } }