Example #1
0
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);
}
Example #2
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);
}
Example #3
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);
}
Example #4
0
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);
}
Example #5
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);
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #8
0
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);
}
Example #9
0
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);
}