int ch_getelemstatus(struct ch_softc *sc, int first, int count, caddr_t data, size_t datalen, int voltag) { struct scsi_read_element_status *cmd; struct scsi_xfer *xs; int error; /* * Build SCSI command. */ xs = scsi_xs_get(sc->sc_link, SCSI_DATA_IN); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->data = data; xs->datalen = datalen; xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_read_element_status *)xs->cmd; cmd->opcode = READ_ELEMENT_STATUS; _lto2b(first, cmd->sea); _lto2b(count, cmd->count); _lto3b(datalen, cmd->len); if (voltag) cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
int emc_inquiry(struct emc_softc *sc, char *model, char *serial) { u_int8_t *buffer; struct scsi_inquiry *cdb; struct scsi_xfer *xs; size_t length; int error; u_int8_t slen, mlen; length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, 255); if (length < 160) { printf("%s: FC (Legacy)\n"); return (0); } buffer = dma_alloc(length, PR_WAITOK); xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf); if (xs == NULL) { error = EBUSY; goto done; } cdb = (struct scsi_inquiry *)xs->cmd; cdb->opcode = INQUIRY; _lto2b(length, cdb->length); xs->cmdlen = sizeof(*cdb); xs->flags |= SCSI_DATA_IN; xs->data = buffer; xs->datalen = length; error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) goto done; slen = buffer[160]; if (slen == 0 || slen + 161 > length) { error = EIO; goto done; } mlen = buffer[99]; if (mlen == 0 || slen + mlen + 161 > length) { error = EIO; goto done; } scsi_strvis(serial, buffer + 161, slen); scsi_strvis(model, buffer + 161 + slen, mlen); error = 0; done: dma_free(buffer, length); return (error); }
int ch_move(struct ch_softc *sc, struct changer_move *cm) { struct scsi_move_medium *cmd; struct scsi_xfer *xs; int error; u_int16_t fromelem, toelem; /* * Check arguments. */ if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) return (EINVAL); if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) return (EINVAL); /* * Calculate the source and destination elements. */ fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_move_medium *)xs->cmd; cmd->opcode = MOVE_MEDIUM; _lto2b(sc->sc_picker, cmd->tea); _lto2b(fromelem, cmd->src); _lto2b(toelem, cmd->dst); if (cm->cm_flags & CM_INVERT) cmd->flags |= MOVE_MEDIUM_INVERT; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
int emc_inquiry(struct emc_softc *sc, char *model, char *serial) { u_int8_t buffer[255]; struct scsi_inquiry *cdb; struct scsi_xfer *xs; size_t length; int error; u_int8_t slen, mlen; length = MIN(sc->sc_path.p_link->inqdata.additional_length + 5, sizeof(buffer)); if (length < 160) { printf("%s: FC (Legacy)\n"); return (0); } xs = scsi_xs_get(sc->sc_path.p_link, scsi_autoconf); if (xs == NULL) return (EBUSY); cdb = (struct scsi_inquiry *)xs->cmd; cdb->opcode = INQUIRY; _lto2b(length, cdb->length); xs->cmdlen = sizeof(*cdb); xs->flags |= SCSI_DATA_IN; xs->data = buffer; xs->datalen = length; error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) return (error); slen = buffer[160]; if (slen == 0 || slen + 161 > length) return (EIO); mlen = buffer[99]; if (mlen == 0 || slen + mlen + 161 > length) return (EIO); scsi_strvis(serial, buffer + 161, slen); scsi_strvis(model, buffer + 161 + slen, mlen); return (0); }
int sd_read_cap_16(struct sd_softc *sc, int flags) { struct scsi_read_capacity_16 cdb; struct scsi_read_cap_data_16 *rdcap; struct scsi_xfer *xs; int rv = ENOMEM; CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST); rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK) | PR_ZERO); if (rdcap == NULL) return (ENOMEM); xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); if (xs == NULL) goto done; bzero(&cdb, sizeof(cdb)); cdb.opcode = READ_CAPACITY_16; cdb.byte2 = SRC16_SERVICE_ACTION; _lto4b(sizeof(*rdcap), cdb.length); memcpy(xs->cmd, &cdb, sizeof(cdb)); xs->cmdlen = sizeof(cdb); xs->data = (void *)rdcap; xs->datalen = sizeof(*rdcap); xs->timeout = 20000; rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv == 0) { sc->params.disksize = _8btol(rdcap->addr) + 1; sc->params.secsize = _4btol(rdcap->length); if (ISSET(_2btol(rdcap->lowest_aligned), READ_CAP_16_TPE)) SET(sc->flags, SDF_THIN); else CLR(sc->flags, SDF_THIN); } done: dma_free(rdcap, sizeof(*rdcap)); return (rv); }
void sd_flush(struct sd_softc *sc, int flags) { struct scsi_link *link = sc->sc_link; struct scsi_xfer *xs; struct scsi_synchronize_cache *cmd; if (link->quirks & SDEV_NOSYNCCACHE) return; /* * Issue a SYNCHRONIZE CACHE. Address 0, length 0 means "all remaining * blocks starting at address 0". Ignore ILLEGAL REQUEST in the event * that the command is not supported by the device. */ xs = scsi_xs_get(link, flags); if (xs == NULL) { SC_DEBUG(link, SDEV_DB1, ("cache sync failed to get xs\n")); return; } cmd = (struct scsi_synchronize_cache *)xs->cmd; cmd->opcode = SYNCHRONIZE_CACHE; xs->cmdlen = sizeof(*cmd); xs->timeout = 100000; xs->done = sd_flush_done; do { scsi_xs_exec(xs); if (!ISSET(xs->flags, SCSI_POLL)) { while (!ISSET(xs->flags, ITSDONE)) tsleep(xs, PRIBIO, "sdflush", 0); } } while (xs->status == XS_NO_CCB); if (xs->error == XS_NOERROR) sc->flags &= ~SDF_DIRTY; else SC_DEBUG(link, SDEV_DB1, ("cache sync failed\n")); scsi_xs_put(xs); }
int ch_position(struct ch_softc *sc, struct changer_position *cp) { struct scsi_position_to_element *cmd; struct scsi_xfer *xs; int error; u_int16_t dst; /* * Check arguments. */ if (cp->cp_type > CHET_DT) return (EINVAL); if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) return (ENODEV); /* * Calculate the destination element. */ dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_position_to_element *)xs->cmd; cmd->opcode = POSITION_TO_ELEMENT; _lto2b(sc->sc_picker, cmd->tea); _lto2b(dst, cmd->dst); if (cp->cp_flags & CP_INVERT) cmd->flags |= POSITION_TO_ELEMENT_INVERT; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
int sd_flush(struct sd_softc *sc, int flags) { struct scsi_link *link = sc->sc_link; struct scsi_xfer *xs; struct scsi_synchronize_cache *cmd; int error; if (link->quirks & SDEV_NOSYNCCACHE) return (0); /* * Issue a SYNCHRONIZE CACHE. Address 0, length 0 means "all remaining * blocks starting at address 0". Ignore ILLEGAL REQUEST in the event * that the command is not supported by the device. */ xs = scsi_xs_get(link, flags); if (xs == NULL) { SC_DEBUG(link, SDEV_DB1, ("cache sync failed to get xs\n")); return (EIO); } cmd = (struct scsi_synchronize_cache *)xs->cmd; cmd->opcode = SYNCHRONIZE_CACHE; xs->cmdlen = sizeof(*cmd); xs->timeout = 100000; xs->flags |= SCSI_IGNORE_ILLEGAL_REQUEST; error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error) SC_DEBUG(link, SDEV_DB1, ("cache sync failed\n")); else sc->flags &= ~SDF_DIRTY; return (error); }
int safte_read_config(struct safte_softc *sc) { struct safte_config *config = NULL; struct safte_readbuf_cmd *cmd; struct safte_sensor *s; struct scsi_xfer *xs; int error = 0, flags = 0, i, j; config = dma_alloc(sizeof(*config), PR_NOWAIT); if (config == NULL) return (1); if (cold) flags |= SCSI_AUTOCONF; xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); if (xs == NULL) { error = 1; goto done; } xs->cmdlen = sizeof(*cmd); xs->data = (void *)config; xs->datalen = sizeof(*config); xs->retries = 2; xs->timeout = 30000; cmd = (struct safte_readbuf_cmd *)xs->cmd; cmd->opcode = READ_BUFFER; cmd->flags |= SAFTE_RD_MODE; cmd->bufferid = SAFTE_RD_CONFIG; cmd->length = htobe16(sizeof(*config)); error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) { error = 1; goto done; } DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d" " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config->nfans, config->npwrsup, config->nslots, config->doorlock, config->ntemps, config->alarm, SAFTE_CFG_CELSIUS(config->therm), SAFTE_CFG_NTHERM(config->therm))); sc->sc_encbuflen = config->nfans * sizeof(u_int8_t) + /* fan status */ config->npwrsup * sizeof(u_int8_t) + /* power supply status */ config->nslots * sizeof(u_int8_t) + /* device scsi id (lun) */ sizeof(u_int8_t) + /* door lock status */ sizeof(u_int8_t) + /* speaker status */ config->ntemps * sizeof(u_int8_t) + /* temp sensors */ sizeof(u_int16_t); /* temp out of range sensors */ sc->sc_encbuf = dma_alloc(sc->sc_encbuflen, PR_NOWAIT); if (sc->sc_encbuf == NULL) { error = 1; goto done; } sc->sc_nsensors = config->nfans + config->npwrsup + config->ntemps + (config->doorlock ? 1 : 0) + (config->alarm ? 1 : 0); sc->sc_sensors = mallocarray(sc->sc_nsensors, sizeof(struct safte_sensor), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_sensors == NULL) { dma_free(sc->sc_encbuf, sc->sc_encbuflen); sc->sc_encbuf = NULL; sc->sc_nsensors = 0; error = 1; goto done; } strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), sizeof(sc->sc_sensordev.xname)); s = sc->sc_sensors; for (i = 0; i < config->nfans; i++) { s->se_type = SAFTE_T_FAN; s->se_field = (u_int8_t *)(sc->sc_encbuf + i); s->se_sensor.type = SENSOR_INDICATOR; snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc), "Fan%d", i); s++; } j = config->nfans; for (i = 0; i < config->npwrsup; i++) { s->se_type = SAFTE_T_PWRSUP; s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i); s->se_sensor.type = SENSOR_INDICATOR; snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc), "PSU%d", i); s++; } j += config->npwrsup; #if NBIO > 0 sc->sc_nslots = config->nslots; sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j); #endif j += config->nslots; if (config->doorlock) { s->se_type = SAFTE_T_DOORLOCK; s->se_field = (u_int8_t *)(sc->sc_encbuf + j); s->se_sensor.type = SENSOR_INDICATOR; strlcpy(s->se_sensor.desc, "doorlock", sizeof(s->se_sensor.desc)); s++; } j++; if (config->alarm) { s->se_type = SAFTE_T_ALARM; s->se_field = (u_int8_t *)(sc->sc_encbuf + j); s->se_sensor.type = SENSOR_INDICATOR; strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc)); s++; } j++; /* * stash the temp info so we can get out of range status. limit the * number so the out of temp checks cant go into memory it doesnt own */ sc->sc_ntemps = (config->ntemps > 15) ? 15 : config->ntemps; sc->sc_temps = s; sc->sc_celsius = SAFTE_CFG_CELSIUS(config->therm); for (i = 0; i < config->ntemps; i++) { s->se_type = SAFTE_T_TEMP; s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i); s->se_sensor.type = SENSOR_TEMP; s++; } j += config->ntemps; sc->sc_temperrs = (u_int8_t *)(sc->sc_encbuf + j); done: dma_free(config, sizeof(*config)); return (error); }
int safte_match(struct device *parent, void *match, void *aux) { struct scsi_inquiry_data *inqbuf; struct scsi_attach_args *sa = aux; struct scsi_inquiry_data *inq = sa->sa_inqbuf; struct scsi_xfer *xs; struct safte_inq *si; int error, flags = 0, length; if (inq == NULL) return (0); /* match on dell enclosures */ if ((inq->device & SID_TYPE) == T_PROCESSOR && SCSISPC(inq->version) == 3) return (2); if ((inq->device & SID_TYPE) != T_PROCESSOR || SCSISPC(inq->version) != 2 || (inq->response_format & SID_ANSII) != 2) return (0); length = inq->additional_length + SAFTE_EXTRA_OFFSET; if (length < SAFTE_INQ_LEN) return (0); if (length > sizeof(*inqbuf)) length = sizeof(*inqbuf); inqbuf = dma_alloc(sizeof(*inqbuf), PR_NOWAIT | PR_ZERO); if (inqbuf == NULL) return (0); memset(inqbuf->extra, ' ', sizeof(inqbuf->extra)); if (cold) flags |= SCSI_AUTOCONF; xs = scsi_xs_get(sa->sa_sc_link, flags | SCSI_DATA_IN); if (xs == NULL) goto fail; xs->retries = 2; xs->timeout = 10000; scsi_init_inquiry(xs, 0, 0, inqbuf, length); error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error) goto fail; si = (struct safte_inq *)&inqbuf->extra; if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0) { dma_free(inqbuf, sizeof(*inqbuf)); return (2); } fail: dma_free(inqbuf, sizeof(*inqbuf)); return (0); }
/* * dump all of physical memory into the partition specified, starting * at offset 'dumplo' into the partition. */ int sddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) { struct sd_softc *sc; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; u_int32_t sectorsize; /* size of a disk sector */ u_int64_t nsects; /* number of sectors in partition */ u_int64_t sectoff; /* sector offset of partition */ u_int64_t totwrt; /* total number of sectors left to write */ u_int32_t nwrt; /* current number of sectors to write */ struct scsi_xfer *xs; /* ... convenience */ int rv; /* Check if recursive dump; if so, punt. */ if (sddoingadump) return EFAULT; if (blkno < 0) return EINVAL; /* Mark as active early. */ sddoingadump = 1; unit = DISKUNIT(dev); /* Decompose unit & partition. */ part = DISKPART(dev); /* Check for acceptable drive number. */ if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL) return ENXIO; /* * XXX Can't do this check, since the media might have been * XXX marked `invalid' by successful unmounting of all * XXX filesystems. */ #if 0 /* Make sure it was initialized. */ if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) return ENXIO; #endif /* Convert to disk sectors. Request must be a multiple of size. */ lp = sc->sc_dk.dk_label; sectorsize = lp->d_secsize; if ((size % sectorsize) != 0) return EFAULT; if ((blkno % DL_BLKSPERSEC(lp)) != 0) return EFAULT; totwrt = size / sectorsize; blkno = DL_BLKTOSEC(lp, blkno); nsects = DL_GETPSIZE(&lp->d_partitions[part]); sectoff = DL_GETPOFFSET(&lp->d_partitions[part]); /* Check transfer bounds against partition size. */ if ((blkno + totwrt) > nsects) return EINVAL; /* Offset block number to start of partition. */ blkno += sectoff; while (totwrt > 0) { if (totwrt > UINT32_MAX) nwrt = UINT32_MAX; else nwrt = totwrt; #ifndef SD_DUMP_NOT_TRUSTED xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP); if (xs == NULL) return (ENOMEM); xs->timeout = 10000; xs->flags |= SCSI_DATA_OUT; xs->data = va; xs->datalen = nwrt * sectorsize; sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */ rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv != 0) return (ENXIO); #else /* SD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("sd%d: dump addr 0x%x, blk %lld\n", unit, va, (long long)blkno); delay(500 * 1000); /* half a second */ #endif /* SD_DUMP_NOT_TRUSTED */ /* update block count */ totwrt -= nwrt; blkno += nwrt; va += sectorsize * nwrt; } sddoingadump = 0; return (0); }
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); }
int ch_exchange(struct ch_softc *sc, struct changer_exchange *ce) { struct scsi_exchange_medium *cmd; struct scsi_xfer *xs; int error; u_int16_t src, dst1, dst2; /* * Check arguments. */ if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || (ce->ce_sdsttype > CHET_DT)) return (EINVAL); if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) return (ENODEV); /* * Check the request against the changer's capabilities. */ if (((sc->sc_exchangemask[ce->ce_srctype] & (1 << ce->ce_fdsttype)) == 0) || ((sc->sc_exchangemask[ce->ce_fdsttype] & (1 << ce->ce_sdsttype)) == 0)) return (EINVAL); /* * Calculate the source and destination elements. */ src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; /* * Build the SCSI command. */ xs = scsi_xs_get(sc->sc_link, 0); if (xs == NULL) return (ENOMEM); xs->cmdlen = sizeof(*cmd); xs->retries = CHRETRIES; xs->timeout = 100000; cmd = (struct scsi_exchange_medium *)xs->cmd; cmd->opcode = EXCHANGE_MEDIUM; _lto2b(sc->sc_picker, cmd->tea); _lto2b(src, cmd->src); _lto2b(dst1, cmd->fdst); _lto2b(dst2, cmd->sdst); if (ce->ce_flags & CE_INVERT1) cmd->flags |= EXCHANGE_MEDIUM_INV1; if (ce->ce_flags & CE_INVERT2) cmd->flags |= EXCHANGE_MEDIUM_INV2; error = scsi_xs_sync(xs); scsi_xs_put(xs); return (error); }
/* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, * It dequeues the buf and creates a scsi command to perform the * transfer in the buf. The transfer request will call scsi_done * on completion, which will in turn call this routine again * so that the next queued transfer is performed. * The bufs are queued by the strategy routine (sdstrategy) * * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. */ void sdstart(void *v) { struct sd_softc *sc = (struct sd_softc *)v; struct scsi_link *link = sc->sc_link; struct scsi_xfer *xs; struct buf *bp; daddr64_t blkno; int nblks; int read; struct partition *p; int s; if (sc->flags & SDF_DYING) return; SC_DEBUG(link, SDEV_DB2, ("sdstart\n")); mtx_enter(&sc->sc_start_mtx); if (ISSET(sc->flags, SDF_STARTING)) { mtx_leave(&sc->sc_start_mtx); return; } SET(sc->flags, SDF_STARTING); mtx_leave(&sc->sc_start_mtx); CLR(sc->flags, SDF_WAITING); while (!ISSET(sc->flags, SDF_WAITING) && (bp = sd_buf_dequeue(sc)) != NULL) { /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ if ((link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; s = splbio(); biodone(bp); splx(s); continue; } xs = scsi_xs_get(link, SCSI_NOSLEEP); if (xs == NULL) { sd_buf_requeue(sc, bp); break; } blkno = bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); read = bp->b_flags & B_READ; /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ if (!(link->flags & SDEV_ATAPI) && !(link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && ((nblks & 0xff) == nblks)) sd_cmd_rw6(xs, read, blkno, nblks); else if (((blkno & 0xffffffff) == blkno) && ((nblks & 0xffff) == nblks)) sd_cmd_rw10(xs, read, blkno, nblks); else if (((blkno & 0xffffffff) == blkno) && ((nblks & 0xffffffff) == nblks)) sd_cmd_rw12(xs, read, blkno, nblks); else sd_cmd_rw16(xs, read, blkno, nblks); xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); xs->timeout = 60000; xs->data = bp->b_data; xs->datalen = bp->b_bcount; xs->done = sd_buf_done; xs->cookie = bp; /* Instrumentation. */ disk_busy(&sc->sc_dk); /* Mark disk as dirty. */ if ((bp->b_flags & B_READ) == 0) sc->flags |= SDF_DIRTY; scsi_xs_exec(xs); } mtx_enter(&sc->sc_start_mtx); CLR(sc->flags, SDF_STARTING); mtx_leave(&sc->sc_start_mtx); }
void safte_read_encstat(void *arg) { struct safte_readbuf_cmd *cmd; struct safte_sensor *s; struct safte_softc *sc = (struct safte_softc *)arg; struct scsi_xfer *xs; int error, i, flags = 0; u_int16_t oot; rw_enter_write(&sc->sc_lock); if (cold) flags |= SCSI_AUTOCONF; xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); if (xs == NULL) { rw_exit_write(&sc->sc_lock); return; } xs->cmdlen = sizeof(*cmd); xs->data = sc->sc_encbuf; xs->datalen = sc->sc_encbuflen; xs->retries = 2; xs->timeout = 30000; cmd = (struct safte_readbuf_cmd *)xs->cmd; cmd->opcode = READ_BUFFER; cmd->flags |= SAFTE_RD_MODE; cmd->bufferid = SAFTE_RD_ENCSTAT; cmd->length = htobe16(sc->sc_encbuflen); error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) { rw_exit_write(&sc->sc_lock); return; } for (i = 0; i < sc->sc_nsensors; i++) { s = &sc->sc_sensors[i]; s->se_sensor.flags &= ~SENSOR_FUNKNOWN; DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i, s->se_type, *s->se_field)); switch (s->se_type) { case SAFTE_T_FAN: switch (*s->se_field) { case SAFTE_FAN_OP: s->se_sensor.value = 1; s->se_sensor.status = SENSOR_S_OK; break; case SAFTE_FAN_MF: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_CRIT; break; case SAFTE_FAN_NOTINST: case SAFTE_FAN_UNKNOWN: default: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_UNKNOWN; s->se_sensor.flags |= SENSOR_FUNKNOWN; break; } break; case SAFTE_T_PWRSUP: switch (*s->se_field) { case SAFTE_PWR_OP_ON: s->se_sensor.value = 1; s->se_sensor.status = SENSOR_S_OK; break; case SAFTE_PWR_OP_OFF: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_OK; break; case SAFTE_PWR_MF_ON: s->se_sensor.value = 1; s->se_sensor.status = SENSOR_S_CRIT; break; case SAFTE_PWR_MF_OFF: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_CRIT; break; case SAFTE_PWR_NOTINST: case SAFTE_PWR_PRESENT: case SAFTE_PWR_UNKNOWN: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_UNKNOWN; s->se_sensor.flags |= SENSOR_FUNKNOWN; break; } break; case SAFTE_T_DOORLOCK: switch (*s->se_field) { case SAFTE_DOOR_LOCKED: s->se_sensor.value = 1; s->se_sensor.status = SENSOR_S_OK; break; case SAFTE_DOOR_UNLOCKED: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_CRIT; break; case SAFTE_DOOR_UNKNOWN: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_CRIT; s->se_sensor.flags |= SENSOR_FUNKNOWN; break; } break; case SAFTE_T_ALARM: switch (*s->se_field) { case SAFTE_SPKR_OFF: s->se_sensor.value = 0; s->se_sensor.status = SENSOR_S_OK; break; case SAFTE_SPKR_ON: s->se_sensor.value = 1; s->se_sensor.status = SENSOR_S_CRIT; break; } break; case SAFTE_T_TEMP: s->se_sensor.value = safte_temp2uK(*s->se_field, sc->sc_celsius); break; } } oot = _2btol(sc->sc_temperrs); for (i = 0; i < sc->sc_ntemps; i++) sc->sc_temps[i].se_sensor.status = (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK; rw_exit_write(&sc->sc_lock); }
int safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink) { struct safte_writebuf_cmd *cmd; struct safte_slotop *op; struct scsi_xfer *xs; int error, slot, flags = 0, wantblink; switch (blink->bb_status) { case BIOC_SBBLINK: wantblink = 1; break; case BIOC_SBUNBLINK: wantblink = 0; break; default: return (EINVAL); } rw_enter_read(&sc->sc_lock); for (slot = 0; slot < sc->sc_nslots; slot++) { if (sc->sc_slots[slot] == blink->bb_target) break; } rw_exit_read(&sc->sc_lock); if (slot >= sc->sc_nslots) return (ENODEV); op = dma_alloc(sizeof(*op), PR_WAITOK | PR_ZERO); op->opcode = SAFTE_WRITE_SLOTOP; op->slot = slot; op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0; if (cold) flags |= SCSI_AUTOCONF; xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_OUT | SCSI_SILENT); if (xs == NULL) { dma_free(op, sizeof(*op)); return (ENOMEM); } xs->cmdlen = sizeof(*cmd); xs->data = (void *)op; xs->datalen = sizeof(*op); xs->retries = 2; xs->timeout = 30000; cmd = (struct safte_writebuf_cmd *)xs->cmd; cmd->opcode = WRITE_BUFFER; cmd->flags |= SAFTE_WR_MODE; cmd->length = htobe16(sizeof(struct safte_slotop)); error = scsi_xs_sync(xs); scsi_xs_put(xs); if (error != 0) { error = EIO; } dma_free(op, sizeof(*op)); return (error); }
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); }