* Copyright 2011, Haiku, Inc. All RightsReserved.
* Copyright 2002-03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "scsi_periph_int.h"
static
err_res check_sense(scsi_periph_device_info *device, scsi_ccb *request)
{
scsi_sense *sense = (scsi_sense *)request->sense;
if ((request->subsys_status & SCSI_AUTOSNS_VALID) == 0) {
SHOW_ERROR0(2, "No auto-sense (but there should be)");
return MK_ERROR(err_act_fail, B_ERROR);
}
if (SCSI_MAX_SENSE_SIZE - request->sense_resid
< (int)offsetof(scsi_sense, add_sense_length) + 1) {
SHOW_ERROR(2, "sense too short (%d bytes)", SCSI_MAX_SENSE_SIZE - request->sense_resid);
return MK_ERROR(err_act_fail, B_ERROR);
}
switch (sense->error_code) {
case SCSIS_DEFERRED_ERROR:
SHOW_ERROR0(2, "encountered DEFERRED ERROR - bye, bye");
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_CURR_ERROR:
switch ((sense->asc << 8) | sense->ascq) {
case SCSIS_ASC_AUDIO_PLAYING:
SHOW_INFO0(2, "busy because playing audio");
return MK_ERROR(err_act_fail, B_DEV_NOT_READY);
case SCSIS_ASC_LUN_NEED_INIT:
SHOW_INFO0(2, "LUN needs init");
return MK_ERROR(err_act_start, B_NO_INIT);
case SCSIS_ASC_LUN_NEED_MANUAL_HELP:
SHOW_ERROR0(2, "LUN needs manual help");
return MK_ERROR(err_act_fail, B_DEV_NOT_READY);
case SCSIS_ASC_LUN_FORMATTING:
SHOW_INFO0(2, "LUN is formatting");
return MK_ERROR(err_act_fail, B_DEV_NOT_READY);
case SCSIS_ASC_MEDIUM_CHANGED:
SHOW_FLOW0(3, "Medium changed");
periph_media_changed(device, request);
return MK_ERROR(err_act_fail, B_DEV_MEDIA_CHANGED);
case SCSIS_ASC_WRITE_ERR_AUTOREALLOC:
SHOW_ERROR0(2, "Recovered write error - block got reallocated automatically");
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_ASC_ID_RECOV:
SHOW_ERROR0(2, "Recovered ID with ECC");
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_ASC_REMOVAL_REQUESTED:
SHOW_INFO0(2, "Removal requested");
mutex_lock(&device->mutex);
device->removal_requested = true;
mutex_unlock(&device->mutex);
return MK_ERROR(err_act_retry, B_DEV_MEDIA_CHANGE_REQUESTED);
case SCSIS_ASC_LUN_BECOMING_READY:
SHOW_INFO0(2, "Becoming ready");
snooze(100000);
return MK_ERROR(err_act_many_retries, B_DEV_NOT_READY);
case SCSIS_ASC_WAS_RESET:
SHOW_INFO0(2, "Unit was reset");
return MK_ERROR(err_act_retry, B_DEV_NOT_READY);
}
switch (sense->asc) {
case SCSIS_ASC_DATA_RECOV_NO_ERR_CORR >> 8:
case SCSIS_ASC_DATA_RECOV_WITH_CORR >> 8:
SHOW_ERROR(0, "Recovered data, asc=0x%2x, ascq=0x%2x",
sense->asc, sense->ascq);
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_ASC_WRITE_PROTECTED >> 8:
SHOW_ERROR0( 2, "Write protected" );
return MK_ERROR(err_act_fail, B_READ_ONLY_DEVICE);
case SCSIS_ASC_NO_MEDIUM >> 8:
SHOW_FLOW0(2, "No medium");
return MK_ERROR(err_act_fail, B_DEV_NO_MEDIA);
}
SHOW_ERROR(3, "0x%04x", (sense->asc << 8) | sense->ascq);
switch (sense->sense_key) {
case SCSIS_KEY_NO_SENSE:
SHOW_ERROR0(2, "No sense");
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_KEY_RECOVERED_ERROR:
SHOW_ERROR0(2, "Recovered error");
return MK_ERROR(err_act_ok, B_OK);
case SCSIS_KEY_NOT_READY:
return MK_ERROR(err_act_retry, B_DEV_NOT_READY);
case SCSIS_KEY_MEDIUM_ERROR:
SHOW_ERROR0(2, "Medium error");
return MK_ERROR( err_act_retry, B_DEV_RECALIBRATE_ERROR);
case SCSIS_KEY_HARDWARE_ERROR:
SHOW_ERROR0(2, "Hardware error");
return MK_ERROR(err_act_retry, B_DEV_SEEK_ERROR);
case SCSIS_KEY_ILLEGAL_REQUEST:
SHOW_ERROR0(2, "Illegal request");
return MK_ERROR(err_act_invalid_req, B_ERROR);
case SCSIS_KEY_UNIT_ATTENTION:
SHOW_ERROR0(2, "Unit attention");
return MK_ERROR( err_act_retry, B_DEV_NOT_READY);
case SCSIS_KEY_DATA_PROTECT:
SHOW_ERROR0(2, "Data protect");
return MK_ERROR(err_act_fail, B_NOT_ALLOWED);
case SCSIS_KEY_BLANK_CHECK:
SHOW_ERROR0(2, "Is blank");
return MK_ERROR(err_act_fail, B_DEV_UNREADABLE);
case SCSIS_KEY_VENDOR_SPECIFIC:
return MK_ERROR(err_act_fail, B_ERROR);
case SCSIS_KEY_COPY_ABORTED:
return MK_ERROR(err_act_fail, B_ERROR);
case SCSIS_KEY_ABORTED_COMMAND:
return MK_ERROR(err_act_retry, B_ERROR);
case SCSIS_KEY_EQUAL:
case SCSIS_KEY_MISCOMPARE:
return MK_ERROR(err_act_fail, B_ERROR);
case SCSIS_KEY_VOLUME_OVERFLOW:
return MK_ERROR(err_act_fail, B_DEV_SEEK_ERROR);
case SCSIS_KEY_RESERVED:
default:
return MK_ERROR(err_act_fail, B_ERROR);
}
default:
SHOW_ERROR(2, "Invalid sense type (0x%x)", sense->error_code);
return MK_ERROR(err_act_fail, B_ERROR);
}
}
static err_res
check_scsi_status(scsi_periph_device_info *device, scsi_ccb *request)
{
SHOW_FLOW(3, "%d", request->device_status & SCSI_STATUS_MASK);
switch (request->device_status & SCSI_STATUS_MASK) {
case SCSI_STATUS_GOOD:
return MK_ERROR(err_act_ok, B_OK);
case SCSI_STATUS_CHECK_CONDITION:
return check_sense(device, request);
case SCSI_STATUS_QUEUE_FULL:
case SCSI_STATUS_BUSY:
snooze(1000000);
return MK_ERROR(err_act_retry, B_DEV_TIMEOUT);
case SCSI_STATUS_COMMAND_TERMINATED:
return MK_ERROR(err_act_retry, B_INTERRUPTED);
default:
return MK_ERROR(err_act_retry, B_ERROR);
}
}
* 1. check SCSI subsystem problems
* 2. if request hit device, check SCSI status
* 3. if request got executed, check sense
*/
err_res
periph_check_error(scsi_periph_device_info *device, scsi_ccb *request)
{
SHOW_FLOW(4, "%d", request->subsys_status & SCSI_SUBSYS_STATUS_MASK);
switch (request->subsys_status & SCSI_SUBSYS_STATUS_MASK) {
case SCSI_REQ_CMP:
return MK_ERROR(err_act_ok, B_OK);
case SCSI_LUN_INVALID:
case SCSI_TID_INVALID:
case SCSI_PATH_INVALID:
case SCSI_DEV_NOT_THERE:
case SCSI_NO_HBA:
SHOW_ERROR0(2, "No device");
return MK_ERROR(err_act_fail, B_DEV_BAD_DRIVE_NUM);
case SCSI_SEL_TIMEOUT:
case SCSI_BUSY:
case SCSI_SCSI_BUSY:
case SCSI_HBA_ERR:
case SCSI_MSG_REJECT_REC:
case SCSI_NO_NEXUS:
case SCSI_FUNC_NOTAVAIL:
case SCSI_RESRC_UNAVAIL:
snooze(1000000);
return MK_ERROR(err_act_retry, B_DEV_TIMEOUT);
case SCSI_DATA_RUN_ERR:
case SCSI_UNCOR_PARITY:
SHOW_ERROR0(2, "Data transmission failed");
return MK_ERROR(err_act_retry, B_DEV_READ_ERROR);
case SCSI_REQ_INVALID:
SHOW_ERROR0(2, "Invalid request");
return MK_ERROR(err_act_fail, B_ERROR);
case SCSI_REQ_ABORTED:
case SCSI_SCSI_BUS_RESET:
case SCSI_REQ_TERMIO:
case SCSI_UNEXP_BUSFREE:
case SCSI_BDR_SENT:
case SCSI_CMD_TIMEOUT:
case SCSI_IID_INVALID:
case SCSI_UNACKED_EVENT:
case SCSI_IDE:
case SCSI_SEQUENCE_FAIL:
snooze(100000);
return MK_ERROR(err_act_retry, B_DEV_TIMEOUT);
case SCSI_REQ_CMP_ERR:
return check_scsi_status(device, request);
case SCSI_AUTOSENSE_FAIL:
SHOW_ERROR0(2, "Auto-sense failed, don't know what really happened");
return MK_ERROR(err_act_fail, B_ERROR);
case SCSI_BUS_RESET_DENIED:
case SCSI_PROVIDE_FAIL:
case SCSI_UA_TERMIO:
case SCSI_CDB_RECVD:
case SCSI_LUN_ALLREADY_ENAB:
default:
return MK_ERROR(err_act_fail, B_ERROR);
}
}