Example #1
0
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;
	}
}