static int chkqfilter(dev_t dev, struct knote *kn) { struct ch_softc *sc = device_lookup_private(&ch_cd, CHUNIT(dev)); struct klist *klist; switch (kn->kn_filter) { case EVFILT_READ: klist = &sc->sc_selq.sel_klist; kn->kn_fop = &chread_filtops; break; case EVFILT_WRITE: klist = &sc->sc_selq.sel_klist; kn->kn_fop = &chwrite_filtops; break; default: return (EINVAL); } kn->kn_hook = sc; SLIST_INSERT_HEAD(klist, kn, kn_selnext); return (0); }
int chclose(dev_t dev, int flags, int fmt, struct proc *p) { struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; sc->sc_link->flags &= ~SDEV_OPEN; return (0); }
static int chopen(dev_t dev, int flags, int fmt, struct lwp *l) { struct ch_softc *sc; struct scsipi_periph *periph; struct scsipi_adapter *adapt; int unit, error; unit = CHUNIT(dev); sc = device_lookup_private(&ch_cd, unit); if (sc == NULL) return (ENXIO); periph = sc->sc_periph; adapt = periph->periph_channel->chan_adapter; /* * Only allow one open at a time. */ if (periph->periph_flags & PERIPH_OPEN) return (EBUSY); if ((error = scsipi_adapter_addref(adapt)) != 0) return (error); /* * Make sure the unit is on-line. If a UNIT ATTENTION * occurs, we will mark that an Init-Element-Status is * needed in ch_get_params(). * * We ignore NOT READY in case e.g a magazine isn't actually * loaded into the changer or a tape isn't in the drive. */ error = scsipi_test_unit_ready(periph, XS_CTL_IGNORE_NOT_READY); if (error) goto bad; periph->periph_flags |= PERIPH_OPEN; /* * Make sure our parameters are up to date. */ if ((error = ch_get_params(sc, 0)) != 0) goto bad; return (0); bad: scsipi_adapter_delref(adapt); periph->periph_flags &= ~PERIPH_OPEN; return (error); }
static int chclose(dev_t dev, int flags, int fmt, struct lwp *l) { struct ch_softc *sc = device_lookup_private(&ch_cd, CHUNIT(dev)); struct scsipi_periph *periph = sc->sc_periph; struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter; scsipi_wait_drain(periph); scsipi_adapter_delref(adapt); sc->sc_events = 0; periph->periph_flags &= ~PERIPH_OPEN; return (0); }
static int chpoll(dev_t dev, int events, struct lwp *l) { struct ch_softc *sc = device_lookup_private(&ch_cd, CHUNIT(dev)); int revents; revents = events & (POLLOUT | POLLWRNORM); if ((events & (POLLIN | POLLRDNORM)) == 0) return (revents); if (sc->sc_events == 0) revents |= events & (POLLIN | POLLRDNORM); else selrecord(l, &sc->sc_selq); return (revents); }
static int chread(dev_t dev, struct uio *uio, int flags) { struct ch_softc *sc = device_lookup_private(&ch_cd, CHUNIT(dev)); int error; if (uio->uio_resid != CHANGER_EVENT_SIZE) return (EINVAL); /* * Read never blocks; if there are no events pending, we just * return an all-clear bitmask. */ error = uiomove(&sc->sc_events, CHANGER_EVENT_SIZE, uio); if (error == 0) sc->sc_events = 0; return (error); }
static int chioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct ch_softc *sc = device_lookup_private(&ch_cd, CHUNIT(dev)); int error = 0; /* * If this command can change the device's state, we must * have the device open for writing. */ switch (cmd) { case CHIOGPICKER: case CHIOGPARAMS: case OCHIOGSTATUS: break; default: if ((flags & FWRITE) == 0) return (EBADF); } switch (cmd) { case CHIOMOVE: error = ch_move(sc, (struct changer_move_request *)data); break; case CHIOEXCHANGE: error = ch_exchange(sc, (struct changer_exchange_request *)data); break; case CHIOPOSITION: error = ch_position(sc, (struct changer_position_request *)data); break; case CHIOGPICKER: *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT]; break; case CHIOSPICKER: { int new_picker = *(int *)data; if (new_picker > (sc->sc_counts[CHET_MT] - 1)) return (EINVAL); sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker; break; } case CHIOGPARAMS: { struct changer_params *cp = (struct changer_params *)data; cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT]; cp->cp_npickers = sc->sc_counts[CHET_MT]; cp->cp_nslots = sc->sc_counts[CHET_ST]; cp->cp_nportals = sc->sc_counts[CHET_IE]; cp->cp_ndrives = sc->sc_counts[CHET_DT]; break; } case CHIOIELEM: error = ch_ielem(sc); if (error == 0) { sc->sc_periph->periph_flags |= PERIPH_MEDIA_LOADED; } break; case OCHIOGSTATUS: { struct ochanger_element_status_request *cesr = (struct ochanger_element_status_request *)data; error = ch_ousergetelemstatus(sc, cesr->cesr_type, cesr->cesr_data); break; } case CHIOGSTATUS: error = ch_usergetelemstatus(sc, (struct changer_element_status_request *)data); break; case CHIOSVOLTAG: error = ch_setvoltag(sc, (struct changer_set_voltag_request *)data); break; /* Implement prevent/allow? */ default: error = scsipi_do_ioctl(sc->sc_periph, dev, cmd, data, flags, l); break; } return (error); }
int chioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; int error = 0; /* * If this command can change the device's state, we must * have the device open for writing. */ switch (cmd) { case CHIOGPICKER: case CHIOGPARAMS: case CHIOGSTATUS: break; default: if ((flags & FWRITE) == 0) return (EBADF); } switch (cmd) { case CHIOMOVE: error = ch_move(sc, (struct changer_move *)data); break; case CHIOEXCHANGE: error = ch_exchange(sc, (struct changer_exchange *)data); break; case CHIOPOSITION: error = ch_position(sc, (struct changer_position *)data); break; case CHIOGPICKER: *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT]; break; case CHIOSPICKER: { int new_picker = *(int *)data; if (new_picker > (sc->sc_counts[CHET_MT] - 1)) return (EINVAL); sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker; break; } case CHIOGPARAMS: { struct changer_params *cp = (struct changer_params *)data; cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT]; cp->cp_npickers = sc->sc_counts[CHET_MT]; cp->cp_nslots = sc->sc_counts[CHET_ST]; cp->cp_nportals = sc->sc_counts[CHET_IE]; cp->cp_ndrives = sc->sc_counts[CHET_DT]; break; } case CHIOGSTATUS: { struct changer_element_status_request *cesr = (struct changer_element_status_request *)data; error = ch_usergetelemstatus(sc, cesr); break; } /* Implement prevent/allow? */ default: error = scsi_do_ioctl(sc->sc_link, cmd, data, flags); break; } return (error); }
int chopen(dev_t dev, int flags, int fmt, struct proc *p) { struct ch_softc *sc; int oldcounts[4]; int i, unit, error = 0; unit = CHUNIT(dev); if ((unit >= ch_cd.cd_ndevs) || ((sc = ch_cd.cd_devs[unit]) == NULL)) return (ENXIO); /* * Only allow one open at a time. */ if (sc->sc_link->flags & SDEV_OPEN) return (EBUSY); sc->sc_link->flags |= SDEV_OPEN; /* * Absorb any unit attention errors. We must notice * "Not ready" errors as a changer will report "In the * process of getting ready" any time it must rescan * itself to determine the state of the changer. */ error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE); if (error) goto bad; /* * Get information about the device. Save old information * so we can decide whether to be verbose about new parameters. */ for (i = 0; i < 4; i++) { oldcounts[i] = sc->sc_counts[i]; } error = ch_get_params(sc, scsi_autoconf); if (error) goto bad; for (i = 0; i < 4; i++) { if (oldcounts[i] != sc->sc_counts[i]) { break; } } if (i < 4) { #ifdef CHANGER_DEBUG #define PLURAL(c) (c) == 1 ? "" : "s" printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n", sc->sc_dev.dv_xname, sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]), sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]), sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]), sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE])); #undef PLURAL printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n", sc->sc_dev.dv_xname, sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST], sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]); printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n", sc->sc_dev.dv_xname, sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST], sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]); #endif /* CHANGER_DEBUG */ } /* Default the current picker. */ sc->sc_picker = sc->sc_firsts[CHET_MT]; return (0); bad: sc->sc_link->flags &= ~SDEV_OPEN; return (error); }