/* * 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); }
/* * 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)); } }
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 */ }
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; }