Home | History | Annotate | Line # | Download | only in mscp
mscp_tape.c revision 1.27.2.2
      1  1.27.2.2  elad /*	$NetBSD: mscp_tape.c,v 1.27.2.2 2006/04/19 03:25:24 elad Exp $ */
      2  1.27.2.2  elad /*
      3  1.27.2.2  elad  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
      4  1.27.2.2  elad  * All rights reserved.
      5  1.27.2.2  elad  *
      6  1.27.2.2  elad  * Redistribution and use in source and binary forms, with or without
      7  1.27.2.2  elad  * modification, are permitted provided that the following conditions
      8  1.27.2.2  elad  * are met:
      9  1.27.2.2  elad  * 1. Redistributions of source code must retain the above copyright
     10  1.27.2.2  elad  *    notice, this list of conditions and the following disclaimer.
     11  1.27.2.2  elad  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.27.2.2  elad  *    notice, this list of conditions and the following disclaimer in the
     13  1.27.2.2  elad  *    documentation and/or other materials provided with the distribution.
     14  1.27.2.2  elad  * 3. All advertising materials mentioning features or use of this software
     15  1.27.2.2  elad  *    must display the following acknowledgement:
     16  1.27.2.2  elad  *	This product includes software developed at Ludd, University of
     17  1.27.2.2  elad  *	Lule}, Sweden and its contributors.
     18  1.27.2.2  elad  * 4. The name of the author may not be used to endorse or promote products
     19  1.27.2.2  elad  *    derived from this software without specific prior written permission
     20  1.27.2.2  elad  *
     21  1.27.2.2  elad  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  1.27.2.2  elad  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  1.27.2.2  elad  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  1.27.2.2  elad  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  1.27.2.2  elad  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  1.27.2.2  elad  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  1.27.2.2  elad  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  1.27.2.2  elad  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  1.27.2.2  elad  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  1.27.2.2  elad  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  1.27.2.2  elad  */
     32  1.27.2.2  elad 
     33  1.27.2.2  elad 
     34  1.27.2.2  elad /*
     35  1.27.2.2  elad  * MSCP tape device driver
     36  1.27.2.2  elad  */
     37  1.27.2.2  elad 
     38  1.27.2.2  elad /*
     39  1.27.2.2  elad  * TODO
     40  1.27.2.2  elad  *	Write status handling code.
     41  1.27.2.2  elad  */
     42  1.27.2.2  elad 
     43  1.27.2.2  elad #include <sys/cdefs.h>
     44  1.27.2.2  elad __KERNEL_RCSID(0, "$NetBSD: mscp_tape.c,v 1.27.2.2 2006/04/19 03:25:24 elad Exp $");
     45  1.27.2.2  elad 
     46  1.27.2.2  elad #include <sys/param.h>
     47  1.27.2.2  elad #include <sys/device.h>
     48  1.27.2.2  elad #include <sys/kernel.h>
     49  1.27.2.2  elad #include <sys/buf.h>
     50  1.27.2.2  elad #include <sys/bufq.h>
     51  1.27.2.2  elad #include <sys/ioccom.h>
     52  1.27.2.2  elad #include <sys/mtio.h>
     53  1.27.2.2  elad #include <sys/fcntl.h>
     54  1.27.2.2  elad #include <sys/malloc.h>
     55  1.27.2.2  elad #include <sys/systm.h>
     56  1.27.2.2  elad #include <sys/proc.h>
     57  1.27.2.2  elad #include <sys/conf.h>
     58  1.27.2.2  elad 
     59  1.27.2.2  elad #include <machine/bus.h>
     60  1.27.2.2  elad #include <machine/cpu.h>
     61  1.27.2.2  elad 
     62  1.27.2.2  elad #include <dev/mscp/mscp.h>
     63  1.27.2.2  elad #include <dev/mscp/mscpreg.h>
     64  1.27.2.2  elad #include <dev/mscp/mscpvar.h>
     65  1.27.2.2  elad 
     66  1.27.2.2  elad #include "locators.h"
     67  1.27.2.2  elad 
     68  1.27.2.2  elad /*
     69  1.27.2.2  elad  * Drive status, per drive
     70  1.27.2.2  elad  */
     71  1.27.2.2  elad struct mt_softc {
     72  1.27.2.2  elad 	struct	device mt_dev;	/* Autoconf struct */
     73  1.27.2.2  elad 	int	mt_state;	/* open/closed state */
     74  1.27.2.2  elad 	int	mt_hwunit;	/* Hardware unit number */
     75  1.27.2.2  elad 	int	mt_inuse;	/* Locks the tape drive for others */
     76  1.27.2.2  elad 	int	mt_waswrite;	/* Last operation was a write op */
     77  1.27.2.2  elad 	int	mt_serex;	/* Got serious exception */
     78  1.27.2.2  elad 	int	mt_ioctlerr;	/* Error after last ioctl */
     79  1.27.2.2  elad };
     80  1.27.2.2  elad 
     81  1.27.2.2  elad #define MT_OFFLINE	0
     82  1.27.2.2  elad #define MT_ONLINE	1
     83  1.27.2.2  elad 
     84  1.27.2.2  elad int	mtmatch(struct device *, struct cfdata *, void *);
     85  1.27.2.2  elad void	mtattach(struct device *, struct device *, void *);
     86  1.27.2.2  elad void	mtdgram(struct device *, struct mscp *, struct mscp_softc *);
     87  1.27.2.2  elad void	mtiodone(struct device *, struct buf *);
     88  1.27.2.2  elad int	mtonline(struct device *, struct mscp *);
     89  1.27.2.2  elad int	mtgotstatus(struct device *, struct mscp *);
     90  1.27.2.2  elad int	mtioerror(struct device *, struct mscp *, struct buf *);
     91  1.27.2.2  elad void	mtfillin(struct buf *, struct mscp *);
     92  1.27.2.2  elad int	mtcmd(struct mt_softc *, int, int, int);
     93  1.27.2.2  elad void	mtcmddone(struct device *, struct mscp *);
     94  1.27.2.2  elad int	mt_putonline(struct mt_softc *);
     95  1.27.2.2  elad 
     96  1.27.2.2  elad struct	mscp_device mt_device = {
     97  1.27.2.2  elad 	mtdgram,
     98  1.27.2.2  elad 	mtiodone,
     99  1.27.2.2  elad 	mtonline,
    100  1.27.2.2  elad 	mtgotstatus,
    101  1.27.2.2  elad 	0,
    102  1.27.2.2  elad 	mtioerror,
    103  1.27.2.2  elad 	0,
    104  1.27.2.2  elad 	mtfillin,
    105  1.27.2.2  elad 	mtcmddone,
    106  1.27.2.2  elad };
    107  1.27.2.2  elad 
    108  1.27.2.2  elad /* This is not good, should allow more than 4 tapes/device type */
    109  1.27.2.2  elad #define mtunit(dev)	(minor(dev) & T_UNIT)
    110  1.27.2.2  elad #define mtnorewind(dev) (dev & T_NOREWIND)
    111  1.27.2.2  elad #define mthdensity(dev) (dev & T_1600BPI)
    112  1.27.2.2  elad 
    113  1.27.2.2  elad CFATTACH_DECL(mt, sizeof(struct mt_softc),
    114  1.27.2.2  elad     mtmatch, mtattach, NULL, NULL);
    115  1.27.2.2  elad 
    116  1.27.2.2  elad extern struct cfdriver mt_cd;
    117  1.27.2.2  elad 
    118  1.27.2.2  elad dev_type_open(mtopen);
    119  1.27.2.2  elad dev_type_close(mtclose);
    120  1.27.2.2  elad dev_type_read(mtread);
    121  1.27.2.2  elad dev_type_write(mtwrite);
    122  1.27.2.2  elad dev_type_ioctl(mtioctl);
    123  1.27.2.2  elad dev_type_strategy(mtstrategy);
    124  1.27.2.2  elad dev_type_dump(mtdump);
    125  1.27.2.2  elad 
    126  1.27.2.2  elad const struct bdevsw mt_bdevsw = {
    127  1.27.2.2  elad 	mtopen, mtclose, mtstrategy, mtioctl, mtdump, nosize, D_TAPE
    128  1.27.2.2  elad };
    129  1.27.2.2  elad 
    130  1.27.2.2  elad const struct cdevsw mt_cdevsw = {
    131  1.27.2.2  elad 	mtopen, mtclose, mtread, mtwrite, mtioctl,
    132  1.27.2.2  elad 	nostop, notty, nopoll, nommap, nokqfilter, D_TAPE
    133  1.27.2.2  elad };
    134  1.27.2.2  elad 
    135  1.27.2.2  elad /*
    136  1.27.2.2  elad  * More driver definitions, for generic MSCP code.
    137  1.27.2.2  elad  */
    138  1.27.2.2  elad 
    139  1.27.2.2  elad int
    140  1.27.2.2  elad mtmatch(parent, cf, aux)
    141  1.27.2.2  elad 	struct	device *parent;
    142  1.27.2.2  elad 	struct	cfdata *cf;
    143  1.27.2.2  elad 	void	*aux;
    144  1.27.2.2  elad {
    145  1.27.2.2  elad 	struct	drive_attach_args *da = aux;
    146  1.27.2.2  elad 	struct	mscp *mp = da->da_mp;
    147  1.27.2.2  elad 
    148  1.27.2.2  elad 	if ((da->da_typ & MSCPBUS_TAPE) == 0)
    149  1.27.2.2  elad 		return 0;
    150  1.27.2.2  elad 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
    151  1.27.2.2  elad 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
    152  1.27.2.2  elad 		return 0;
    153  1.27.2.2  elad 	return 1;
    154  1.27.2.2  elad }
    155  1.27.2.2  elad 
    156  1.27.2.2  elad /*
    157  1.27.2.2  elad  * The attach routine only checks and prints drive type.
    158  1.27.2.2  elad  */
    159  1.27.2.2  elad void
    160  1.27.2.2  elad mtattach(parent, self, aux)
    161  1.27.2.2  elad 	struct	device *parent, *self;
    162  1.27.2.2  elad 	void	*aux;
    163  1.27.2.2  elad {
    164  1.27.2.2  elad 	struct	mt_softc *mt = device_private(self);
    165  1.27.2.2  elad 	struct	drive_attach_args *da = aux;
    166  1.27.2.2  elad 	struct	mscp *mp = da->da_mp;
    167  1.27.2.2  elad 	struct	mscp_softc *mi = (void *)parent;
    168  1.27.2.2  elad 
    169  1.27.2.2  elad 	mt->mt_hwunit = mp->mscp_unit;
    170  1.27.2.2  elad 	mi->mi_dp[mp->mscp_unit] = self;
    171  1.27.2.2  elad 
    172  1.27.2.2  elad 	disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
    173  1.27.2.2  elad }
    174  1.27.2.2  elad 
    175  1.27.2.2  elad /*
    176  1.27.2.2  elad  * (Try to) put the drive online. This is done the first time the
    177  1.27.2.2  elad  * drive is opened, or if it has fallen offline.
    178  1.27.2.2  elad  */
    179  1.27.2.2  elad int
    180  1.27.2.2  elad mt_putonline(mt)
    181  1.27.2.2  elad 	struct mt_softc *mt;
    182  1.27.2.2  elad {
    183  1.27.2.2  elad 	struct	mscp *mp;
    184  1.27.2.2  elad 	struct	mscp_softc *mi =
    185  1.27.2.2  elad 	    (struct mscp_softc *)device_parent(&mt->mt_dev);
    186  1.27.2.2  elad 	volatile int i;
    187  1.27.2.2  elad 
    188  1.27.2.2  elad 	((volatile struct mt_softc *) mt)->mt_state = MT_OFFLINE;
    189  1.27.2.2  elad 	mp = mscp_getcp(mi, MSCP_WAIT);
    190  1.27.2.2  elad 	mp->mscp_opcode = M_OP_ONLINE;
    191  1.27.2.2  elad 	mp->mscp_unit = mt->mt_hwunit;
    192  1.27.2.2  elad 	mp->mscp_cmdref = (long)&mt->mt_state;
    193  1.27.2.2  elad 	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;
    194  1.27.2.2  elad 
    195  1.27.2.2  elad 	/* Poll away */
    196  1.27.2.2  elad 	i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
    197  1.27.2.2  elad 	if (tsleep(&mt->mt_state, PRIBIO, "mtonline", 240 * hz))
    198  1.27.2.2  elad 		return MSCP_FAILED;
    199  1.27.2.2  elad 
    200  1.27.2.2  elad 	if ((volatile int)mt->mt_state != MT_ONLINE)
    201  1.27.2.2  elad 		return MSCP_FAILED;
    202  1.27.2.2  elad 
    203  1.27.2.2  elad 	return MSCP_DONE;
    204  1.27.2.2  elad }
    205  1.27.2.2  elad /*
    206  1.27.2.2  elad  * Open a drive.
    207  1.27.2.2  elad  */
    208  1.27.2.2  elad /*ARGSUSED*/
    209  1.27.2.2  elad int
    210  1.27.2.2  elad mtopen(dev, flag, fmt, l)
    211  1.27.2.2  elad 	dev_t dev;
    212  1.27.2.2  elad 	int flag, fmt;
    213  1.27.2.2  elad 	struct	lwp *l;
    214  1.27.2.2  elad {
    215  1.27.2.2  elad 	struct mt_softc *mt;
    216  1.27.2.2  elad 	int unit;
    217  1.27.2.2  elad 
    218  1.27.2.2  elad 	/*
    219  1.27.2.2  elad 	 * Make sure this is a reasonable open request.
    220  1.27.2.2  elad 	 */
    221  1.27.2.2  elad 	unit = mtunit(dev);
    222  1.27.2.2  elad 	if (unit >= mt_cd.cd_ndevs)
    223  1.27.2.2  elad 		return ENXIO;
    224  1.27.2.2  elad 	mt = mt_cd.cd_devs[unit];
    225  1.27.2.2  elad 	if (mt == 0)
    226  1.27.2.2  elad 		return ENXIO;
    227  1.27.2.2  elad 
    228  1.27.2.2  elad 	if (mt->mt_inuse)
    229  1.27.2.2  elad 			return EBUSY;
    230  1.27.2.2  elad 	mt->mt_inuse = 1;
    231  1.27.2.2  elad 
    232  1.27.2.2  elad 	if (mt_putonline(mt) == MSCP_FAILED) {
    233  1.27.2.2  elad 		mt->mt_inuse = 0;
    234  1.27.2.2  elad 		return EIO;
    235  1.27.2.2  elad 	}
    236  1.27.2.2  elad 
    237  1.27.2.2  elad 	return 0;
    238  1.27.2.2  elad }
    239  1.27.2.2  elad 
    240  1.27.2.2  elad /* ARGSUSED */
    241  1.27.2.2  elad int
    242  1.27.2.2  elad mtclose(dev, flags, fmt, l)
    243  1.27.2.2  elad 	dev_t dev;
    244  1.27.2.2  elad 	int flags, fmt;
    245  1.27.2.2  elad 	struct	lwp *l;
    246  1.27.2.2  elad {
    247  1.27.2.2  elad 	int unit = mtunit(dev);
    248  1.27.2.2  elad 	struct mt_softc *mt = mt_cd.cd_devs[unit];
    249  1.27.2.2  elad 
    250  1.27.2.2  elad 	/*
    251  1.27.2.2  elad 	 * If we just have finished a writing, write EOT marks.
    252  1.27.2.2  elad 	 */
    253  1.27.2.2  elad 	if ((flags & FWRITE) && mt->mt_waswrite) {
    254  1.27.2.2  elad 		mtcmd(mt, MTWEOF, 0, 0);
    255  1.27.2.2  elad 		mtcmd(mt, MTWEOF, 0, 0);
    256  1.27.2.2  elad 		mtcmd(mt, MTBSR, 1, 0);
    257  1.27.2.2  elad 	}
    258  1.27.2.2  elad 	if (mtnorewind(dev) == 0)
    259  1.27.2.2  elad 		mtcmd(mt, MTREW, 0, 1);
    260  1.27.2.2  elad 	if (mt->mt_serex)
    261  1.27.2.2  elad 		mtcmd(mt, -1, 0, 0);
    262  1.27.2.2  elad 
    263  1.27.2.2  elad 	mt->mt_inuse = 0; /* Release the tape */
    264  1.27.2.2  elad 	return 0;
    265  1.27.2.2  elad }
    266  1.27.2.2  elad 
    267  1.27.2.2  elad void
    268  1.27.2.2  elad mtstrategy(bp)
    269  1.27.2.2  elad 	struct buf *bp;
    270  1.27.2.2  elad {
    271  1.27.2.2  elad 	int unit;
    272  1.27.2.2  elad 	struct mt_softc *mt;
    273  1.27.2.2  elad 
    274  1.27.2.2  elad 	/*
    275  1.27.2.2  elad 	 * Make sure this is a reasonable drive to use.
    276  1.27.2.2  elad 	 */
    277  1.27.2.2  elad 	unit = mtunit(bp->b_dev);
    278  1.27.2.2  elad 	if (unit > mt_cd.cd_ndevs || (mt = mt_cd.cd_devs[unit]) == NULL) {
    279  1.27.2.2  elad 		bp->b_error = ENXIO;
    280  1.27.2.2  elad 		goto bad;
    281  1.27.2.2  elad 	}
    282  1.27.2.2  elad 
    283  1.27.2.2  elad 	mt->mt_waswrite = bp->b_flags & B_READ ? 0 : 1;
    284  1.27.2.2  elad 	mscp_strategy(bp, device_parent(&mt->mt_dev));
    285  1.27.2.2  elad 	return;
    286  1.27.2.2  elad 
    287  1.27.2.2  elad bad:
    288  1.27.2.2  elad 	bp->b_flags |= B_ERROR;
    289  1.27.2.2  elad 	biodone(bp);
    290  1.27.2.2  elad }
    291  1.27.2.2  elad 
    292  1.27.2.2  elad int
    293  1.27.2.2  elad mtread(dev, uio, flag)
    294  1.27.2.2  elad 	dev_t dev;
    295  1.27.2.2  elad 	struct uio *uio;
    296  1.27.2.2  elad 	int flag;
    297  1.27.2.2  elad {
    298  1.27.2.2  elad 
    299  1.27.2.2  elad 	return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio));
    300  1.27.2.2  elad }
    301  1.27.2.2  elad 
    302  1.27.2.2  elad int
    303  1.27.2.2  elad mtwrite(dev, uio, flag)
    304  1.27.2.2  elad 	dev_t dev;
    305  1.27.2.2  elad 	struct uio *uio;
    306  1.27.2.2  elad 	int flag;
    307  1.27.2.2  elad {
    308  1.27.2.2  elad 
    309  1.27.2.2  elad 	return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio));
    310  1.27.2.2  elad }
    311  1.27.2.2  elad 
    312  1.27.2.2  elad void
    313  1.27.2.2  elad mtiodone(usc, bp)
    314  1.27.2.2  elad 	struct device *usc;
    315  1.27.2.2  elad 	struct buf *bp;
    316  1.27.2.2  elad {
    317  1.27.2.2  elad 
    318  1.27.2.2  elad 	biodone(bp);
    319  1.27.2.2  elad }
    320  1.27.2.2  elad 
    321  1.27.2.2  elad /*
    322  1.27.2.2  elad  * Fill in drive addresses in a mscp packet waiting for transfer.
    323  1.27.2.2  elad  */
    324  1.27.2.2  elad void
    325  1.27.2.2  elad mtfillin(bp, mp)
    326  1.27.2.2  elad 	struct buf *bp;
    327  1.27.2.2  elad 	struct mscp *mp;
    328  1.27.2.2  elad {
    329  1.27.2.2  elad 	int unit = mtunit(bp->b_dev);
    330  1.27.2.2  elad 	struct mt_softc *mt = mt_cd.cd_devs[unit];
    331  1.27.2.2  elad 
    332  1.27.2.2  elad 	mp->mscp_unit = mt->mt_hwunit;
    333  1.27.2.2  elad 	if (mt->mt_serex == 2) {
    334  1.27.2.2  elad 		mp->mscp_modifier = M_MD_CLSEX;
    335  1.27.2.2  elad 		mt->mt_serex = 0;
    336  1.27.2.2  elad 	} else
    337  1.27.2.2  elad 		mp->mscp_modifier = 0;
    338  1.27.2.2  elad 
    339  1.27.2.2  elad 	mp->mscp_seq.seq_bytecount = bp->b_bcount;
    340  1.27.2.2  elad }
    341  1.27.2.2  elad 
    342  1.27.2.2  elad /*
    343  1.27.2.2  elad  * Handle an error datagram.
    344  1.27.2.2  elad  */
    345  1.27.2.2  elad void
    346  1.27.2.2  elad mtdgram(usc, mp, mi)
    347  1.27.2.2  elad 	struct device *usc;
    348  1.27.2.2  elad 	struct mscp *mp;
    349  1.27.2.2  elad 	struct mscp_softc *mi;
    350  1.27.2.2  elad {
    351  1.27.2.2  elad 	if (mscp_decodeerror(usc == NULL?"unconf mt" : usc->dv_xname, mp, mi))
    352  1.27.2.2  elad 		return;
    353  1.27.2.2  elad }
    354  1.27.2.2  elad 
    355  1.27.2.2  elad /*
    356  1.27.2.2  elad  * A drive came on line, make sure it really _is_ on line before
    357  1.27.2.2  elad  * trying to use it.
    358  1.27.2.2  elad  */
    359  1.27.2.2  elad int
    360  1.27.2.2  elad mtonline(usc, mp)
    361  1.27.2.2  elad 	struct device *usc;
    362  1.27.2.2  elad 	struct mscp *mp;
    363  1.27.2.2  elad {
    364  1.27.2.2  elad 	struct mt_softc *mt = (void *)usc;
    365  1.27.2.2  elad 
    366  1.27.2.2  elad 	wakeup((caddr_t)&mt->mt_state);
    367  1.27.2.2  elad 	if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)
    368  1.27.2.2  elad 		mt->mt_state = MT_ONLINE;
    369  1.27.2.2  elad 
    370  1.27.2.2  elad 	return (MSCP_DONE);
    371  1.27.2.2  elad }
    372  1.27.2.2  elad 
    373  1.27.2.2  elad /*
    374  1.27.2.2  elad  * We got some (configured) unit's status.  Return DONE.
    375  1.27.2.2  elad  */
    376  1.27.2.2  elad int
    377  1.27.2.2  elad mtgotstatus(usc, mp)
    378  1.27.2.2  elad 	struct device *usc;
    379  1.27.2.2  elad 	struct mscp *mp;
    380  1.27.2.2  elad {
    381  1.27.2.2  elad 	return (MSCP_DONE);
    382  1.27.2.2  elad }
    383  1.27.2.2  elad 
    384  1.27.2.2  elad static const char *mt_ioerrs[] = {
    385  1.27.2.2  elad 	"invalid command",	/* 1 M_ST_INVALCMD */
    386  1.27.2.2  elad 	"command aborted",	/* 2 M_ST_ABORTED */
    387  1.27.2.2  elad 	"unit offline",		/* 3 M_ST_OFFLINE */
    388  1.27.2.2  elad 	"unknown",		/* 4 M_ST_AVAILABLE */
    389  1.27.2.2  elad 	"unknown",		/* 5 M_ST_MFMTERR */
    390  1.27.2.2  elad 	"unit write protected", /* 6 M_ST_WRPROT */
    391  1.27.2.2  elad 	"compare error",	/* 7 M_ST_COMPERR */
    392  1.27.2.2  elad 	"data error",		/* 8 M_ST_DATAERR */
    393  1.27.2.2  elad 	"host buffer access error",	/* 9 M_ST_HOSTBUFERR */
    394  1.27.2.2  elad 	"controller error",	/* 10 M_ST_CTLRERR */
    395  1.27.2.2  elad 	"drive error",		/* 11 M_ST_DRIVEERR */
    396  1.27.2.2  elad 	"formatter error",	/* 12 M_ST_FORMATTERR */
    397  1.27.2.2  elad 	"BOT encountered",	/* 13 M_ST_BOT */
    398  1.27.2.2  elad 	"tape mark encountered",/* 14 M_ST_TAPEMARK */
    399  1.27.2.2  elad 	"unknown",		/* 15 */
    400  1.27.2.2  elad 	"record data truncated",/* 16 M_ST_RDTRUNC */
    401  1.27.2.2  elad };
    402  1.27.2.2  elad 
    403  1.27.2.2  elad /*
    404  1.27.2.2  elad  * An I/O error, may be because of a tapemark encountered.
    405  1.27.2.2  elad  * Check that before failing.
    406  1.27.2.2  elad  */
    407  1.27.2.2  elad /*ARGSUSED*/
    408  1.27.2.2  elad int
    409  1.27.2.2  elad mtioerror(usc, mp, bp)
    410  1.27.2.2  elad 	struct device *usc;
    411  1.27.2.2  elad 	struct mscp *mp;
    412  1.27.2.2  elad 	struct buf *bp;
    413  1.27.2.2  elad {
    414  1.27.2.2  elad 	struct mt_softc *mt = (void *)usc;
    415  1.27.2.2  elad 	int st = mp->mscp_status & M_ST_MASK;
    416  1.27.2.2  elad 
    417  1.27.2.2  elad 	if (mp->mscp_flags & M_EF_SEREX)
    418  1.27.2.2  elad 		mt->mt_serex = 1;
    419  1.27.2.2  elad 	if (st == M_ST_TAPEMARK)
    420  1.27.2.2  elad 		mt->mt_serex = 2;
    421  1.27.2.2  elad 	else {
    422  1.27.2.2  elad 		if (st && st < 17)
    423  1.27.2.2  elad 			printf("%s: error %d (%s)\n", mt->mt_dev.dv_xname, st,
    424  1.27.2.2  elad 			    mt_ioerrs[st-1]);
    425  1.27.2.2  elad 		else
    426  1.27.2.2  elad 			printf("%s: error %d\n", mt->mt_dev.dv_xname, st);
    427  1.27.2.2  elad 		bp->b_flags |= B_ERROR;
    428  1.27.2.2  elad 		bp->b_error = EROFS;
    429  1.27.2.2  elad 	}
    430  1.27.2.2  elad 
    431  1.27.2.2  elad 	return (MSCP_DONE);
    432  1.27.2.2  elad }
    433  1.27.2.2  elad 
    434  1.27.2.2  elad /*
    435  1.27.2.2  elad  * I/O controls.
    436  1.27.2.2  elad  */
    437  1.27.2.2  elad int
    438  1.27.2.2  elad mtioctl(dev, cmd, data, flag, l)
    439  1.27.2.2  elad 	dev_t dev;
    440  1.27.2.2  elad 	u_long cmd;
    441  1.27.2.2  elad 	caddr_t data;
    442  1.27.2.2  elad 	int flag;
    443  1.27.2.2  elad 	struct lwp *l;
    444  1.27.2.2  elad {
    445  1.27.2.2  elad 	int unit = mtunit(dev);
    446  1.27.2.2  elad 	struct mt_softc *mt = mt_cd.cd_devs[unit];
    447  1.27.2.2  elad 	struct mtop *mtop;
    448  1.27.2.2  elad 	int error = 0;
    449  1.27.2.2  elad 
    450  1.27.2.2  elad 	switch (cmd) {
    451  1.27.2.2  elad 
    452  1.27.2.2  elad 	case MTIOCTOP:
    453  1.27.2.2  elad 		mtop = (void *)data;
    454  1.27.2.2  elad 		if (mtop->mt_op == MTWEOF) {
    455  1.27.2.2  elad 			while (mtop->mt_count-- > 0)
    456  1.27.2.2  elad 				if ((error = mtcmd(mt, mtop->mt_op, 0, 0)))
    457  1.27.2.2  elad 					break;
    458  1.27.2.2  elad 		} else
    459  1.27.2.2  elad 			error = mtcmd(mt, mtop->mt_op, mtop->mt_count, 0);
    460  1.27.2.2  elad 
    461  1.27.2.2  elad 	case MTIOCGET:
    462  1.27.2.2  elad 		((struct mtget *)data)->mt_type = MT_ISTMSCP;
    463  1.27.2.2  elad 		/* XXX we need to fill in more fields here */
    464  1.27.2.2  elad 		break;
    465  1.27.2.2  elad 
    466  1.27.2.2  elad 	default:
    467  1.27.2.2  elad 		error = ENXIO;
    468  1.27.2.2  elad 		break;
    469  1.27.2.2  elad 	}
    470  1.27.2.2  elad 	return (error);
    471  1.27.2.2  elad }
    472  1.27.2.2  elad 
    473  1.27.2.2  elad /*
    474  1.27.2.2  elad  * No crash dump support...
    475  1.27.2.2  elad  */
    476  1.27.2.2  elad int
    477  1.27.2.2  elad mtdump(dev, blkno, va, size)
    478  1.27.2.2  elad 	dev_t	dev;
    479  1.27.2.2  elad 	daddr_t blkno;
    480  1.27.2.2  elad 	caddr_t va;
    481  1.27.2.2  elad 	size_t	size;
    482  1.27.2.2  elad {
    483  1.27.2.2  elad 	return -1;
    484  1.27.2.2  elad }
    485  1.27.2.2  elad 
    486  1.27.2.2  elad /*
    487  1.27.2.2  elad  * Send a command to the tape drive. Wait until the command is
    488  1.27.2.2  elad  * finished before returning.
    489  1.27.2.2  elad  * This routine must only be called when there are no data transfer
    490  1.27.2.2  elad  * active on this device. Can we be sure of this? Or does the ctlr
    491  1.27.2.2  elad  * queue up all command packets and take them in sequential order?
    492  1.27.2.2  elad  * It sure would be nice if my manual stated this... /ragge
    493  1.27.2.2  elad  */
    494  1.27.2.2  elad int
    495  1.27.2.2  elad mtcmd(mt, cmd, count, complete)
    496  1.27.2.2  elad 	struct mt_softc *mt;
    497  1.27.2.2  elad 	int cmd, count, complete;
    498  1.27.2.2  elad {
    499  1.27.2.2  elad 	struct mscp *mp;
    500  1.27.2.2  elad 	struct mscp_softc *mi = (void *)device_parent(&mt->mt_dev);
    501  1.27.2.2  elad 	volatile int i;
    502  1.27.2.2  elad 
    503  1.27.2.2  elad 	mp = mscp_getcp(mi, MSCP_WAIT);
    504  1.27.2.2  elad 
    505  1.27.2.2  elad 	mt->mt_ioctlerr = 0;
    506  1.27.2.2  elad 	mp->mscp_unit = mt->mt_hwunit;
    507  1.27.2.2  elad 	mp->mscp_cmdref = -1;
    508  1.27.2.2  elad 	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;
    509  1.27.2.2  elad 
    510  1.27.2.2  elad 	switch (cmd) {
    511  1.27.2.2  elad 	case MTWEOF:
    512  1.27.2.2  elad 		mp->mscp_opcode = M_OP_WRITM;
    513  1.27.2.2  elad 		break;
    514  1.27.2.2  elad 
    515  1.27.2.2  elad 	case MTBSF:
    516  1.27.2.2  elad 		mp->mscp_modifier = M_MD_REVERSE;
    517  1.27.2.2  elad 	case MTFSF:
    518  1.27.2.2  elad 		mp->mscp_opcode = M_OP_POS;
    519  1.27.2.2  elad 		mp->mscp_seq.seq_buffer = count;
    520  1.27.2.2  elad 		break;
    521  1.27.2.2  elad 
    522  1.27.2.2  elad 	case MTBSR:
    523  1.27.2.2  elad 		mp->mscp_modifier = M_MD_REVERSE;
    524  1.27.2.2  elad 	case MTFSR:
    525  1.27.2.2  elad 		mp->mscp_opcode = M_OP_POS;
    526  1.27.2.2  elad 		mp->mscp_modifier |= M_MD_OBJCOUNT;
    527  1.27.2.2  elad 		mp->mscp_seq.seq_bytecount = count;
    528  1.27.2.2  elad 		break;
    529  1.27.2.2  elad 
    530  1.27.2.2  elad 	case MTREW:
    531  1.27.2.2  elad 		mp->mscp_opcode = M_OP_POS;
    532  1.27.2.2  elad 		mp->mscp_modifier = M_MD_REWIND | M_MD_CLSEX;
    533  1.27.2.2  elad 		if (complete)
    534  1.27.2.2  elad 			mp->mscp_modifier |= M_MD_IMMEDIATE;
    535  1.27.2.2  elad 		mt->mt_serex = 0;
    536  1.27.2.2  elad 		break;
    537  1.27.2.2  elad 
    538  1.27.2.2  elad 	case MTOFFL:
    539  1.27.2.2  elad 		mp->mscp_opcode = M_OP_AVAILABLE;
    540  1.27.2.2  elad 		mp->mscp_modifier = M_MD_UNLOAD | M_MD_CLSEX;
    541  1.27.2.2  elad 		mt->mt_serex = 0;
    542  1.27.2.2  elad 		break;
    543  1.27.2.2  elad 
    544  1.27.2.2  elad 	case MTNOP:
    545  1.27.2.2  elad 		mp->mscp_opcode = M_OP_GETUNITST;
    546  1.27.2.2  elad 		break;
    547  1.27.2.2  elad 
    548  1.27.2.2  elad 	case -1: /* Clear serious exception only */
    549  1.27.2.2  elad 		mp->mscp_opcode = M_OP_POS;
    550  1.27.2.2  elad 		mp->mscp_modifier = M_MD_CLSEX;
    551  1.27.2.2  elad 		mt->mt_serex = 0;
    552  1.27.2.2  elad 		break;
    553  1.27.2.2  elad 
    554  1.27.2.2  elad 	default:
    555  1.27.2.2  elad 		printf("Bad ioctl %x\n", cmd);
    556  1.27.2.2  elad 		mp->mscp_opcode = M_OP_POS;
    557  1.27.2.2  elad 		break;
    558  1.27.2.2  elad 	}
    559  1.27.2.2  elad 
    560  1.27.2.2  elad 	i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
    561  1.27.2.2  elad 	tsleep(&mt->mt_inuse, PRIBIO, "mtioctl", 0);
    562  1.27.2.2  elad 	return mt->mt_ioctlerr;
    563  1.27.2.2  elad }
    564  1.27.2.2  elad 
    565  1.27.2.2  elad /*
    566  1.27.2.2  elad  * Called from bus routines whenever a non-data transfer is finished.
    567  1.27.2.2  elad  */
    568  1.27.2.2  elad void
    569  1.27.2.2  elad mtcmddone(usc, mp)
    570  1.27.2.2  elad 	struct device *usc;
    571  1.27.2.2  elad 	struct mscp *mp;
    572  1.27.2.2  elad {
    573  1.27.2.2  elad 	struct mt_softc *mt = (void *)usc;
    574  1.27.2.2  elad 
    575  1.27.2.2  elad 	if (mp->mscp_status) {
    576  1.27.2.2  elad 		mt->mt_ioctlerr = EIO;
    577  1.27.2.2  elad 		printf("%s: bad status %x\n", mt->mt_dev.dv_xname,
    578  1.27.2.2  elad 		    mp->mscp_status);
    579  1.27.2.2  elad 	}
    580  1.27.2.2  elad 	wakeup(&mt->mt_inuse);
    581  1.27.2.2  elad }
    582