int scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq) { struct scsi_xfer *xs; int err = 0; if (screq->cmdlen > sizeof(struct scsi_generic)) return (EFAULT); if (screq->datalen > MAXPHYS) return (EINVAL); xs = scsi_xs_get(link, 0); if (xs == NULL) return (ENOMEM); memcpy(xs->cmd, screq->cmd, screq->cmdlen); xs->cmdlen = screq->cmdlen; if (screq->datalen > 0) { xs->data = dma_alloc(screq->datalen, PR_WAITOK | PR_ZERO); if (xs->data == NULL) { err = ENOMEM; goto err; } xs->datalen = screq->datalen; } if (screq->flags & SCCMD_READ) xs->flags |= SCSI_DATA_IN; if (screq->flags & SCCMD_WRITE) { if (screq->datalen > 0) { err = copyin(screq->databuf, xs->data, screq->datalen); if (err != 0) goto err; } xs->flags |= SCSI_DATA_OUT; } xs->flags |= SCSI_SILENT; /* User is responsible for errors. */ xs->timeout = screq->timeout; xs->retries = 0; /* user must do the retries *//* ignored */ scsi_xs_sync(xs); screq->retsts = 0; screq->status = xs->status; switch (xs->error) { case XS_NOERROR: /* probably rubbish */ screq->datalen_used = xs->datalen - xs->resid; screq->retsts = SCCMD_OK; break; case XS_SENSE: #ifdef SCSIDEBUG scsi_sense_print_debug(xs); #endif screq->senselen_used = min(sizeof(xs->sense), sizeof(screq->sense)); bcopy(&xs->sense, screq->sense, screq->senselen_used); screq->retsts = SCCMD_SENSE; break; case XS_SHORTSENSE: #ifdef SCSIDEBUG scsi_sense_print_debug(xs); #endif printf("XS_SHORTSENSE\n"); screq->senselen_used = min(sizeof(xs->sense), sizeof(screq->sense)); bcopy(&xs->sense, screq->sense, screq->senselen_used); screq->retsts = SCCMD_UNKNOWN; break; case XS_DRIVER_STUFFUP: screq->retsts = SCCMD_UNKNOWN; break; case XS_TIMEOUT: screq->retsts = SCCMD_TIMEOUT; break; case XS_BUSY: screq->retsts = SCCMD_BUSY; break; default: screq->retsts = SCCMD_UNKNOWN; break; } if (screq->datalen > 0 && screq->flags & SCCMD_READ) { err = copyout(xs->data, screq->databuf, screq->datalen); if (err != 0) goto err; } err: if (xs->data) dma_free(xs->data, screq->datalen); scsi_xs_put(xs); return (err); }
void sd_buf_done(struct scsi_xfer *xs) { struct sd_softc *sc = xs->sc_link->device_softc; struct buf *bp = xs->cookie; int error, s; 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. */ disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid, bp->b_flags & B_READ); bufq_requeue(&sc->sc_bufq, bp); scsi_xs_put(xs); SET(sc->flags, SDF_WAITING); timeout_add(&sc->sc_timeout, 1); return; case XS_SENSE: case XS_SHORTSENSE: #ifdef SCSIDEBUG scsi_sense_print_debug(xs); #endif error = sd_interpret_sense(xs); if (error == 0) { bp->b_error = 0; bp->b_resid = xs->resid; break; } if (error != ERESTART) { bp->b_error = error; xs->retries = 0; } goto retry; case XS_BUSY: if (xs->retries) { if (scsi_delay(xs, 1) != ERESTART) xs->retries = 0; } goto retry; case XS_TIMEOUT: retry: if (xs->retries--) { scsi_xs_exec(xs); return; } /* FALLTHROUGH */ default: if (bp->b_error == 0) bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; break; } disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid, bp->b_flags & B_READ); s = splbio(); biodone(bp); splx(s); scsi_xs_put(xs); }
int scsi_ioc_ata_cmd(struct scsi_link *link, atareq_t *atareq) { struct scsi_xfer *xs; struct scsi_ata_passthru_12 *cdb; int err = 0; if (atareq->datalen > MAXPHYS) return (EINVAL); xs = scsi_xs_get(link, 0); if (xs == NULL) return (ENOMEM); cdb = (struct scsi_ata_passthru_12 *)xs->cmd; cdb->opcode = ATA_PASSTHRU_12; if (atareq->datalen > 0) { if (atareq->flags & ATACMD_READ) { cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAIN; cdb->flags = ATA_PASSTHRU_T_DIR_READ; } else { cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAOUT; cdb->flags = ATA_PASSTHRU_T_DIR_WRITE; } cdb->flags |= ATA_PASSTHRU_T_LEN_SECTOR_COUNT; } else { cdb->count_proto = ATA_PASSTHRU_PROTO_NON_DATA; cdb->flags = ATA_PASSTHRU_T_LEN_NONE; } cdb->features = atareq->features; cdb->sector_count = atareq->sec_count; cdb->lba_low = atareq->sec_num; cdb->lba_mid = atareq->cylinder; cdb->lba_high = atareq->cylinder >> 8; cdb->device = atareq->head & 0x0f; cdb->command = atareq->command; xs->cmdlen = sizeof(*cdb); if (atareq->datalen > 0) { xs->data = dma_alloc(atareq->datalen, PR_WAITOK | PR_ZERO); if (xs->data == NULL) { err = ENOMEM; goto err; } xs->datalen = atareq->datalen; } if (atareq->flags & ATACMD_READ) xs->flags |= SCSI_DATA_IN; if (atareq->flags & ATACMD_WRITE) { if (atareq->datalen > 0) { err = copyin(atareq->databuf, xs->data, atareq->datalen); if (err != 0) goto err; } xs->flags |= SCSI_DATA_OUT; } xs->flags |= SCSI_SILENT; /* User is responsible for errors. */ xs->retries = 0; /* user must do the retries *//* ignored */ scsi_xs_sync(xs); atareq->retsts = ATACMD_ERROR; switch (xs->error) { case XS_SENSE: case XS_SHORTSENSE: #ifdef SCSIDEBUG scsi_sense_print_debug(xs); #endif /* XXX this is not right */ case XS_NOERROR: atareq->retsts = ATACMD_OK; break; default: atareq->retsts = ATACMD_ERROR; break; } if (atareq->datalen > 0 && atareq->flags & ATACMD_READ) { err = copyout(xs->data, atareq->databuf, atareq->datalen); if (err != 0) goto err; } err: if (xs->data) dma_free(xs->data, atareq->datalen); scsi_xs_put(xs); return (err); }