Home | History | Annotate | Line # | Download | only in scsipi
ch.c revision 1.33
      1  1.33    mjacob /*	$NetBSD: ch.c,v 1.33 1998/07/03 19:11:25 mjacob Exp $	*/
      2   1.8       cgd 
      3   1.1       cgd /*
      4  1.26   thorpej  * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej (at) and.com>
      5  1.20   thorpej  * All rights reserved.
      6  1.20   thorpej  *
      7  1.20   thorpej  * Partially based on an autochanger driver written by Stefan Grefen
      8  1.20   thorpej  * and on an autochanger driver written by the Systems Programming Group
      9  1.20   thorpej  * at the University of Utah Computer Science Department.
     10   1.6   mycroft  *
     11   1.6   mycroft  * Redistribution and use in source and binary forms, with or without
     12   1.6   mycroft  * modification, are permitted provided that the following conditions
     13   1.6   mycroft  * are met:
     14   1.6   mycroft  * 1. Redistributions of source code must retain the above copyright
     15   1.6   mycroft  *    notice, this list of conditions and the following disclaimer.
     16   1.6   mycroft  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.6   mycroft  *    notice, this list of conditions and the following disclaimer in the
     18   1.6   mycroft  *    documentation and/or other materials provided with the distribution.
     19   1.6   mycroft  * 3. All advertising materials mentioning features or use of this software
     20  1.20   thorpej  *    must display the following acknowledgements:
     21  1.20   thorpej  *	This product includes software developed by Jason R. Thorpe
     22  1.20   thorpej  *	for And Communications, http://www.and.com/
     23   1.6   mycroft  * 4. The name of the author may not be used to endorse or promote products
     24   1.6   mycroft  *    derived from this software without specific prior written permission.
     25   1.6   mycroft  *
     26   1.6   mycroft  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     27   1.6   mycroft  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     28   1.6   mycroft  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     29   1.6   mycroft  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     30  1.20   thorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     31  1.20   thorpej  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     32  1.20   thorpej  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     33  1.20   thorpej  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     34  1.20   thorpej  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  1.20   thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  1.20   thorpej  * SUCH DAMAGE.
     37   1.6   mycroft  */
     38   1.1       cgd 
     39   1.1       cgd #include <sys/param.h>
     40   1.1       cgd #include <sys/systm.h>
     41   1.1       cgd #include <sys/errno.h>
     42   1.1       cgd #include <sys/ioctl.h>
     43   1.1       cgd #include <sys/buf.h>
     44   1.1       cgd #include <sys/proc.h>
     45   1.1       cgd #include <sys/user.h>
     46  1.20   thorpej #include <sys/chio.h>
     47   1.6   mycroft #include <sys/device.h>
     48  1.20   thorpej #include <sys/malloc.h>
     49  1.21  christos #include <sys/conf.h>
     50  1.22   thorpej #include <sys/fcntl.h>
     51   1.1       cgd 
     52  1.27    bouyer #include <dev/scsipi/scsipi_all.h>
     53  1.27    bouyer #include <dev/scsipi/scsi_all.h>
     54  1.27    bouyer #include <dev/scsipi/scsi_changer.h>
     55  1.27    bouyer #include <dev/scsipi/scsiconf.h>
     56   1.1       cgd 
     57  1.20   thorpej #define CHRETRIES	2
     58  1.20   thorpej #define CHUNIT(x)	(minor((x)))
     59  1.20   thorpej 
     60  1.20   thorpej struct ch_softc {
     61  1.20   thorpej 	struct device	sc_dev;		/* generic device info */
     62  1.27    bouyer 	struct scsipi_link *sc_link;	/* link in the SCSI bus */
     63  1.20   thorpej 
     64  1.20   thorpej 	int		sc_picker;	/* current picker */
     65   1.1       cgd 
     66  1.20   thorpej 	/*
     67  1.20   thorpej 	 * The following information is obtained from the
     68  1.20   thorpej 	 * element address assignment page.
     69  1.20   thorpej 	 */
     70  1.20   thorpej 	int		sc_firsts[4];	/* firsts, indexed by CHET_* */
     71  1.20   thorpej 	int		sc_counts[4];	/* counts, indexed by CHET_* */
     72   1.1       cgd 
     73  1.20   thorpej 	/*
     74  1.20   thorpej 	 * The following mask defines the legal combinations
     75  1.20   thorpej 	 * of elements for the MOVE MEDIUM command.
     76  1.20   thorpej 	 */
     77  1.20   thorpej 	u_int8_t	sc_movemask[4];
     78  1.20   thorpej 
     79  1.20   thorpej 	/*
     80  1.20   thorpej 	 * As above, but for EXCHANGE MEDIUM.
     81  1.20   thorpej 	 */
     82  1.20   thorpej 	u_int8_t	sc_exchangemask[4];
     83   1.1       cgd 
     84  1.20   thorpej 	int		flags;		/* misc. info */
     85  1.26   thorpej 
     86  1.26   thorpej 	/*
     87  1.26   thorpej 	 * Quirks; see below.
     88  1.26   thorpej 	 */
     89  1.26   thorpej 	int		sc_settledelay;	/* delay for settle */
     90  1.26   thorpej 
     91   1.6   mycroft };
     92   1.6   mycroft 
     93  1.20   thorpej /* sc_flags */
     94  1.20   thorpej #define CHF_ROTATE	0x01		/* picker can rotate */
     95  1.20   thorpej 
     96  1.20   thorpej /* Autoconfiguration glue */
     97  1.25       cgd #ifdef __BROKEN_INDIRECT_CONFIG
     98  1.15  christos int	chmatch __P((struct device *, void *, void *));
     99  1.25       cgd #else
    100  1.25       cgd int	chmatch __P((struct device *, struct cfdata *, void *));
    101  1.25       cgd #endif
    102  1.15  christos void	chattach __P((struct device *, struct device *, void *));
    103   1.6   mycroft 
    104  1.17   thorpej struct cfattach ch_ca = {
    105  1.17   thorpej 	sizeof(struct ch_softc), chmatch, chattach
    106  1.17   thorpej };
    107  1.17   thorpej 
    108  1.32   thorpej extern struct cfdriver ch_cd;
    109   1.1       cgd 
    110  1.27    bouyer struct scsipi_inquiry_pattern ch_patterns[] = {
    111  1.20   thorpej 	{T_CHANGER, T_REMOV,
    112  1.20   thorpej 	 "",		"",		""},
    113  1.20   thorpej };
    114  1.20   thorpej 
    115  1.20   thorpej /* SCSI glue */
    116  1.27    bouyer struct scsipi_device ch_switch = {
    117  1.20   thorpej 	NULL, NULL, NULL, NULL
    118   1.6   mycroft };
    119   1.6   mycroft 
    120  1.20   thorpej int	ch_move __P((struct ch_softc *, struct changer_move *));
    121  1.20   thorpej int	ch_exchange __P((struct ch_softc *, struct changer_exchange *));
    122  1.20   thorpej int	ch_position __P((struct ch_softc *, struct changer_position *));
    123  1.28    mjacob int	ch_ielem __P((struct ch_softc *));
    124  1.20   thorpej int	ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *));
    125  1.20   thorpej int	ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t));
    126  1.20   thorpej int	ch_get_params __P((struct ch_softc *, int));
    127  1.29     enami void	ch_get_quirks __P((struct ch_softc *,
    128  1.29     enami 	    struct scsipi_inquiry_pattern *));
    129  1.26   thorpej 
    130  1.26   thorpej /*
    131  1.26   thorpej  * SCSI changer quirks.
    132  1.26   thorpej  */
    133  1.26   thorpej struct chquirk {
    134  1.27    bouyer 	struct	scsipi_inquiry_pattern cq_match; /* device id pattern */
    135  1.26   thorpej 	int	cq_settledelay;	/* settle delay, in seconds */
    136  1.26   thorpej };
    137  1.26   thorpej 
    138  1.26   thorpej struct chquirk chquirks[] = {
    139  1.26   thorpej 	{{T_CHANGER, T_REMOV,
    140  1.26   thorpej 	  "SPECTRA",	"9000",		"0200"},
    141  1.26   thorpej 	 75},
    142  1.26   thorpej };
    143  1.13   mycroft 
    144  1.13   mycroft int
    145  1.13   mycroft chmatch(parent, match, aux)
    146  1.13   mycroft 	struct device *parent;
    147  1.25       cgd #ifdef __BROKEN_INDIRECT_CONFIG
    148  1.25       cgd 	void *match;
    149  1.25       cgd #else
    150  1.25       cgd 	struct cfdata *match;
    151  1.25       cgd #endif
    152  1.25       cgd 	void *aux;
    153  1.13   mycroft {
    154  1.27    bouyer 	struct scsipibus_attach_args *sa = aux;
    155  1.13   mycroft 	int priority;
    156  1.13   mycroft 
    157  1.27    bouyer 	(void)scsipi_inqmatch(&sa->sa_inqbuf,
    158  1.29     enami 	    (caddr_t)ch_patterns, sizeof(ch_patterns) / sizeof(ch_patterns[0]),
    159  1.13   mycroft 	    sizeof(ch_patterns[0]), &priority);
    160  1.20   thorpej 
    161  1.13   mycroft 	return (priority);
    162  1.13   mycroft }
    163  1.13   mycroft 
    164  1.20   thorpej void
    165   1.6   mycroft chattach(parent, self, aux)
    166   1.6   mycroft 	struct device *parent, *self;
    167   1.6   mycroft 	void *aux;
    168   1.1       cgd {
    169  1.20   thorpej 	struct ch_softc *sc = (struct ch_softc *)self;
    170  1.27    bouyer 	struct scsipibus_attach_args *sa = aux;
    171  1.27    bouyer 	struct scsipi_link *link = sa->sa_sc_link;
    172  1.20   thorpej 
    173  1.20   thorpej 	/* Glue into the SCSI bus */
    174  1.20   thorpej 	sc->sc_link = link;
    175  1.20   thorpej 	link->device = &ch_switch;
    176  1.20   thorpej 	link->device_softc = sc;
    177  1.20   thorpej 	link->openings = 1;
    178   1.1       cgd 
    179  1.24  christos 	printf("\n");
    180   1.1       cgd 
    181   1.6   mycroft 	/*
    182  1.26   thorpej 	 * Find out our device's quirks.
    183  1.26   thorpej 	 */
    184  1.27    bouyer 	ch_get_quirks(sc, &sa->sa_inqbuf);
    185  1.26   thorpej 
    186  1.26   thorpej 	/*
    187  1.26   thorpej 	 * Some changers require a long time to settle out, to do
    188  1.26   thorpej 	 * tape inventory, for instance.
    189  1.26   thorpej 	 */
    190  1.26   thorpej 	if (sc->sc_settledelay) {
    191  1.26   thorpej 		printf("%s: waiting %d seconds for changer to settle...\n",
    192  1.26   thorpej 		    sc->sc_dev.dv_xname, sc->sc_settledelay);
    193  1.26   thorpej 		delay(1000000 * sc->sc_settledelay);
    194  1.26   thorpej 	}
    195  1.26   thorpej 
    196  1.26   thorpej 	/*
    197  1.20   thorpej 	 * Get information about the device.  Note we can't use
    198  1.20   thorpej 	 * interrupts yet.
    199   1.6   mycroft 	 */
    200  1.20   thorpej 	if (ch_get_params(sc, SCSI_AUTOCONF))
    201  1.24  christos 		printf("%s: offline\n", sc->sc_dev.dv_xname);
    202  1.20   thorpej 	else {
    203  1.26   thorpej #define PLURAL(c)	(c) == 1 ? "" : "s"
    204  1.26   thorpej 		printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
    205  1.20   thorpej 		    sc->sc_dev.dv_xname,
    206  1.26   thorpej 		    sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
    207  1.26   thorpej 		    sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
    208  1.26   thorpej 		    sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
    209  1.26   thorpej 		    sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
    210  1.26   thorpej #undef PLURAL
    211  1.20   thorpej #ifdef CHANGER_DEBUG
    212  1.24  christos 		printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
    213  1.20   thorpej 		    sc->sc_dev.dv_xname,
    214  1.20   thorpej 		    sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
    215  1.20   thorpej 		    sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
    216  1.24  christos 		printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
    217  1.20   thorpej 		    sc->sc_dev.dv_xname,
    218  1.20   thorpej 		    sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
    219  1.20   thorpej 		    sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
    220  1.20   thorpej #endif /* CHANGER_DEBUG */
    221  1.20   thorpej 	}
    222   1.6   mycroft 
    223  1.20   thorpej 	/* Default the current picker. */
    224  1.20   thorpej 	sc->sc_picker = sc->sc_firsts[CHET_MT];
    225   1.1       cgd }
    226   1.1       cgd 
    227  1.20   thorpej int
    228  1.20   thorpej chopen(dev, flags, fmt, p)
    229   1.6   mycroft 	dev_t dev;
    230  1.20   thorpej 	int flags, fmt;
    231  1.15  christos 	struct proc *p;
    232   1.1       cgd {
    233  1.20   thorpej 	struct ch_softc *sc;
    234  1.20   thorpej 	int unit, error = 0;
    235   1.6   mycroft 
    236   1.6   mycroft 	unit = CHUNIT(dev);
    237  1.20   thorpej 	if ((unit >= ch_cd.cd_ndevs) ||
    238  1.20   thorpej 	    ((sc = ch_cd.cd_devs[unit]) == NULL))
    239  1.20   thorpej 		return (ENXIO);
    240  1.12   mycroft 
    241  1.12   mycroft 	/*
    242  1.20   thorpej 	 * Only allow one open at a time.
    243  1.12   mycroft 	 */
    244  1.20   thorpej 	if (sc->sc_link->flags & SDEV_OPEN)
    245  1.20   thorpej 		return (EBUSY);
    246  1.20   thorpej 
    247  1.20   thorpej 	sc->sc_link->flags |= SDEV_OPEN;
    248   1.6   mycroft 
    249   1.6   mycroft 	/*
    250  1.20   thorpej 	 * Absorb any unit attention errors.  Ignore "not ready"
    251  1.20   thorpej 	 * since this might occur if e.g. a tape isn't actually
    252  1.20   thorpej 	 * loaded in the drive.
    253   1.6   mycroft 	 */
    254  1.27    bouyer 	error = scsipi_test_unit_ready(sc->sc_link,
    255  1.21  christos 	    SCSI_IGNORE_NOT_READY|SCSI_IGNORE_MEDIA_CHANGE);
    256  1.21  christos 	if (error)
    257  1.13   mycroft 		goto bad;
    258   1.6   mycroft 
    259   1.6   mycroft 	/*
    260  1.20   thorpej 	 * Make sure our parameters are up to date.
    261   1.6   mycroft 	 */
    262  1.21  christos 	if ((error = ch_get_params(sc, 0)) != 0)
    263  1.12   mycroft 		goto bad;
    264   1.6   mycroft 
    265  1.20   thorpej 	return (0);
    266  1.12   mycroft 
    267  1.20   thorpej  bad:
    268  1.20   thorpej 	sc->sc_link->flags &= ~SDEV_OPEN;
    269  1.20   thorpej 	return (error);
    270   1.6   mycroft }
    271   1.6   mycroft 
    272  1.20   thorpej int
    273  1.20   thorpej chclose(dev, flags, fmt, p)
    274   1.6   mycroft 	dev_t dev;
    275  1.20   thorpej 	int flags, fmt;
    276  1.15  christos 	struct proc *p;
    277   1.1       cgd {
    278  1.20   thorpej 	struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
    279   1.6   mycroft 
    280  1.20   thorpej 	sc->sc_link->flags &= ~SDEV_OPEN;
    281  1.20   thorpej 	return (0);
    282   1.6   mycroft }
    283   1.6   mycroft 
    284  1.20   thorpej int
    285  1.20   thorpej chioctl(dev, cmd, data, flags, p)
    286   1.6   mycroft 	dev_t dev;
    287  1.10       cgd 	u_long cmd;
    288  1.20   thorpej 	caddr_t data;
    289  1.20   thorpej 	int flags;
    290  1.13   mycroft 	struct proc *p;
    291   1.6   mycroft {
    292  1.20   thorpej 	struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
    293  1.20   thorpej 	int error = 0;
    294  1.22   thorpej 
    295  1.22   thorpej 	/*
    296  1.22   thorpej 	 * If this command can change the device's state, we must
    297  1.22   thorpej 	 * have the device open for writing.
    298  1.22   thorpej 	 */
    299  1.22   thorpej 	switch (cmd) {
    300  1.22   thorpej 	case CHIOGPICKER:
    301  1.22   thorpej 	case CHIOGPARAMS:
    302  1.22   thorpej 	case CHIOGSTATUS:
    303  1.22   thorpej 		break;
    304  1.22   thorpej 
    305  1.22   thorpej 	default:
    306  1.22   thorpej 		if ((flags & FWRITE) == 0)
    307  1.22   thorpej 			return (EBADF);
    308  1.22   thorpej 	}
    309  1.20   thorpej 
    310  1.20   thorpej 	switch (cmd) {
    311  1.20   thorpej 	case CHIOMOVE:
    312  1.20   thorpej 		error = ch_move(sc, (struct changer_move *)data);
    313  1.20   thorpej 		break;
    314  1.20   thorpej 
    315  1.20   thorpej 	case CHIOEXCHANGE:
    316  1.20   thorpej 		error = ch_exchange(sc, (struct changer_exchange *)data);
    317  1.20   thorpej 		break;
    318  1.20   thorpej 
    319  1.20   thorpej 	case CHIOPOSITION:
    320  1.20   thorpej 		error = ch_position(sc, (struct changer_position *)data);
    321  1.20   thorpej 		break;
    322  1.20   thorpej 
    323  1.20   thorpej 	case CHIOGPICKER:
    324  1.20   thorpej 		*(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
    325  1.20   thorpej 		break;
    326  1.20   thorpej 
    327  1.20   thorpej 	case CHIOSPICKER:	{
    328  1.20   thorpej 		int new_picker = *(int *)data;
    329  1.20   thorpej 
    330  1.20   thorpej 		if (new_picker > (sc->sc_counts[CHET_MT] - 1))
    331  1.20   thorpej 			return (EINVAL);
    332  1.20   thorpej 		sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
    333  1.20   thorpej 		break;		}
    334  1.20   thorpej 
    335  1.20   thorpej 	case CHIOGPARAMS:	{
    336  1.20   thorpej 		struct changer_params *cp = (struct changer_params *)data;
    337  1.20   thorpej 
    338  1.20   thorpej 		cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
    339  1.20   thorpej 		cp->cp_npickers = sc->sc_counts[CHET_MT];
    340  1.20   thorpej 		cp->cp_nslots = sc->sc_counts[CHET_ST];
    341  1.20   thorpej 		cp->cp_nportals = sc->sc_counts[CHET_IE];
    342  1.20   thorpej 		cp->cp_ndrives = sc->sc_counts[CHET_DT];
    343  1.20   thorpej 		break;		}
    344  1.20   thorpej 
    345  1.28    mjacob 	case CHIOIELEM:
    346  1.28    mjacob 		error = ch_ielem(sc);
    347  1.28    mjacob 		break;
    348  1.28    mjacob 
    349  1.20   thorpej 	case CHIOGSTATUS:	{
    350  1.20   thorpej 		struct changer_element_status *ces =
    351  1.20   thorpej 		    (struct changer_element_status *)data;
    352  1.20   thorpej 
    353  1.20   thorpej 		error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data);
    354  1.20   thorpej 		break;		}
    355   1.6   mycroft 
    356  1.20   thorpej 	/* Implement prevent/allow? */
    357   1.6   mycroft 
    358   1.1       cgd 	default:
    359  1.27    bouyer 		error = scsipi_do_ioctl(sc->sc_link, dev, cmd, data, flags, p);
    360  1.20   thorpej 		break;
    361   1.1       cgd 	}
    362  1.20   thorpej 
    363  1.20   thorpej 	return (error);
    364   1.1       cgd }
    365   1.1       cgd 
    366  1.20   thorpej int
    367  1.20   thorpej ch_move(sc, cm)
    368  1.20   thorpej 	struct ch_softc *sc;
    369  1.20   thorpej 	struct changer_move *cm;
    370   1.1       cgd {
    371  1.20   thorpej 	struct scsi_move_medium cmd;
    372  1.20   thorpej 	u_int16_t fromelem, toelem;
    373  1.20   thorpej 
    374  1.20   thorpej 	/*
    375  1.20   thorpej 	 * Check arguments.
    376  1.20   thorpej 	 */
    377  1.20   thorpej 	if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
    378  1.20   thorpej 		return (EINVAL);
    379  1.20   thorpej 	if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
    380  1.20   thorpej 	    (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
    381  1.20   thorpej 		return (ENODEV);
    382  1.20   thorpej 
    383  1.20   thorpej 	/*
    384  1.20   thorpej 	 * Check the request against the changer's capabilities.
    385  1.20   thorpej 	 */
    386  1.20   thorpej 	if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
    387  1.20   thorpej 		return (EINVAL);
    388  1.20   thorpej 
    389  1.20   thorpej 	/*
    390  1.20   thorpej 	 * Calculate the source and destination elements.
    391  1.20   thorpej 	 */
    392  1.20   thorpej 	fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
    393  1.20   thorpej 	toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
    394  1.20   thorpej 
    395  1.20   thorpej 	/*
    396  1.20   thorpej 	 * Build the SCSI command.
    397  1.20   thorpej 	 */
    398  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    399  1.20   thorpej 	cmd.opcode = MOVE_MEDIUM;
    400  1.20   thorpej 	_lto2b(sc->sc_picker, cmd.tea);
    401  1.20   thorpej 	_lto2b(fromelem, cmd.src);
    402  1.20   thorpej 	_lto2b(toelem, cmd.dst);
    403  1.20   thorpej 	if (cm->cm_flags & CM_INVERT)
    404  1.20   thorpej 		cmd.flags |= MOVE_MEDIUM_INVERT;
    405  1.20   thorpej 
    406  1.20   thorpej 	/*
    407  1.20   thorpej 	 * Send command to changer.
    408  1.20   thorpej 	 */
    409  1.31   thorpej 	return (scsipi_command(sc->sc_link,
    410  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES,
    411  1.29     enami 	    100000, NULL, 0));
    412   1.1       cgd }
    413   1.1       cgd 
    414  1.20   thorpej int
    415  1.20   thorpej ch_exchange(sc, ce)
    416  1.20   thorpej 	struct ch_softc *sc;
    417  1.20   thorpej 	struct changer_exchange *ce;
    418  1.20   thorpej {
    419  1.20   thorpej 	struct scsi_exchange_medium cmd;
    420  1.20   thorpej 	u_int16_t src, dst1, dst2;
    421  1.20   thorpej 
    422  1.20   thorpej 	/*
    423  1.20   thorpej 	 * Check arguments.
    424  1.20   thorpej 	 */
    425  1.20   thorpej 	if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
    426  1.20   thorpej 	    (ce->ce_sdsttype > CHET_DT))
    427  1.20   thorpej 		return (EINVAL);
    428  1.20   thorpej 	if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
    429  1.20   thorpej 	    (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
    430  1.20   thorpej 	    (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
    431  1.20   thorpej 		return (ENODEV);
    432  1.20   thorpej 
    433  1.20   thorpej 	/*
    434  1.20   thorpej 	 * Check the request against the changer's capabilities.
    435  1.20   thorpej 	 */
    436  1.20   thorpej 	if (((sc->sc_exchangemask[ce->ce_srctype] &
    437  1.20   thorpej 	     (1 << ce->ce_fdsttype)) == 0) ||
    438  1.20   thorpej 	    ((sc->sc_exchangemask[ce->ce_fdsttype] &
    439  1.20   thorpej 	     (1 << ce->ce_sdsttype)) == 0))
    440  1.20   thorpej 		return (EINVAL);
    441  1.20   thorpej 
    442  1.20   thorpej 	/*
    443  1.20   thorpej 	 * Calculate the source and destination elements.
    444  1.20   thorpej 	 */
    445  1.20   thorpej 	src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
    446  1.20   thorpej 	dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
    447  1.20   thorpej 	dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
    448  1.20   thorpej 
    449  1.20   thorpej 	/*
    450  1.20   thorpej 	 * Build the SCSI command.
    451  1.20   thorpej 	 */
    452  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    453  1.20   thorpej 	cmd.opcode = EXCHANGE_MEDIUM;
    454  1.20   thorpej 	_lto2b(sc->sc_picker, cmd.tea);
    455  1.20   thorpej 	_lto2b(src, cmd.src);
    456  1.20   thorpej 	_lto2b(dst1, cmd.fdst);
    457  1.20   thorpej 	_lto2b(dst2, cmd.sdst);
    458  1.20   thorpej 	if (ce->ce_flags & CE_INVERT1)
    459  1.20   thorpej 		cmd.flags |= EXCHANGE_MEDIUM_INV1;
    460  1.20   thorpej 	if (ce->ce_flags & CE_INVERT2)
    461  1.20   thorpej 		cmd.flags |= EXCHANGE_MEDIUM_INV2;
    462  1.20   thorpej 
    463  1.20   thorpej 	/*
    464  1.20   thorpej 	 * Send command to changer.
    465  1.20   thorpej 	 */
    466  1.31   thorpej 	return (scsipi_command(sc->sc_link,
    467  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES,
    468  1.29     enami 	    100000, NULL, 0));
    469   1.1       cgd }
    470   1.1       cgd 
    471  1.20   thorpej int
    472  1.20   thorpej ch_position(sc, cp)
    473  1.20   thorpej 	struct ch_softc *sc;
    474  1.20   thorpej 	struct changer_position *cp;
    475  1.20   thorpej {
    476  1.20   thorpej 	struct scsi_position_to_element cmd;
    477  1.20   thorpej 	u_int16_t dst;
    478  1.20   thorpej 
    479  1.20   thorpej 	/*
    480  1.20   thorpej 	 * Check arguments.
    481  1.20   thorpej 	 */
    482  1.20   thorpej 	if (cp->cp_type > CHET_DT)
    483  1.20   thorpej 		return (EINVAL);
    484  1.20   thorpej 	if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
    485  1.20   thorpej 		return (ENODEV);
    486  1.20   thorpej 
    487  1.20   thorpej 	/*
    488  1.20   thorpej 	 * Calculate the destination element.
    489  1.20   thorpej 	 */
    490  1.20   thorpej 	dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
    491  1.20   thorpej 
    492  1.20   thorpej 	/*
    493  1.20   thorpej 	 * Build the SCSI command.
    494  1.20   thorpej 	 */
    495  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    496  1.20   thorpej 	cmd.opcode = POSITION_TO_ELEMENT;
    497  1.20   thorpej 	_lto2b(sc->sc_picker, cmd.tea);
    498  1.20   thorpej 	_lto2b(dst, cmd.dst);
    499  1.20   thorpej 	if (cp->cp_flags & CP_INVERT)
    500  1.20   thorpej 		cmd.flags |= POSITION_TO_ELEMENT_INVERT;
    501  1.20   thorpej 
    502  1.20   thorpej 	/*
    503  1.20   thorpej 	 * Send command to changer.
    504  1.20   thorpej 	 */
    505  1.31   thorpej 	return (scsipi_command(sc->sc_link,
    506  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES,
    507  1.29     enami 	    100000, NULL, 0));
    508   1.1       cgd }
    509   1.1       cgd 
    510   1.6   mycroft /*
    511  1.20   thorpej  * Perform a READ ELEMENT STATUS on behalf of the user, and return to
    512  1.20   thorpej  * the user only the data the user is interested in (i.e. an array of
    513  1.20   thorpej  * flags bytes).
    514   1.6   mycroft  */
    515  1.20   thorpej int
    516  1.20   thorpej ch_usergetelemstatus(sc, chet, uptr)
    517  1.20   thorpej 	struct ch_softc *sc;
    518  1.20   thorpej 	int chet;
    519  1.20   thorpej 	u_int8_t *uptr;
    520  1.20   thorpej {
    521  1.20   thorpej 	struct read_element_status_header *st_hdr;
    522  1.20   thorpej 	struct read_element_status_page_header *pg_hdr;
    523  1.20   thorpej 	struct read_element_status_descriptor *desc;
    524  1.20   thorpej 	caddr_t data = NULL;
    525  1.20   thorpej 	size_t size, desclen;
    526  1.20   thorpej 	int avail, i, error = 0;
    527  1.20   thorpej 	u_int8_t *user_data = NULL;
    528  1.20   thorpej 
    529  1.20   thorpej 	/*
    530  1.20   thorpej 	 * If there are no elements of the requested type in the changer,
    531  1.20   thorpej 	 * the request is invalid.
    532  1.20   thorpej 	 */
    533  1.20   thorpej 	if (sc->sc_counts[chet] == 0)
    534  1.20   thorpej 		return (EINVAL);
    535  1.20   thorpej 
    536  1.20   thorpej 	/*
    537  1.20   thorpej 	 * Request one descriptor for the given element type.  This
    538  1.20   thorpej 	 * is used to determine the size of the descriptor so that
    539  1.20   thorpej 	 * we can allocate enough storage for all of them.  We assume
    540  1.20   thorpej 	 * that the first one can fit into 1k.
    541  1.20   thorpej 	 */
    542  1.20   thorpej 	data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
    543  1.21  christos 	error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024);
    544  1.21  christos 	if (error)
    545  1.20   thorpej 		goto done;
    546  1.20   thorpej 
    547  1.20   thorpej 	st_hdr = (struct read_element_status_header *)data;
    548  1.20   thorpej 	pg_hdr = (struct read_element_status_page_header *)((u_long)st_hdr +
    549  1.20   thorpej 	    sizeof(struct read_element_status_header));
    550  1.20   thorpej 	desclen = _2btol(pg_hdr->edl);
    551  1.20   thorpej 
    552  1.20   thorpej 	size = sizeof(struct read_element_status_header) +
    553  1.20   thorpej 	    sizeof(struct read_element_status_page_header) +
    554  1.20   thorpej 	    (desclen * sc->sc_counts[chet]);
    555  1.20   thorpej 
    556  1.20   thorpej 	/*
    557  1.20   thorpej 	 * Reallocate storage for descriptors and get them from the
    558  1.20   thorpej 	 * device.
    559  1.20   thorpej 	 */
    560  1.20   thorpej 	free(data, M_DEVBUF);
    561  1.20   thorpej 	data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
    562  1.21  christos 	error = ch_getelemstatus(sc, sc->sc_firsts[chet],
    563  1.21  christos 	    sc->sc_counts[chet], data, size);
    564  1.21  christos 	if (error)
    565  1.20   thorpej 		goto done;
    566  1.20   thorpej 
    567  1.20   thorpej 	/*
    568  1.20   thorpej 	 * Fill in the user status array.
    569  1.20   thorpej 	 */
    570  1.20   thorpej 	st_hdr = (struct read_element_status_header *)data;
    571  1.20   thorpej 	avail = _2btol(st_hdr->count);
    572  1.28    mjacob 
    573  1.20   thorpej 	if (avail != sc->sc_counts[chet])
    574  1.24  christos 		printf("%s: warning, READ ELEMENT STATUS avail != count\n",
    575  1.20   thorpej 		    sc->sc_dev.dv_xname);
    576  1.20   thorpej 
    577  1.20   thorpej 	user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK);
    578  1.20   thorpej 
    579  1.20   thorpej 	desc = (struct read_element_status_descriptor *)((u_long)data +
    580  1.20   thorpej 	    sizeof(struct read_element_status_header) +
    581  1.20   thorpej 	    sizeof(struct read_element_status_page_header));
    582  1.20   thorpej 	for (i = 0; i < avail; ++i) {
    583  1.20   thorpej 		user_data[i] = desc->flags1;
    584  1.20   thorpej 		(u_long)desc += desclen;
    585  1.20   thorpej 	}
    586  1.20   thorpej 
    587  1.20   thorpej 	/* Copy flags array out to userspace. */
    588  1.20   thorpej 	error = copyout(user_data, uptr, avail);
    589  1.20   thorpej 
    590  1.20   thorpej  done:
    591  1.20   thorpej 	if (data != NULL)
    592  1.20   thorpej 		free(data, M_DEVBUF);
    593  1.20   thorpej 	if (user_data != NULL)
    594  1.20   thorpej 		free(user_data, M_DEVBUF);
    595  1.20   thorpej 	return (error);
    596  1.20   thorpej }
    597  1.20   thorpej 
    598  1.20   thorpej int
    599  1.20   thorpej ch_getelemstatus(sc, first, count, data, datalen)
    600  1.20   thorpej 	struct ch_softc *sc;
    601  1.20   thorpej 	int first, count;
    602  1.20   thorpej 	caddr_t data;
    603  1.20   thorpej 	size_t datalen;
    604   1.1       cgd {
    605  1.20   thorpej 	struct scsi_read_element_status cmd;
    606   1.6   mycroft 
    607   1.6   mycroft 	/*
    608  1.20   thorpej 	 * Build SCSI command.
    609   1.6   mycroft 	 */
    610  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    611  1.20   thorpej 	cmd.opcode = READ_ELEMENT_STATUS;
    612  1.20   thorpej 	_lto2b(first, cmd.sea);
    613  1.20   thorpej 	_lto2b(count, cmd.count);
    614  1.20   thorpej 	_lto3b(datalen, cmd.len);
    615   1.6   mycroft 
    616   1.6   mycroft 	/*
    617  1.20   thorpej 	 * Send command to changer.
    618   1.6   mycroft 	 */
    619  1.31   thorpej 	return (scsipi_command(sc->sc_link,
    620  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd),
    621  1.30   thorpej 	    (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN));
    622  1.20   thorpej }
    623  1.20   thorpej 
    624  1.20   thorpej 
    625  1.28    mjacob int
    626  1.28    mjacob ch_ielem(sc)
    627  1.28    mjacob 	struct ch_softc *sc;
    628  1.28    mjacob {
    629  1.33    mjacob 	int tmo;
    630  1.28    mjacob 	struct scsi_initialize_element_status cmd;
    631  1.28    mjacob 
    632  1.28    mjacob 	/*
    633  1.28    mjacob 	 * Build SCSI command.
    634  1.28    mjacob 	 */
    635  1.28    mjacob 	bzero(&cmd, sizeof(cmd));
    636  1.28    mjacob 	cmd.opcode = INITIALIZE_ELEMENT_STATUS;
    637  1.28    mjacob 
    638  1.28    mjacob 	/*
    639  1.28    mjacob 	 * Send command to changer.
    640  1.33    mjacob 	 *
    641  1.33    mjacob 	 * The problem is, how long to allow for the command?
    642  1.33    mjacob 	 * It can take a *really* long time, and also depends
    643  1.33    mjacob 	 * on unknowable factors such as whether there are
    644  1.33    mjacob 	 * *almost* readable labels on tapes that a barcode
    645  1.33    mjacob 	 * reader is trying to decipher.
    646  1.33    mjacob 	 *
    647  1.33    mjacob 	 * I'm going to make this long enough to allow 5 minutes
    648  1.33    mjacob 	 * per element plus an initial 10 minute wait.
    649  1.33    mjacob 	 */
    650  1.33    mjacob 	tmo =	sc->sc_counts[CHET_MT] +
    651  1.33    mjacob 		sc->sc_counts[CHET_ST] +
    652  1.33    mjacob 		sc->sc_counts[CHET_IE] +
    653  1.33    mjacob 		sc->sc_counts[CHET_DT];
    654  1.33    mjacob 	tmo *= 5 * 1000;
    655  1.33    mjacob 	tmo += (10 * 60 * 1000);
    656  1.33    mjacob 
    657  1.31   thorpej 	return (scsipi_command(sc->sc_link,
    658  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd),
    659  1.33    mjacob 	    NULL, 0, CHRETRIES, tmo, NULL, 0));
    660  1.28    mjacob }
    661  1.28    mjacob 
    662  1.20   thorpej /*
    663  1.20   thorpej  * Ask the device about itself and fill in the parameters in our
    664  1.20   thorpej  * softc.
    665  1.20   thorpej  */
    666  1.20   thorpej int
    667  1.20   thorpej ch_get_params(sc, scsiflags)
    668  1.20   thorpej 	struct ch_softc *sc;
    669  1.20   thorpej 	int scsiflags;
    670  1.20   thorpej {
    671  1.20   thorpej 	struct scsi_mode_sense cmd;
    672  1.20   thorpej 	struct scsi_mode_sense_data {
    673  1.20   thorpej 		struct scsi_mode_header header;
    674  1.20   thorpej 		union {
    675  1.20   thorpej 			struct page_element_address_assignment ea;
    676  1.20   thorpej 			struct page_transport_geometry_parameters tg;
    677  1.20   thorpej 			struct page_device_capabilities cap;
    678  1.20   thorpej 		} pages;
    679  1.20   thorpej 	} sense_data;
    680  1.20   thorpej 	int error, from;
    681  1.20   thorpej 	u_int8_t *moves, *exchanges;
    682   1.6   mycroft 
    683   1.6   mycroft 	/*
    684  1.20   thorpej 	 * Grab info from the element address assignment page.
    685   1.6   mycroft 	 */
    686  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    687  1.20   thorpej 	bzero(&sense_data, sizeof(sense_data));
    688  1.27    bouyer 	cmd.opcode = SCSI_MODE_SENSE;
    689  1.20   thorpej 	cmd.byte2 |= 0x08;	/* disable block descriptors */
    690  1.20   thorpej 	cmd.page = 0x1d;
    691  1.20   thorpej 	cmd.length = (sizeof(sense_data) & 0xff);
    692  1.31   thorpej 	error = scsipi_command(sc->sc_link,
    693  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&sense_data,
    694  1.29     enami 	    sizeof(sense_data), CHRETRIES, 6000, NULL,
    695  1.29     enami 	    scsiflags | SCSI_DATA_IN);
    696  1.15  christos 	if (error) {
    697  1.24  christos 		printf("%s: could not sense element address page\n",
    698  1.21  christos 		    sc->sc_dev.dv_xname);
    699  1.20   thorpej 		return (error);
    700   1.6   mycroft 	}
    701   1.6   mycroft 
    702  1.20   thorpej 	sc->sc_firsts[CHET_MT] = _2btol(sense_data.pages.ea.mtea);
    703  1.20   thorpej 	sc->sc_counts[CHET_MT] = _2btol(sense_data.pages.ea.nmte);
    704  1.20   thorpej 	sc->sc_firsts[CHET_ST] = _2btol(sense_data.pages.ea.fsea);
    705  1.20   thorpej 	sc->sc_counts[CHET_ST] = _2btol(sense_data.pages.ea.nse);
    706  1.20   thorpej 	sc->sc_firsts[CHET_IE] = _2btol(sense_data.pages.ea.fieea);
    707  1.20   thorpej 	sc->sc_counts[CHET_IE] = _2btol(sense_data.pages.ea.niee);
    708  1.20   thorpej 	sc->sc_firsts[CHET_DT] = _2btol(sense_data.pages.ea.fdtea);
    709  1.20   thorpej 	sc->sc_counts[CHET_DT] = _2btol(sense_data.pages.ea.ndte);
    710  1.20   thorpej 
    711  1.20   thorpej 	/* XXX ask for page trasport geom */
    712   1.6   mycroft 
    713   1.6   mycroft 	/*
    714  1.20   thorpej 	 * Grab info from the capabilities page.
    715  1.20   thorpej 	 */
    716  1.20   thorpej 	bzero(&cmd, sizeof(cmd));
    717  1.20   thorpej 	bzero(&sense_data, sizeof(sense_data));
    718  1.27    bouyer 	cmd.opcode = SCSI_MODE_SENSE;
    719  1.28    mjacob 	/*
    720  1.28    mjacob 	 * XXX: Note: not all changers can deal with disabled block descriptors
    721  1.28    mjacob 	 */
    722  1.28    mjacob 	cmd.byte2 = 0x08;	/* disable block descriptors */
    723  1.20   thorpej 	cmd.page = 0x1f;
    724  1.20   thorpej 	cmd.length = (sizeof(sense_data) & 0xff);
    725  1.31   thorpej 	error = scsipi_command(sc->sc_link,
    726  1.29     enami 	    (struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&sense_data,
    727  1.29     enami 	    sizeof(sense_data), CHRETRIES, 6000, NULL,
    728  1.29     enami 	    scsiflags | SCSI_DATA_IN);
    729  1.20   thorpej 	if (error) {
    730  1.24  christos 		printf("%s: could not sense capabilities page\n",
    731  1.21  christos 		    sc->sc_dev.dv_xname);
    732  1.20   thorpej 		return (error);
    733  1.20   thorpej 	}
    734  1.20   thorpej 
    735  1.20   thorpej 	bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
    736  1.20   thorpej 	bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
    737  1.20   thorpej 	moves = &sense_data.pages.cap.move_from_mt;
    738  1.20   thorpej 	exchanges = &sense_data.pages.cap.exchange_with_mt;
    739  1.20   thorpej 	for (from = CHET_MT; from <= CHET_DT; ++from) {
    740  1.20   thorpej 		sc->sc_movemask[from] = moves[from];
    741  1.20   thorpej 		sc->sc_exchangemask[from] = exchanges[from];
    742   1.1       cgd 	}
    743  1.20   thorpej 
    744  1.20   thorpej 	sc->sc_link->flags |= SDEV_MEDIA_LOADED;
    745  1.20   thorpej 	return (0);
    746  1.26   thorpej }
    747  1.26   thorpej 
    748  1.26   thorpej void
    749  1.26   thorpej ch_get_quirks(sc, inqbuf)
    750  1.26   thorpej 	struct ch_softc *sc;
    751  1.27    bouyer 	struct scsipi_inquiry_pattern *inqbuf;
    752  1.26   thorpej {
    753  1.26   thorpej 	struct chquirk *match;
    754  1.26   thorpej 	int priority;
    755  1.26   thorpej 
    756  1.26   thorpej 	sc->sc_settledelay = 0;
    757  1.26   thorpej 
    758  1.27    bouyer 	match = (struct chquirk *)scsipi_inqmatch(inqbuf,
    759  1.26   thorpej 	    (caddr_t)chquirks,
    760  1.26   thorpej 	    sizeof(chquirks) / sizeof(chquirks[0]),
    761  1.26   thorpej 	    sizeof(chquirks[0]), &priority);
    762  1.29     enami 	if (priority != 0)
    763  1.26   thorpej 		sc->sc_settledelay = match->cq_settledelay;
    764   1.1       cgd }
    765