예제 #1
0
/*
 * Check Errors
 */
int
sd_interpret_sense(struct scsi_xfer *xs)
{
	struct scsi_sense_data *sense = &xs->sense;
	struct scsi_link *sc_link = xs->sc_link;
	struct sd_softc *sc = sc_link->device_softc;
	u_int8_t serr = sense->error_code & SSD_ERRCODE;
	int retval;

	/*
	 * Let the generic code handle everything except a few categories of
	 * LUN not ready errors on open devices.
	 */
	if (((sc_link->flags & SDEV_OPEN) == 0) ||
	    (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED) ||
	    ((sense->flags & SSD_KEY) != SKEY_NOT_READY) ||
	    (sense->extra_len < 6))
		return (scsi_interpret_sense(xs));

	switch (ASC_ASCQ(sense)) {
	case SENSE_NOT_READY_BECOMING_READY:
		SC_DEBUG(sc_link, SDEV_DB1, ("becoming ready.\n"));
		retval = scsi_delay(xs, 5);
		break;

	case SENSE_NOT_READY_INIT_REQUIRED:
		SC_DEBUG(sc_link, SDEV_DB1, ("spinning up\n"));
		retval = scsi_start(sc->sc_link, SSS_START,
		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_NOSLEEP);
		if (retval == 0)
			retval = ERESTART;
		else if (retval == ENOMEM)
			/* Can't issue the command. Fall back on a delay. */
			retval = scsi_delay(xs, 5);
		else
			SC_DEBUG(sc_link, SDEV_DB1, ("spin up failed (%#x)\n",
			    retval));
		break;

	default:
		retval = scsi_interpret_sense(xs);
		break;
	}

	return (retval);
}
예제 #2
0
파일: ch.c 프로젝트: darksoul42/bitrig
/*
 * Look at the returned sense and act on the error and detirmine
 * The unix error number to pass back... (0 = report no error)
 *                            (-1 = continue processing)
 */
int
ch_interpret_sense(struct scsi_xfer *xs)
{
	struct scsi_sense_data *sense = &xs->sense;
	struct scsi_link *sc_link = xs->sc_link;
	u_int8_t serr = sense->error_code & SSD_ERRCODE;
	u_int8_t skey = sense->flags & SSD_KEY;

	if (((sc_link->flags & SDEV_OPEN) == 0) ||
	    (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
		return (scsi_interpret_sense(xs));

	switch (skey) {

	/*
	 * We do custom processing in ch for the unit becoming ready case.
	 * in this case we do not allow xs->retries to be decremented
	 * only on the "Unit Becoming Ready" case. This is because tape
	 * changers report "Unit Becoming Ready" when they rescan their
	 * state (i.e. when the door got opened) and can take a long time
	 * for large units. Rather than having a massive timeout for
	 * all operations (which would cause other problems) we allow
	 * changers to wait (but be interruptable with Ctrl-C) forever
	 * as long as they are reporting that they are becoming ready.
	 * all other cases are handled as per the default.
	 */
	case SKEY_NOT_READY:
		if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
			return (0);
		switch (ASC_ASCQ(sense)) {
		case SENSE_NOT_READY_BECOMING_READY:
			SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n",
			    sense->add_sense_code_qual));
			/* don't count this as a retry */
			xs->retries++;
			return (scsi_delay(xs, 1));
		default:
			return (scsi_interpret_sense(xs));
	}
	default:
		return (scsi_interpret_sense(xs));
	}
}
예제 #3
0
void
sd_buf_done(struct scsi_xfer *xs)
{
    struct sd_softc *sc = xs->sc_link->device_softc;
    struct buf *bp = xs->cookie;

    splassert(IPL_BIO);

    disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid,
                bp->b_flags & B_READ);

    switch (xs->error) {
    case XS_NOERROR:
        bp->b_error = 0;
        bp->b_resid = xs->resid;
        break;

    case XS_NO_CCB:
        /* The adapter is busy, requeue the buf and try it later. */
        sd_buf_requeue(sc, bp);
        scsi_xs_put(xs);
        SET(sc->flags, SDF_WAITING); /* break out of sdstart loop */
        timeout_add(&sc->sc_timeout, 1);
        return;

    case XS_SENSE:
    case XS_SHORTSENSE:
        if (scsi_interpret_sense(xs) != ERESTART)
            xs->retries = 0;

    /* FALLTHROUGH */
    case XS_BUSY:
    case XS_TIMEOUT:
        if (xs->retries--) {
            scsi_xs_exec(xs);
            return;
        }

    /* FALLTHROUGH */
    default:
        bp->b_error = EIO;
        bp->b_flags |= B_ERROR;
        bp->b_resid = bp->b_bcount;
        break;
    }

    biodone(bp);
    scsi_xs_put(xs);
    sdstart(sc); /* restart io */
}
예제 #4
0
static int
siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs)
{
	void *xfer = adp->xfer;
	int timo, error;

	if (adp->sel_t != xs->target) {
		const int free_lo = __arraycount(siop_script);
		int i;
		void *scriptaddr = (void *)local_to_PCI((u_long)adp->script);

		if (adp->sel_t != -1)
			adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] =
			    htoc32(0x800c00ff);

		for (i = 0; i < __arraycount(lun_switch); i++)
			adp->script[free_lo + i] = htoc32(lun_switch[i]);
		adp->script[free_lo + E_abs_lunsw_return_Used[0]] =
		    htoc32(scriptaddr + Ent_lunsw_return);

		siop_add_reselsw(adp, xs->target, free_lo);

		adp->sel_t = xs->target;
	}

restart:

	siop_setuptables(adp, xfer, xs);

	/* load the DMA maps */
	if (xs->datalen != 0)
		_inv((u_long)xs->data, xs->datalen);
	_wbinv((u_long)xs->cmd, xs->cmdlen);

	_wbinv((u_long)xfer, sizeof(struct siop_xfer));
	siop_start(adp, xs);

	adp->xs = xs;
	timo = 0;
	while (!(xs->xs_status & XS_STS_DONE)) {
		delay(1000);
		siop_intr(adp);

		if (timo++ > 3000) {		/* XXXX: 3sec */
			printf("%s: timeout\n", __func__);
			return ETIMEDOUT;
		}
	}

	if (xs->error != XS_NOERROR) {
		if (xs->error == XS_BUSY || xs->status == SCSI_CHECK)
			scsi_request_sense(adp, xs);

		switch (xs->error) {
		case XS_SENSE:
		case XS_SHORTSENSE:
			error = scsi_interpret_sense(adp, xs);
			break;
		case XS_RESOURCE_SHORTAGE:
			printf("adapter resource shortage\n");

			/* FALLTHROUGH */
		case XS_BUSY:
			error = EBUSY;
			break;
		case XS_REQUEUE:
			printf("XXXX: requeue...\n");
			error = ERESTART;
			break;
		case XS_SELTIMEOUT:
		case XS_TIMEOUT:
			error = EIO;
			break;
		case XS_RESET:
			error = EIO;
			break;
		case XS_DRIVER_STUFFUP:
			printf("generic HBA error\n");
			error = EIO;
			break;
		default:
			printf("invalid return code from adapter: %d\n",
			    xs->error);
			error = EIO;
			break;
		}
		if (error == ERESTART) {
			xs->error = XS_NOERROR;
			xs->status = SCSI_OK;
			xs->xs_status &= ~XS_STS_DONE;
			goto restart;
		}
		return error;
	}
	return 0;
}