1*faa8e1b3Spooka /* $NetBSD: mt.c,v 1.23 2009/12/05 22:34:43 pooka Exp $ */ 20f968376Sgmcgarry 30f968376Sgmcgarry /*- 40f968376Sgmcgarry * Copyright (c) 1996-2003 The NetBSD Foundation, Inc. 50f968376Sgmcgarry * All rights reserved. 60f968376Sgmcgarry * 70f968376Sgmcgarry * This code is derived from software contributed to The NetBSD Foundation 80f968376Sgmcgarry * by Jason R. Thorpe. 90f968376Sgmcgarry * 100f968376Sgmcgarry * Redistribution and use in source and binary forms, with or without 110f968376Sgmcgarry * modification, are permitted provided that the following conditions 120f968376Sgmcgarry * are met: 130f968376Sgmcgarry * 1. Redistributions of source code must retain the above copyright 140f968376Sgmcgarry * notice, this list of conditions and the following disclaimer. 150f968376Sgmcgarry * 2. Redistributions in binary form must reproduce the above copyright 160f968376Sgmcgarry * notice, this list of conditions and the following disclaimer in the 170f968376Sgmcgarry * documentation and/or other materials provided with the distribution. 180f968376Sgmcgarry * 190f968376Sgmcgarry * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 200f968376Sgmcgarry * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 210f968376Sgmcgarry * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 220f968376Sgmcgarry * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 230f968376Sgmcgarry * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 240f968376Sgmcgarry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 250f968376Sgmcgarry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 260f968376Sgmcgarry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 270f968376Sgmcgarry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 280f968376Sgmcgarry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 290f968376Sgmcgarry * POSSIBILITY OF SUCH DAMAGE. 300f968376Sgmcgarry */ 310f968376Sgmcgarry 320f968376Sgmcgarry /* 330f968376Sgmcgarry * Copyright (c) 1982, 1990, 1993 340f968376Sgmcgarry * The Regents of the University of California. All rights reserved. 350f968376Sgmcgarry * 360f968376Sgmcgarry * This code is derived from software contributed to Berkeley by 370f968376Sgmcgarry * the Systems Programming Group of the University of Utah Computer 380f968376Sgmcgarry * Science Department. 390f968376Sgmcgarry * 400f968376Sgmcgarry * Redistribution and use in source and binary forms, with or without 410f968376Sgmcgarry * modification, are permitted provided that the following conditions 420f968376Sgmcgarry * are met: 430f968376Sgmcgarry * 1. Redistributions of source code must retain the above copyright 440f968376Sgmcgarry * notice, this list of conditions and the following disclaimer. 450f968376Sgmcgarry * 2. Redistributions in binary form must reproduce the above copyright 460f968376Sgmcgarry * notice, this list of conditions and the following disclaimer in the 470f968376Sgmcgarry * documentation and/or other materials provided with the distribution. 48aad01611Sagc * 3. Neither the name of the University nor the names of its contributors 49aad01611Sagc * may be used to endorse or promote products derived from this software 50aad01611Sagc * without specific prior written permission. 51aad01611Sagc * 52aad01611Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53aad01611Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54aad01611Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55aad01611Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56aad01611Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57aad01611Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58aad01611Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59aad01611Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60aad01611Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61aad01611Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62aad01611Sagc * SUCH DAMAGE. 63aad01611Sagc * 64aad01611Sagc * from: Utah $Hdr: rd.c 1.44 92/12/26$ 65aad01611Sagc * 66aad01611Sagc * @(#)rd.c 8.2 (Berkeley) 5/19/94 67aad01611Sagc */ 68aad01611Sagc 69aad01611Sagc /* 70aad01611Sagc * Copyright (c) 1988 University of Utah. 71aad01611Sagc * 72aad01611Sagc * This code is derived from software contributed to Berkeley by 73aad01611Sagc * the Systems Programming Group of the University of Utah Computer 74aad01611Sagc * Science Department. 75aad01611Sagc * 76aad01611Sagc * Redistribution and use in source and binary forms, with or without 77aad01611Sagc * modification, are permitted provided that the following conditions 78aad01611Sagc * are met: 79aad01611Sagc * 1. Redistributions of source code must retain the above copyright 80aad01611Sagc * notice, this list of conditions and the following disclaimer. 81aad01611Sagc * 2. Redistributions in binary form must reproduce the above copyright 82aad01611Sagc * notice, this list of conditions and the following disclaimer in the 83aad01611Sagc * documentation and/or other materials provided with the distribution. 840f968376Sgmcgarry * 3. All advertising materials mentioning features or use of this software 850f968376Sgmcgarry * must display the following acknowledgement: 860f968376Sgmcgarry * This product includes software developed by the University of 870f968376Sgmcgarry * California, Berkeley and its contributors. 880f968376Sgmcgarry * 4. Neither the name of the University nor the names of its contributors 890f968376Sgmcgarry * may be used to endorse or promote products derived from this software 900f968376Sgmcgarry * without specific prior written permission. 910f968376Sgmcgarry * 920f968376Sgmcgarry * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 930f968376Sgmcgarry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 940f968376Sgmcgarry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 950f968376Sgmcgarry * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 960f968376Sgmcgarry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 970f968376Sgmcgarry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 980f968376Sgmcgarry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 990f968376Sgmcgarry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1000f968376Sgmcgarry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1010f968376Sgmcgarry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1020f968376Sgmcgarry * SUCH DAMAGE. 1030f968376Sgmcgarry * 1040f968376Sgmcgarry * from: Utah $Hdr: rd.c 1.44 92/12/26$ 1050f968376Sgmcgarry * 1060f968376Sgmcgarry * @(#)rd.c 8.2 (Berkeley) 5/19/94 1070f968376Sgmcgarry */ 1080f968376Sgmcgarry 1090f968376Sgmcgarry /* 1100f968376Sgmcgarry * Magnetic tape driver (HP7974a, HP7978a/b, HP7979a, HP7980a, HP7980xc) 1110f968376Sgmcgarry * Original version contributed by Mt. Xinu. 1120f968376Sgmcgarry * Modified for 4.4BSD by Mark Davies and Andrew Vignaux, Department of 1130f968376Sgmcgarry * Computer Science, Victoria University of Wellington 1140f968376Sgmcgarry */ 1150f968376Sgmcgarry 1160f968376Sgmcgarry #include <sys/cdefs.h> 117*faa8e1b3Spooka __KERNEL_RCSID(0, "$NetBSD: mt.c,v 1.23 2009/12/05 22:34:43 pooka Exp $"); 1180f968376Sgmcgarry 1190f968376Sgmcgarry #include <sys/param.h> 1200f968376Sgmcgarry #include <sys/systm.h> 1210f968376Sgmcgarry #include <sys/callout.h> 1220f968376Sgmcgarry #include <sys/buf.h> 12305f25dccSyamt #include <sys/bufq.h> 1240f968376Sgmcgarry #include <sys/ioctl.h> 1250f968376Sgmcgarry #include <sys/mtio.h> 1260f968376Sgmcgarry #include <sys/file.h> 1270f968376Sgmcgarry #include <sys/proc.h> 1280f968376Sgmcgarry #include <sys/tty.h> 1290f968376Sgmcgarry #include <sys/kernel.h> 1300f968376Sgmcgarry #include <sys/tprintf.h> 1310f968376Sgmcgarry #include <sys/device.h> 1320f968376Sgmcgarry #include <sys/conf.h> 1330f968376Sgmcgarry 1340f968376Sgmcgarry #include <dev/gpib/gpibvar.h> 1350f968376Sgmcgarry #include <dev/gpib/cs80busvar.h> 1360f968376Sgmcgarry 1370f968376Sgmcgarry #include <dev/gpib/mtreg.h> 1380f968376Sgmcgarry 1390f968376Sgmcgarry #ifdef DEBUG 1400f968376Sgmcgarry int mtdebug = 0; 1410f968376Sgmcgarry #define MDB_ANY 0xff 1420f968376Sgmcgarry #define MDB_FOLLOW 0x01 1430f968376Sgmcgarry #define DPRINTF(mask, str) if (mtdebug & (mask)) printf str 1440f968376Sgmcgarry #else 1450f968376Sgmcgarry #define DPRINTF(mask, str) /* nothing */ 1460f968376Sgmcgarry #endif 1470f968376Sgmcgarry 1480f968376Sgmcgarry struct mt_softc { 1490f968376Sgmcgarry struct device sc_dev; 1500f968376Sgmcgarry 1510f968376Sgmcgarry gpib_chipset_tag_t sc_ic; 1520f968376Sgmcgarry gpib_handle_t sc_hdl; 1530f968376Sgmcgarry 1540f968376Sgmcgarry int sc_slave; /* GPIB slave address (0-6) */ 1550f968376Sgmcgarry short sc_flags; /* see below */ 1560f968376Sgmcgarry u_char sc_lastdsj; /* place for DSJ in mtreaddsj() */ 1570f968376Sgmcgarry u_char sc_lastecmd; /* place for End Command in mtreaddsj() */ 1580f968376Sgmcgarry short sc_recvtimeo; /* count of gpibsend timeouts to prevent hang */ 1590f968376Sgmcgarry short sc_statindex; /* index for next sc_stat when MTF_STATTIMEO */ 1600f968376Sgmcgarry struct mt_stat sc_stat;/* status bytes last read from device */ 1610f968376Sgmcgarry short sc_density; /* current density of tape (mtio.h format) */ 1620f968376Sgmcgarry short sc_type; /* tape drive model (hardware IDs) */ 1630f968376Sgmcgarry tpr_t sc_ttyp; 164aec75b1cSyamt struct bufq_state *sc_tab;/* buf queue */ 1650f968376Sgmcgarry int sc_active; 1660f968376Sgmcgarry struct buf sc_bufstore; /* XXX buffer storage */ 1670f968376Sgmcgarry 1680f968376Sgmcgarry struct callout sc_start_ch; 1690f968376Sgmcgarry struct callout sc_intr_ch; 1700f968376Sgmcgarry }; 1710f968376Sgmcgarry 1720f968376Sgmcgarry #define MTUNIT(x) (minor(x) & 0x03) 1730f968376Sgmcgarry 17443061c75Sreinoud #define B_CMD B_DEVPRIVATE /* command buf instead of data */ 1750f968376Sgmcgarry #define b_cmd b_blkno /* blkno holds cmd when B_CMD */ 1760f968376Sgmcgarry 177529e91fcScegger int mtmatch(device_t, cfdata_t, void *); 178529e91fcScegger void mtattach(device_t, device_t, void *); 1790f968376Sgmcgarry 1800f968376Sgmcgarry CFATTACH_DECL(mt, sizeof(struct mt_softc), 1810f968376Sgmcgarry mtmatch, mtattach, NULL, NULL); 1820f968376Sgmcgarry 1830f968376Sgmcgarry int mtlookup(int, int, int); 1840f968376Sgmcgarry void mtustart(struct mt_softc *); 1850f968376Sgmcgarry int mtreaddsj(struct mt_softc *, int); 1860f968376Sgmcgarry int mtcommand(dev_t, int, int); 1870f968376Sgmcgarry 1880f968376Sgmcgarry void mtintr_callout(void *); 1890f968376Sgmcgarry void mtstart_callout(void *); 1900f968376Sgmcgarry 1910f968376Sgmcgarry void mtcallback(void *, int); 1920f968376Sgmcgarry void mtstart(struct mt_softc *); 1930f968376Sgmcgarry void mtintr(struct mt_softc *); 1940f968376Sgmcgarry 1950f968376Sgmcgarry dev_type_open(mtopen); 1960f968376Sgmcgarry dev_type_close(mtclose); 1970f968376Sgmcgarry dev_type_read(mtread); 1980f968376Sgmcgarry dev_type_write(mtwrite); 1990f968376Sgmcgarry dev_type_ioctl(mtioctl); 2000f968376Sgmcgarry dev_type_strategy(mtstrategy); 2010f968376Sgmcgarry 2020f968376Sgmcgarry const struct bdevsw mt_bdevsw = { 2030f968376Sgmcgarry mtopen, mtclose, mtstrategy, mtioctl, nodump, nosize, D_TAPE 2040f968376Sgmcgarry }; 2050f968376Sgmcgarry 2060f968376Sgmcgarry const struct cdevsw mt_cdevsw = { 2070f968376Sgmcgarry mtopen, mtclose, mtread, mtwrite, mtioctl, 2080f968376Sgmcgarry nostop, notty, nopoll, nommap, nokqfilter, D_TAPE 2090f968376Sgmcgarry }; 2100f968376Sgmcgarry 2110f968376Sgmcgarry 2120f968376Sgmcgarry extern struct cfdriver mt_cd; 2130f968376Sgmcgarry 2140f968376Sgmcgarry struct mtinfo { 2150f968376Sgmcgarry u_short hwid; 21622974bb6Scube const char *desc; 2170f968376Sgmcgarry } mtinfo[] = { 2180f968376Sgmcgarry { MT7978ID, "7978" }, 2190f968376Sgmcgarry { MT7979AID, "7979A" }, 2200f968376Sgmcgarry { MT7980ID, "7980" }, 2210f968376Sgmcgarry { MT7974AID, "7974A" }, 2220f968376Sgmcgarry }; 2230f968376Sgmcgarry int nmtinfo = sizeof(mtinfo) / sizeof(mtinfo[0]); 2240f968376Sgmcgarry 2250f968376Sgmcgarry 2260f968376Sgmcgarry int 227454af1c0Sdsl mtlookup(int id, int slave, int punit) 2280f968376Sgmcgarry { 2290f968376Sgmcgarry int i; 2300f968376Sgmcgarry 2310f968376Sgmcgarry for (i = 0; i < nmtinfo; i++) 2320f968376Sgmcgarry if (mtinfo[i].hwid == id) 2330f968376Sgmcgarry break; 2340f968376Sgmcgarry if (i == nmtinfo) 2350f968376Sgmcgarry return (-1); 2360f968376Sgmcgarry return (0); 2370f968376Sgmcgarry } 2380f968376Sgmcgarry 2390f968376Sgmcgarry int 240529e91fcScegger mtmatch(device_t parent, cfdata_t match, void *aux) 2410f968376Sgmcgarry { 2420f968376Sgmcgarry struct cs80bus_attach_args *ca = aux; 2430f968376Sgmcgarry 2440f968376Sgmcgarry ca->ca_punit = 0; 2450f968376Sgmcgarry return (mtlookup(ca->ca_id, ca->ca_slave, ca->ca_punit) == 0); 2460f968376Sgmcgarry } 2470f968376Sgmcgarry 2480f968376Sgmcgarry void 249529e91fcScegger mtattach(device_t parent, device_t self, void *aux) 2500f968376Sgmcgarry { 25192c7bba3Sthorpej struct mt_softc *sc = device_private(self); 2520f968376Sgmcgarry struct cs80bus_attach_args *ca = aux; 2530f968376Sgmcgarry int type; 2540f968376Sgmcgarry 2550f968376Sgmcgarry sc->sc_ic = ca->ca_ic; 2560f968376Sgmcgarry sc->sc_slave = ca->ca_slave; 2570f968376Sgmcgarry 2580f968376Sgmcgarry if ((type = mtlookup(ca->ca_id, ca->ca_slave, ca->ca_punit)) < 0) 2590f968376Sgmcgarry return; 2600f968376Sgmcgarry 2610f968376Sgmcgarry printf(": %s tape\n", mtinfo[type].desc); 2620f968376Sgmcgarry 2630f968376Sgmcgarry sc->sc_type = type; 2640f968376Sgmcgarry sc->sc_flags = MTF_EXISTS; 2650f968376Sgmcgarry 266aec75b1cSyamt bufq_alloc(&sc->sc_tab, "fcfs", 0); 26788ab7da9Sad callout_init(&sc->sc_start_ch, 0); 26888ab7da9Sad callout_init(&sc->sc_intr_ch, 0); 2690f968376Sgmcgarry 2700f968376Sgmcgarry if (gpibregister(sc->sc_ic, sc->sc_slave, mtcallback, sc, 2710f968376Sgmcgarry &sc->sc_hdl)) { 2721b044f41Scegger aprint_error_dev(&sc->sc_dev, "can't register callback\n"); 2730f968376Sgmcgarry return; 2740f968376Sgmcgarry } 2750f968376Sgmcgarry } 2760f968376Sgmcgarry 2770f968376Sgmcgarry /* 2780f968376Sgmcgarry * Perform a read of "Device Status Jump" register and update the 2790f968376Sgmcgarry * status if necessary. If status is read, the given "ecmd" is also 2800f968376Sgmcgarry * performed, unless "ecmd" is zero. Returns DSJ value, -1 on failure 2810f968376Sgmcgarry * and -2 on "temporary" failure. 2820f968376Sgmcgarry */ 2830f968376Sgmcgarry int 284454af1c0Sdsl mtreaddsj(struct mt_softc *sc, int ecmd) 2850f968376Sgmcgarry { 2860f968376Sgmcgarry int retval; 2870f968376Sgmcgarry 2880f968376Sgmcgarry if (sc->sc_flags & MTF_STATTIMEO) 2890f968376Sgmcgarry goto getstats; 2900f968376Sgmcgarry retval = gpibrecv(sc->sc_ic, 2910f968376Sgmcgarry (sc->sc_flags & MTF_DSJTIMEO) ? -1 : sc->sc_slave, 2920f968376Sgmcgarry MTT_DSJ, &(sc->sc_lastdsj), 1); 2930f968376Sgmcgarry sc->sc_flags &= ~MTF_DSJTIMEO; 2940f968376Sgmcgarry if (retval != 1) { 2950f968376Sgmcgarry DPRINTF(MDB_ANY, ("%s can't gpibrecv DSJ", 2961b044f41Scegger device_xname(&sc->sc_dev))); 2970f968376Sgmcgarry if (sc->sc_recvtimeo == 0) 2980f968376Sgmcgarry sc->sc_recvtimeo = hz; 2990f968376Sgmcgarry if (--sc->sc_recvtimeo == 0) 3000f968376Sgmcgarry return (-1); 3010f968376Sgmcgarry if (retval == 0) 3020f968376Sgmcgarry sc->sc_flags |= MTF_DSJTIMEO; 3030f968376Sgmcgarry return (-2); 3040f968376Sgmcgarry } 3050f968376Sgmcgarry sc->sc_recvtimeo = 0; 3060f968376Sgmcgarry sc->sc_statindex = 0; 3071b044f41Scegger DPRINTF(MDB_ANY, ("%s readdsj: 0x%x", device_xname(&sc->sc_dev), 3080f968376Sgmcgarry sc->sc_lastdsj)); 3090f968376Sgmcgarry sc->sc_lastecmd = ecmd; 3100f968376Sgmcgarry switch (sc->sc_lastdsj) { 3110f968376Sgmcgarry case 0: 3120f968376Sgmcgarry if (ecmd & MTE_DSJ_FORCE) 3130f968376Sgmcgarry break; 3140f968376Sgmcgarry return (0); 3150f968376Sgmcgarry 3160f968376Sgmcgarry case 2: 3170f968376Sgmcgarry sc->sc_lastecmd = MTE_COMPLETE; 3180f968376Sgmcgarry case 1: 3190f968376Sgmcgarry break; 3200f968376Sgmcgarry 3210f968376Sgmcgarry default: 3221b044f41Scegger printf("%s readdsj: DSJ 0x%x\n", device_xname(&sc->sc_dev), 3230f968376Sgmcgarry sc->sc_lastdsj); 3240f968376Sgmcgarry return (-1); 3250f968376Sgmcgarry } 3260f968376Sgmcgarry 3270f968376Sgmcgarry getstats: 3280f968376Sgmcgarry retval = gpibrecv(sc->sc_ic, 3290f968376Sgmcgarry (sc->sc_flags & MTF_STATCONT) ? -1 : sc->sc_slave, MTT_STAT, 3300f968376Sgmcgarry ((char *)&(sc->sc_stat)) + sc->sc_statindex, 3310f968376Sgmcgarry sizeof(sc->sc_stat) - sc->sc_statindex); 3320f968376Sgmcgarry sc->sc_flags &= ~(MTF_STATTIMEO | MTF_STATCONT); 3330f968376Sgmcgarry if (retval != sizeof(sc->sc_stat) - sc->sc_statindex) { 3340f968376Sgmcgarry if (sc->sc_recvtimeo == 0) 3350f968376Sgmcgarry sc->sc_recvtimeo = hz; 3360f968376Sgmcgarry if (--sc->sc_recvtimeo != 0) { 3370f968376Sgmcgarry if (retval >= 0) { 3380f968376Sgmcgarry sc->sc_statindex += retval; 3390f968376Sgmcgarry sc->sc_flags |= MTF_STATCONT; 3400f968376Sgmcgarry } 3410f968376Sgmcgarry sc->sc_flags |= MTF_STATTIMEO; 3420f968376Sgmcgarry return (-2); 3430f968376Sgmcgarry } 3441b044f41Scegger printf("%s readdsj: can't read status", device_xname(&sc->sc_dev)); 3450f968376Sgmcgarry return (-1); 3460f968376Sgmcgarry } 3470f968376Sgmcgarry sc->sc_recvtimeo = 0; 3480f968376Sgmcgarry sc->sc_statindex = 0; 3490f968376Sgmcgarry DPRINTF(MDB_ANY, ("%s readdsj: status is %x %x %x %x %x %x", 3501b044f41Scegger device_xname(&sc->sc_dev), 3510f968376Sgmcgarry sc->sc_stat1, sc->sc_stat2, sc->sc_stat3, 3520f968376Sgmcgarry sc->sc_stat4, sc->sc_stat5, sc->sc_stat6)); 3530f968376Sgmcgarry if (sc->sc_lastecmd) 3540f968376Sgmcgarry (void) gpibsend(sc->sc_ic, sc->sc_slave, 3550f968376Sgmcgarry MTL_ECMD, &(sc->sc_lastecmd), 1); 3560f968376Sgmcgarry return ((int) sc->sc_lastdsj); 3570f968376Sgmcgarry } 3580f968376Sgmcgarry 3590f968376Sgmcgarry int 3603e484e61Scegger mtopen(dev_t dev, int flag, int mode, struct lwp *l) 3610f968376Sgmcgarry { 3620f968376Sgmcgarry struct mt_softc *sc; 3630f968376Sgmcgarry int req_den; 3640f968376Sgmcgarry int error; 3650f968376Sgmcgarry 3663e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(dev)); 3670f968376Sgmcgarry if (sc == NULL || (sc->sc_flags & MTF_EXISTS) == 0) 3680f968376Sgmcgarry return (ENXIO); 3690f968376Sgmcgarry 3700f968376Sgmcgarry if (sc->sc_flags & MTF_OPEN) 3710f968376Sgmcgarry return (EBUSY); 3720f968376Sgmcgarry 3731b044f41Scegger DPRINTF(MDB_ANY, ("%s open: flags 0x%x", device_xname(&sc->sc_dev), 3740f968376Sgmcgarry sc->sc_flags)); 3750f968376Sgmcgarry 3760f968376Sgmcgarry sc->sc_flags |= MTF_OPEN; 37722974bb6Scube sc->sc_ttyp = tprintf_open(l->l_proc); 3780f968376Sgmcgarry if ((sc->sc_flags & MTF_ALIVE) == 0) { 3790f968376Sgmcgarry error = mtcommand(dev, MTRESET, 0); 3800f968376Sgmcgarry if (error != 0 || (sc->sc_flags & MTF_ALIVE) == 0) 3810f968376Sgmcgarry goto errout; 3820f968376Sgmcgarry if ((sc->sc_stat1 & (SR1_BOT | SR1_ONLINE)) == SR1_ONLINE) 3830f968376Sgmcgarry (void) mtcommand(dev, MTREW, 0); 3840f968376Sgmcgarry } 3850f968376Sgmcgarry for (;;) { 3860f968376Sgmcgarry if ((error = mtcommand(dev, MTNOP, 0)) != 0) 3870f968376Sgmcgarry goto errout; 3880f968376Sgmcgarry if (!(sc->sc_flags & MTF_REW)) 3890f968376Sgmcgarry break; 390*faa8e1b3Spooka error = kpause("mt", true, hz, NULL); 391*faa8e1b3Spooka if (error != 0 && error != EWOULDBLOCK) { 3920f968376Sgmcgarry error = EINTR; 3930f968376Sgmcgarry goto errout; 3940f968376Sgmcgarry } 3950f968376Sgmcgarry } 3960f968376Sgmcgarry if ((flag & FWRITE) && (sc->sc_stat1 & SR1_RO)) { 3970f968376Sgmcgarry error = EROFS; 3980f968376Sgmcgarry goto errout; 3990f968376Sgmcgarry } 4000f968376Sgmcgarry if (!(sc->sc_stat1 & SR1_ONLINE)) { 4011b044f41Scegger uprintf("%s: not online\n", device_xname(&sc->sc_dev)); 4020f968376Sgmcgarry error = EIO; 4030f968376Sgmcgarry goto errout; 4040f968376Sgmcgarry } 4050f968376Sgmcgarry /* 4060f968376Sgmcgarry * Select density: 4070f968376Sgmcgarry * - find out what density the drive is set to 4080f968376Sgmcgarry * (i.e. the density of the current tape) 4090f968376Sgmcgarry * - if we are going to write 4100f968376Sgmcgarry * - if we're not at the beginning of the tape 4110f968376Sgmcgarry * - complain if we want to change densities 4120f968376Sgmcgarry * - otherwise, select the mtcommand to set the density 4130f968376Sgmcgarry * 4140f968376Sgmcgarry * If the drive doesn't support it then don't change the recorded 4150f968376Sgmcgarry * density. 4160f968376Sgmcgarry * 4170f968376Sgmcgarry * The original MOREbsd code had these additional conditions 4180f968376Sgmcgarry * for the mid-tape change 4190f968376Sgmcgarry * 4200f968376Sgmcgarry * req_den != T_BADBPI && 4210f968376Sgmcgarry * sc->sc_density != T_6250BPI 4220f968376Sgmcgarry * 4230f968376Sgmcgarry * which suggests that it would be possible to write multiple 4240f968376Sgmcgarry * densities if req_den == T_BAD_BPI or the current tape 4250f968376Sgmcgarry * density was 6250. Testing of our 7980 suggests that the 4260f968376Sgmcgarry * device cannot change densities mid-tape. 4270f968376Sgmcgarry * 4280f968376Sgmcgarry * ajv@comp.vuw.ac.nz 4290f968376Sgmcgarry */ 4300f968376Sgmcgarry sc->sc_density = (sc->sc_stat2 & SR2_6250) ? T_6250BPI : ( 4310f968376Sgmcgarry (sc->sc_stat3 & SR3_1600) ? T_1600BPI : ( 4320f968376Sgmcgarry (sc->sc_stat3 & SR3_800) ? T_800BPI : -1)); 4330f968376Sgmcgarry req_den = (dev & T_DENSEL); 4340f968376Sgmcgarry 4350f968376Sgmcgarry if (flag & FWRITE) { 4360f968376Sgmcgarry if (!(sc->sc_stat1 & SR1_BOT)) { 4370f968376Sgmcgarry if (sc->sc_density != req_den) { 4380f968376Sgmcgarry uprintf("%s: can't change density mid-tape\n", 4391b044f41Scegger device_xname(&sc->sc_dev)); 4400f968376Sgmcgarry error = EIO; 4410f968376Sgmcgarry goto errout; 4420f968376Sgmcgarry } 4430f968376Sgmcgarry } 4440f968376Sgmcgarry else { 4450f968376Sgmcgarry int mtset_density = 4460f968376Sgmcgarry (req_den == T_800BPI ? MTSET800BPI : ( 4470f968376Sgmcgarry req_den == T_1600BPI ? MTSET1600BPI : ( 4480f968376Sgmcgarry req_den == T_6250BPI ? MTSET6250BPI : ( 4490f968376Sgmcgarry sc->sc_type == MT7980ID 4500f968376Sgmcgarry ? MTSET6250DC 4510f968376Sgmcgarry : MTSET6250BPI)))); 4520f968376Sgmcgarry if (mtcommand(dev, mtset_density, 0) == 0) 4530f968376Sgmcgarry sc->sc_density = req_den; 4540f968376Sgmcgarry } 4550f968376Sgmcgarry } 4560f968376Sgmcgarry return (0); 4570f968376Sgmcgarry errout: 4580f968376Sgmcgarry sc->sc_flags &= ~MTF_OPEN; 4590f968376Sgmcgarry return (error); 4600f968376Sgmcgarry } 4610f968376Sgmcgarry 4620f968376Sgmcgarry int 4633e484e61Scegger mtclose(dev_t dev, int flag, int fmt, struct lwp *l) 4640f968376Sgmcgarry { 4650f968376Sgmcgarry struct mt_softc *sc; 4660f968376Sgmcgarry 4673e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(dev)); 4680f968376Sgmcgarry if (sc == NULL) 4690f968376Sgmcgarry return (ENXIO); 4700f968376Sgmcgarry 4710f968376Sgmcgarry if (sc->sc_flags & MTF_WRT) { 4720f968376Sgmcgarry (void) mtcommand(dev, MTWEOF, 2); 4730f968376Sgmcgarry (void) mtcommand(dev, MTBSF, 0); 4740f968376Sgmcgarry } 4750f968376Sgmcgarry if ((minor(dev) & T_NOREWIND) == 0) 4760f968376Sgmcgarry (void) mtcommand(dev, MTREW, 0); 4770f968376Sgmcgarry sc->sc_flags &= ~MTF_OPEN; 4780f968376Sgmcgarry tprintf_close(sc->sc_ttyp); 4790f968376Sgmcgarry return (0); 4800f968376Sgmcgarry } 4810f968376Sgmcgarry 4820f968376Sgmcgarry int 4833e484e61Scegger mtcommand(dev_t dev, int cmd, int cnt) 4840f968376Sgmcgarry { 4850f968376Sgmcgarry struct mt_softc *sc; 4860f968376Sgmcgarry struct buf *bp; 4870f968376Sgmcgarry int error = 0; 4880f968376Sgmcgarry 4893e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(dev)); 4900f968376Sgmcgarry bp = &sc->sc_bufstore; 4910f968376Sgmcgarry 4924a780c9aSad if (bp->b_cflags & BC_BUSY) 4930f968376Sgmcgarry return (EBUSY); 4940f968376Sgmcgarry 4950f968376Sgmcgarry bp->b_cmd = cmd; 4960f968376Sgmcgarry bp->b_dev = dev; 4974a780c9aSad bp->b_objlock = &buffer_lock; 4980f968376Sgmcgarry do { 4994a780c9aSad bp->b_cflags = BC_BUSY; 5004a780c9aSad bp->b_flags = B_CMD; 5014a780c9aSad bp->b_oflags = 0; 5020f968376Sgmcgarry mtstrategy(bp); 5030f968376Sgmcgarry biowait(bp); 50466fefd11Sad if (bp->b_error != 0) { 5050f968376Sgmcgarry error = (int) (unsigned) bp->b_error; 5060f968376Sgmcgarry break; 5070f968376Sgmcgarry } 5080f968376Sgmcgarry } while (--cnt > 0); 5090f968376Sgmcgarry #if 0 5104a780c9aSad bp->b_cflags = 0 /*&= ~BC_BUSY*/; 5110f968376Sgmcgarry #else 5124a780c9aSad bp->b_cflags &= ~BC_BUSY; 5130f968376Sgmcgarry #endif 5140f968376Sgmcgarry return (error); 5150f968376Sgmcgarry } 5160f968376Sgmcgarry 5170f968376Sgmcgarry /* 5180f968376Sgmcgarry * Only thing to check here is for legal record lengths (writes only). 5190f968376Sgmcgarry */ 5200f968376Sgmcgarry void 5213e484e61Scegger mtstrategy(struct buf *bp) 5220f968376Sgmcgarry { 5230f968376Sgmcgarry struct mt_softc *sc; 5240f968376Sgmcgarry int s; 5250f968376Sgmcgarry 5263e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(bp->b_dev)); 5270f968376Sgmcgarry 5281b044f41Scegger DPRINTF(MDB_ANY, ("%s strategy", device_xname(&sc->sc_dev))); 5290f968376Sgmcgarry 5300f968376Sgmcgarry if ((bp->b_flags & (B_CMD | B_READ)) == 0) { 5310f968376Sgmcgarry #define WRITE_BITS_IGNORED 8 5320f968376Sgmcgarry #if 0 5330f968376Sgmcgarry if (bp->b_bcount & ((1 << WRITE_BITS_IGNORED) - 1)) { 5340f968376Sgmcgarry tprintf(sc->sc_ttyp, 5350f968376Sgmcgarry "%s: write record must be multiple of %d\n", 5361b044f41Scegger device_xname(&sc->sc_dev), 1 << WRITE_BITS_IGNORED); 5370f968376Sgmcgarry goto error; 5380f968376Sgmcgarry } 5390f968376Sgmcgarry #endif 5400f968376Sgmcgarry s = 16 * 1024; 5410f968376Sgmcgarry if (sc->sc_stat2 & SR2_LONGREC) { 5420f968376Sgmcgarry switch (sc->sc_density) { 5430f968376Sgmcgarry case T_1600BPI: 5440f968376Sgmcgarry s = 32 * 1024; 5450f968376Sgmcgarry break; 5460f968376Sgmcgarry 5470f968376Sgmcgarry case T_6250BPI: 5480f968376Sgmcgarry case T_BADBPI: 5490f968376Sgmcgarry s = 60 * 1024; 5500f968376Sgmcgarry break; 5510f968376Sgmcgarry } 5520f968376Sgmcgarry } 5530f968376Sgmcgarry if (bp->b_bcount > s) { 5540f968376Sgmcgarry tprintf(sc->sc_ttyp, 55522974bb6Scube "%s: write record (%d) too big: limit (%d)\n", 5561b044f41Scegger device_xname(&sc->sc_dev), bp->b_bcount, s); 5570f968376Sgmcgarry #if 0 /* XXX see above */ 5580f968376Sgmcgarry error: 5590f968376Sgmcgarry #endif 5600f968376Sgmcgarry bp->b_error = EIO; 5610f968376Sgmcgarry biodone(bp); 5620f968376Sgmcgarry return; 5630f968376Sgmcgarry } 5640f968376Sgmcgarry } 5650f968376Sgmcgarry s = splbio(); 56670de9736Syamt bufq_put(sc->sc_tab, bp); 5670f968376Sgmcgarry if (sc->sc_active == 0) { 5680f968376Sgmcgarry sc->sc_active = 1; 5690f968376Sgmcgarry mtustart(sc); 5700f968376Sgmcgarry } 5710f968376Sgmcgarry splx(s); 5720f968376Sgmcgarry } 5730f968376Sgmcgarry 5740f968376Sgmcgarry void 575454af1c0Sdsl mtustart(struct mt_softc *sc) 5760f968376Sgmcgarry { 5770f968376Sgmcgarry 5781b044f41Scegger DPRINTF(MDB_ANY, ("%s ustart", device_xname(&sc->sc_dev))); 5790f968376Sgmcgarry if (gpibrequest(sc->sc_ic, sc->sc_hdl)) 5800f968376Sgmcgarry mtstart(sc); 5810f968376Sgmcgarry } 5820f968376Sgmcgarry 5830f968376Sgmcgarry void 584454af1c0Sdsl mtcallback(void *v, int action) 5850f968376Sgmcgarry { 5860f968376Sgmcgarry struct mt_softc *sc = v; 5870f968376Sgmcgarry 5880f968376Sgmcgarry DPRINTF(MDB_FOLLOW, ("mtcallback: v=%p, action=%d\n", v, action)); 5890f968376Sgmcgarry 5900f968376Sgmcgarry switch (action) { 5910f968376Sgmcgarry case GPIBCBF_START: 5920f968376Sgmcgarry mtstart(sc); 5930f968376Sgmcgarry break; 5940f968376Sgmcgarry case GPIBCBF_INTR: 5950f968376Sgmcgarry mtintr(sc); 5960f968376Sgmcgarry break; 5970f968376Sgmcgarry #ifdef DEBUG 5980f968376Sgmcgarry default: 5990f968376Sgmcgarry printf("mtcallback: unknown action %d\n", action); 6000f968376Sgmcgarry break; 6010f968376Sgmcgarry #endif 6020f968376Sgmcgarry } 6030f968376Sgmcgarry } 6040f968376Sgmcgarry 6050f968376Sgmcgarry void 606454af1c0Sdsl mtintr_callout(void *arg) 6070f968376Sgmcgarry { 6080f968376Sgmcgarry struct mt_softc *sc = arg; 6090f968376Sgmcgarry int s = splbio(); 6100f968376Sgmcgarry 6110f968376Sgmcgarry gpibppclear(sc->sc_ic); 6120f968376Sgmcgarry mtintr(sc); 6130f968376Sgmcgarry splx(s); 6140f968376Sgmcgarry } 6150f968376Sgmcgarry 6160f968376Sgmcgarry void 617454af1c0Sdsl mtstart_callout(void *arg) 6180f968376Sgmcgarry { 6190f968376Sgmcgarry int s = splbio(); 6200f968376Sgmcgarry 6210f968376Sgmcgarry mtstart((struct mt_softc *)arg); 6220f968376Sgmcgarry splx(s); 6230f968376Sgmcgarry } 6240f968376Sgmcgarry 6250f968376Sgmcgarry void 626454af1c0Sdsl mtstart(struct mt_softc *sc) 6270f968376Sgmcgarry { 6280f968376Sgmcgarry struct buf *bp; 6290f968376Sgmcgarry short cmdcount = 1; 6300f968376Sgmcgarry u_char cmdbuf[2]; 6310f968376Sgmcgarry 6321b044f41Scegger DPRINTF(MDB_ANY, ("%s start", device_xname(&sc->sc_dev))); 6330f968376Sgmcgarry sc->sc_flags &= ~MTF_WRT; 63470de9736Syamt bp = bufq_peek(sc->sc_tab); 6350f968376Sgmcgarry if ((sc->sc_flags & MTF_ALIVE) == 0 && 6360f968376Sgmcgarry ((bp->b_flags & B_CMD) == 0 || bp->b_cmd != MTRESET)) 6370f968376Sgmcgarry goto fatalerror; 6380f968376Sgmcgarry 6390f968376Sgmcgarry if (sc->sc_flags & MTF_REW) { 6400f968376Sgmcgarry if (!gpibpptest(sc->sc_ic, sc->sc_slave)) 6410f968376Sgmcgarry goto stillrew; 6420f968376Sgmcgarry switch (mtreaddsj(sc, MTE_DSJ_FORCE|MTE_COMPLETE|MTE_IDLE)) { 6430f968376Sgmcgarry case 0: 6440f968376Sgmcgarry case 1: 6450f968376Sgmcgarry stillrew: 6460f968376Sgmcgarry if ((sc->sc_stat1 & SR1_BOT) || 6470f968376Sgmcgarry !(sc->sc_stat1 & SR1_ONLINE)) { 6480f968376Sgmcgarry sc->sc_flags &= ~MTF_REW; 6490f968376Sgmcgarry break; 6500f968376Sgmcgarry } 6510f968376Sgmcgarry case -2: 6520f968376Sgmcgarry /* 6530f968376Sgmcgarry * -2 means "timeout" reading DSJ, which is probably 6540f968376Sgmcgarry * temporary. This is considered OK when doing a NOP, 6550f968376Sgmcgarry * but not otherwise. 6560f968376Sgmcgarry */ 6570f968376Sgmcgarry if (sc->sc_flags & (MTF_DSJTIMEO | MTF_STATTIMEO)) { 6580f968376Sgmcgarry callout_reset(&sc->sc_start_ch, hz >> 5, 6590f968376Sgmcgarry mtstart_callout, sc); 6600f968376Sgmcgarry return; 6610f968376Sgmcgarry } 6620f968376Sgmcgarry case 2: 6630f968376Sgmcgarry if (bp->b_cmd != MTNOP || !(bp->b_flags & B_CMD)) { 6640f968376Sgmcgarry bp->b_error = EBUSY; 66566fefd11Sad goto done; 6660f968376Sgmcgarry } 6670f968376Sgmcgarry goto done; 6680f968376Sgmcgarry 6690f968376Sgmcgarry default: 6700f968376Sgmcgarry goto fatalerror; 6710f968376Sgmcgarry } 6720f968376Sgmcgarry } 6730f968376Sgmcgarry if (bp->b_flags & B_CMD) { 6740f968376Sgmcgarry if (sc->sc_flags & MTF_PASTEOT) { 6750f968376Sgmcgarry switch(bp->b_cmd) { 6760f968376Sgmcgarry case MTFSF: 6770f968376Sgmcgarry case MTWEOF: 6780f968376Sgmcgarry case MTFSR: 6790f968376Sgmcgarry bp->b_error = ENOSPC; 68066fefd11Sad goto done; 6810f968376Sgmcgarry 6820f968376Sgmcgarry case MTBSF: 6830f968376Sgmcgarry case MTOFFL: 6840f968376Sgmcgarry case MTBSR: 6850f968376Sgmcgarry case MTREW: 6860f968376Sgmcgarry sc->sc_flags &= ~(MTF_PASTEOT | MTF_ATEOT); 6870f968376Sgmcgarry break; 6880f968376Sgmcgarry } 6890f968376Sgmcgarry } 6900f968376Sgmcgarry switch(bp->b_cmd) { 6910f968376Sgmcgarry case MTFSF: 6920f968376Sgmcgarry if (sc->sc_flags & MTF_HITEOF) 6930f968376Sgmcgarry goto done; 6940f968376Sgmcgarry cmdbuf[0] = MTTC_FSF; 6950f968376Sgmcgarry break; 6960f968376Sgmcgarry 6970f968376Sgmcgarry case MTBSF: 6980f968376Sgmcgarry if (sc->sc_flags & MTF_HITBOF) 6990f968376Sgmcgarry goto done; 7000f968376Sgmcgarry cmdbuf[0] = MTTC_BSF; 7010f968376Sgmcgarry break; 7020f968376Sgmcgarry 7030f968376Sgmcgarry case MTOFFL: 7040f968376Sgmcgarry sc->sc_flags |= MTF_REW; 7050f968376Sgmcgarry cmdbuf[0] = MTTC_REWOFF; 7060f968376Sgmcgarry break; 7070f968376Sgmcgarry 7080f968376Sgmcgarry case MTWEOF: 7090f968376Sgmcgarry cmdbuf[0] = MTTC_WFM; 7100f968376Sgmcgarry break; 7110f968376Sgmcgarry 7120f968376Sgmcgarry case MTBSR: 7130f968376Sgmcgarry cmdbuf[0] = MTTC_BSR; 7140f968376Sgmcgarry break; 7150f968376Sgmcgarry 7160f968376Sgmcgarry case MTFSR: 7170f968376Sgmcgarry cmdbuf[0] = MTTC_FSR; 7180f968376Sgmcgarry break; 7190f968376Sgmcgarry 7200f968376Sgmcgarry case MTREW: 7210f968376Sgmcgarry sc->sc_flags |= MTF_REW; 7220f968376Sgmcgarry cmdbuf[0] = MTTC_REW; 7230f968376Sgmcgarry break; 7240f968376Sgmcgarry 7250f968376Sgmcgarry case MTNOP: 7260f968376Sgmcgarry /* 7270f968376Sgmcgarry * NOP is supposed to set status bits. 7280f968376Sgmcgarry * Force readdsj to do it. 7290f968376Sgmcgarry */ 7300f968376Sgmcgarry switch (mtreaddsj(sc, 7310f968376Sgmcgarry MTE_DSJ_FORCE | MTE_COMPLETE | MTE_IDLE)) { 7320f968376Sgmcgarry default: 7330f968376Sgmcgarry goto done; 7340f968376Sgmcgarry 7350f968376Sgmcgarry case -1: 7360f968376Sgmcgarry /* 7370f968376Sgmcgarry * If this fails, perform a device clear 7380f968376Sgmcgarry * to fix any protocol problems and (most 7390f968376Sgmcgarry * likely) get the status. 7400f968376Sgmcgarry */ 7410f968376Sgmcgarry bp->b_cmd = MTRESET; 7420f968376Sgmcgarry break; 7430f968376Sgmcgarry 7440f968376Sgmcgarry case -2: 7450f968376Sgmcgarry callout_reset(&sc->sc_start_ch, hz >> 5, 7460f968376Sgmcgarry mtstart_callout, sc); 7470f968376Sgmcgarry return; 7480f968376Sgmcgarry } 7490f968376Sgmcgarry 7500f968376Sgmcgarry case MTRESET: 7510f968376Sgmcgarry /* 7520f968376Sgmcgarry * 1) selected device clear (send with "-2" secondary) 7530f968376Sgmcgarry * 2) set timeout, then wait for "service request" 7540f968376Sgmcgarry * 3) interrupt will read DSJ (and END COMPLETE-IDLE) 7550f968376Sgmcgarry */ 7560f968376Sgmcgarry if (gpibsend(sc->sc_ic, sc->sc_slave, -2, NULL, 0)){ 7571b044f41Scegger aprint_error_dev(&sc->sc_dev, "can't reset"); 7580f968376Sgmcgarry goto fatalerror; 7590f968376Sgmcgarry } 7600f968376Sgmcgarry callout_reset(&sc->sc_intr_ch, 4*hz, mtintr_callout, 7610f968376Sgmcgarry sc); 7620f968376Sgmcgarry gpibawait(sc->sc_ic); 7630f968376Sgmcgarry return; 7640f968376Sgmcgarry 7650f968376Sgmcgarry case MTSET800BPI: 7660f968376Sgmcgarry cmdbuf[0] = MTTC_800; 7670f968376Sgmcgarry break; 7680f968376Sgmcgarry 7690f968376Sgmcgarry case MTSET1600BPI: 7700f968376Sgmcgarry cmdbuf[0] = MTTC_1600; 7710f968376Sgmcgarry break; 7720f968376Sgmcgarry 7730f968376Sgmcgarry case MTSET6250BPI: 7740f968376Sgmcgarry cmdbuf[0] = MTTC_6250; 7750f968376Sgmcgarry break; 7760f968376Sgmcgarry 7770f968376Sgmcgarry case MTSET6250DC: 7780f968376Sgmcgarry cmdbuf[0] = MTTC_DC6250; 7790f968376Sgmcgarry break; 7800f968376Sgmcgarry } 7810f968376Sgmcgarry } else { 7820f968376Sgmcgarry if (sc->sc_flags & MTF_PASTEOT) { 7830f968376Sgmcgarry bp->b_error = ENOSPC; 78466fefd11Sad goto done; 7850f968376Sgmcgarry } 7860f968376Sgmcgarry if (bp->b_flags & B_READ) { 7870f968376Sgmcgarry sc->sc_flags |= MTF_IO; 7880f968376Sgmcgarry cmdbuf[0] = MTTC_READ; 7890f968376Sgmcgarry } else { 7900f968376Sgmcgarry sc->sc_flags |= MTF_WRT | MTF_IO; 7910f968376Sgmcgarry cmdbuf[0] = MTTC_WRITE; 7920f968376Sgmcgarry cmdbuf[1] = (bp->b_bcount +((1 << WRITE_BITS_IGNORED) - 1)) >> WRITE_BITS_IGNORED; 7930f968376Sgmcgarry cmdcount = 2; 7940f968376Sgmcgarry } 7950f968376Sgmcgarry } 7960f968376Sgmcgarry if (gpibsend(sc->sc_ic, sc->sc_slave, MTL_TCMD, cmdbuf, cmdcount) 7970f968376Sgmcgarry == cmdcount) { 7980f968376Sgmcgarry if (sc->sc_flags & MTF_REW) 7990f968376Sgmcgarry goto done; 8000f968376Sgmcgarry gpibawait(sc->sc_ic); 8010f968376Sgmcgarry return; 8020f968376Sgmcgarry } 8030f968376Sgmcgarry fatalerror: 8040f968376Sgmcgarry /* 8050f968376Sgmcgarry * If anything fails, the drive is probably hosed, so mark it not 8060f968376Sgmcgarry * "ALIVE" (but it EXISTS and is OPEN or we wouldn't be here, and 8070f968376Sgmcgarry * if, last we heard, it was REWinding, remember that). 8080f968376Sgmcgarry */ 8090f968376Sgmcgarry sc->sc_flags &= MTF_EXISTS | MTF_OPEN | MTF_REW; 8100f968376Sgmcgarry bp->b_error = EIO; 8110f968376Sgmcgarry done: 8120f968376Sgmcgarry sc->sc_flags &= ~(MTF_HITEOF | MTF_HITBOF); 81370de9736Syamt (void)bufq_get(sc->sc_tab); 8140f968376Sgmcgarry biodone(bp); 8150f968376Sgmcgarry gpibrelease(sc->sc_ic, sc->sc_hdl); 81670de9736Syamt if ((bp = bufq_peek(sc->sc_tab)) == NULL) 8170f968376Sgmcgarry sc->sc_active = 0; 8180f968376Sgmcgarry else 8190f968376Sgmcgarry mtustart(sc); 8200f968376Sgmcgarry } 8210f968376Sgmcgarry 8220f968376Sgmcgarry void 823454af1c0Sdsl mtintr(struct mt_softc *sc) 8240f968376Sgmcgarry { 8250f968376Sgmcgarry struct buf *bp; 8260f968376Sgmcgarry int slave, dir, i; 8270f968376Sgmcgarry u_char cmdbuf[4]; 8280f968376Sgmcgarry 8290f968376Sgmcgarry slave = sc->sc_slave; 8300f968376Sgmcgarry 83170de9736Syamt bp = bufq_peek(sc->sc_tab); 8320f968376Sgmcgarry if (bp == NULL) { 8331b044f41Scegger printf("%s intr: bp == NULL", device_xname(&sc->sc_dev)); 8340f968376Sgmcgarry return; 8350f968376Sgmcgarry } 8360f968376Sgmcgarry 8371b044f41Scegger DPRINTF(MDB_ANY, ("%s intr", device_xname(&sc->sc_dev))); 8380f968376Sgmcgarry 8390f968376Sgmcgarry /* 8400f968376Sgmcgarry * Some operation completed. Read status bytes and report errors. 8410f968376Sgmcgarry * Clear EOF flags here `cause they're set once on specific conditions 8420f968376Sgmcgarry * below when a command succeeds. 8430f968376Sgmcgarry * A DSJ of 2 always means keep waiting. If the command was READ 8440f968376Sgmcgarry * (and we're in data DMA phase) stop data transfer first. 8450f968376Sgmcgarry */ 8460f968376Sgmcgarry sc->sc_flags &= ~(MTF_HITEOF | MTF_HITBOF); 8470f968376Sgmcgarry if ((bp->b_flags & (B_CMD|B_READ)) == B_READ && 8480f968376Sgmcgarry !(sc->sc_flags & (MTF_IO | MTF_STATTIMEO | MTF_DSJTIMEO))){ 8490f968376Sgmcgarry cmdbuf[0] = MTE_STOP; 8500f968376Sgmcgarry (void) gpibsend(sc->sc_ic, slave, MTL_ECMD,cmdbuf,1); 8510f968376Sgmcgarry } 8520f968376Sgmcgarry switch (mtreaddsj(sc, 0)) { 8530f968376Sgmcgarry case 0: 8540f968376Sgmcgarry break; 8550f968376Sgmcgarry 8560f968376Sgmcgarry case 1: 8570f968376Sgmcgarry /* 8580f968376Sgmcgarry * If we're in the middle of a READ/WRITE and have yet to 8590f968376Sgmcgarry * start the data transfer, a DSJ of one should terminate it. 8600f968376Sgmcgarry */ 8610f968376Sgmcgarry sc->sc_flags &= ~MTF_IO; 8620f968376Sgmcgarry break; 8630f968376Sgmcgarry 8640f968376Sgmcgarry case 2: 8650f968376Sgmcgarry (void) gpibawait(sc->sc_ic); 8660f968376Sgmcgarry return; 8670f968376Sgmcgarry 8680f968376Sgmcgarry case -2: 8690f968376Sgmcgarry /* 8700f968376Sgmcgarry * -2 means that the drive failed to respond quickly enough 8710f968376Sgmcgarry * to the request for DSJ. It's probably just "busy" figuring 8720f968376Sgmcgarry * it out and will know in a little bit... 8730f968376Sgmcgarry */ 8740f968376Sgmcgarry callout_reset(&sc->sc_intr_ch, hz >> 5, mtintr_callout, sc); 8750f968376Sgmcgarry return; 8760f968376Sgmcgarry 8770f968376Sgmcgarry default: 8781b044f41Scegger printf("%s intr: can't get drive stat", device_xname(&sc->sc_dev)); 8790f968376Sgmcgarry goto error; 8800f968376Sgmcgarry } 8810f968376Sgmcgarry if (sc->sc_stat1 & (SR1_ERR | SR1_REJECT)) { 8820f968376Sgmcgarry i = sc->sc_stat4 & SR4_ERCLMASK; 8830f968376Sgmcgarry printf("%s: %s error, retry %d, SR2/3 %x/%x, code %d", 8841b044f41Scegger device_xname(&sc->sc_dev), i == SR4_DEVICE ? "device" : 8850f968376Sgmcgarry (i == SR4_PROTOCOL ? "protocol" : 8860f968376Sgmcgarry (i == SR4_SELFTEST ? "selftest" : "unknown")), 8870f968376Sgmcgarry sc->sc_stat4 & SR4_RETRYMASK, sc->sc_stat2, 8880f968376Sgmcgarry sc->sc_stat3, sc->sc_stat5); 8890f968376Sgmcgarry 8900f968376Sgmcgarry if ((bp->b_flags & B_CMD) && bp->b_cmd == MTRESET) 8910f968376Sgmcgarry callout_stop(&sc->sc_intr_ch); 8920f968376Sgmcgarry if (sc->sc_stat3 & SR3_POWERUP) 8930f968376Sgmcgarry sc->sc_flags &= MTF_OPEN | MTF_EXISTS; 8940f968376Sgmcgarry goto error; 8950f968376Sgmcgarry } 8960f968376Sgmcgarry /* 8970f968376Sgmcgarry * Report and clear any soft errors. 8980f968376Sgmcgarry */ 8990f968376Sgmcgarry if (sc->sc_stat1 & SR1_SOFTERR) { 9001b044f41Scegger printf("%s: soft error, retry %d\n", device_xname(&sc->sc_dev), 9010f968376Sgmcgarry sc->sc_stat4 & SR4_RETRYMASK); 9020f968376Sgmcgarry sc->sc_stat1 &= ~SR1_SOFTERR; 9030f968376Sgmcgarry } 9040f968376Sgmcgarry /* 9050f968376Sgmcgarry * We've initiated a read or write, but haven't actually started to 9060f968376Sgmcgarry * DMA the data yet. At this point, the drive's ready. 9070f968376Sgmcgarry */ 9080f968376Sgmcgarry if (sc->sc_flags & MTF_IO) { 9090f968376Sgmcgarry sc->sc_flags &= ~MTF_IO; 9100f968376Sgmcgarry dir = (bp->b_flags & B_READ ? GPIB_READ : GPIB_WRITE); 9110f968376Sgmcgarry gpibxfer(sc->sc_ic, slave, 9120f968376Sgmcgarry dir == GPIB_READ ? MTT_READ : MTL_WRITE, 9130f968376Sgmcgarry bp->b_data, bp->b_bcount, dir, dir == GPIB_READ); 9140f968376Sgmcgarry return; 9150f968376Sgmcgarry } 9160f968376Sgmcgarry /* 9170f968376Sgmcgarry * Check for End Of Tape - we're allowed to hit EOT and then write (or 9180f968376Sgmcgarry * read) one more record. If we get here and have not already hit EOT, 9190f968376Sgmcgarry * return ENOSPC to inform the process that it's hit it. If we get 9200f968376Sgmcgarry * here and HAVE already hit EOT, don't allow any more operations that 9210f968376Sgmcgarry * move the tape forward. 9220f968376Sgmcgarry */ 9230f968376Sgmcgarry if (sc->sc_stat1 & SR1_EOT) { 9240f968376Sgmcgarry if (sc->sc_flags & MTF_ATEOT) 9250f968376Sgmcgarry sc->sc_flags |= MTF_PASTEOT; 9260f968376Sgmcgarry else { 9270f968376Sgmcgarry bp->b_error = ENOSPC; 9280f968376Sgmcgarry sc->sc_flags |= MTF_ATEOT; 9290f968376Sgmcgarry } 9300f968376Sgmcgarry } 9310f968376Sgmcgarry /* 9320f968376Sgmcgarry * If a motion command was being executed, check for Tape Marks. 9330f968376Sgmcgarry * If we were doing data, make sure we got the right amount, and 9340f968376Sgmcgarry * check for hitting tape marks on reads. 9350f968376Sgmcgarry */ 9360f968376Sgmcgarry if (bp->b_flags & B_CMD) { 9370f968376Sgmcgarry if (sc->sc_stat1 & SR1_EOF) { 9380f968376Sgmcgarry if (bp->b_cmd == MTFSR) 9390f968376Sgmcgarry sc->sc_flags |= MTF_HITEOF; 9400f968376Sgmcgarry if (bp->b_cmd == MTBSR) 9410f968376Sgmcgarry sc->sc_flags |= MTF_HITBOF; 9420f968376Sgmcgarry } 9430f968376Sgmcgarry if (bp->b_cmd == MTRESET) { 9440f968376Sgmcgarry callout_stop(&sc->sc_intr_ch); 9450f968376Sgmcgarry sc->sc_flags |= MTF_ALIVE; 9460f968376Sgmcgarry } 9470f968376Sgmcgarry } else { 9480f968376Sgmcgarry i = gpibrecv(sc->sc_ic, slave, MTT_BCNT, cmdbuf, 2); 9490f968376Sgmcgarry if (i != 2) { 9501b044f41Scegger aprint_error_dev(&sc->sc_dev, "intr: can't get xfer length\n"); 9510f968376Sgmcgarry goto error; 9520f968376Sgmcgarry } 9530f968376Sgmcgarry i = (int) *((u_short *) cmdbuf); 9540f968376Sgmcgarry if (i <= bp->b_bcount) { 9550f968376Sgmcgarry if (i == 0) 9560f968376Sgmcgarry sc->sc_flags |= MTF_HITEOF; 9570f968376Sgmcgarry bp->b_resid = bp->b_bcount - i; 9580762f691Stsutsui DPRINTF(MDB_ANY, ("%s intr: bcount %d, resid %d", 9590762f691Stsutsui device_xname(&sc->sc_dev), 9600762f691Stsutsui bp->b_bcount, bp->b_resid)); 9610f968376Sgmcgarry } else { 9620f968376Sgmcgarry tprintf(sc->sc_ttyp, 96322974bb6Scube "%s: record (%d) larger than wanted (%d)\n", 9641b044f41Scegger device_xname(&sc->sc_dev), i, bp->b_bcount); 9650f968376Sgmcgarry error: 9660f968376Sgmcgarry sc->sc_flags &= ~MTF_IO; 9670f968376Sgmcgarry bp->b_error = EIO; 9680f968376Sgmcgarry } 9690f968376Sgmcgarry } 9700f968376Sgmcgarry /* 9710f968376Sgmcgarry * The operation is completely done. 9720f968376Sgmcgarry * Let the drive know with an END command. 9730f968376Sgmcgarry */ 9740f968376Sgmcgarry cmdbuf[0] = MTE_COMPLETE | MTE_IDLE; 9750f968376Sgmcgarry (void) gpibsend(sc->sc_ic, slave, MTL_ECMD, cmdbuf, 1); 9760f968376Sgmcgarry bp->b_flags &= ~B_CMD; 97770de9736Syamt (void)bufq_get(sc->sc_tab); 9780f968376Sgmcgarry biodone(bp); 9790f968376Sgmcgarry gpibrelease(sc->sc_ic, sc->sc_hdl); 98070de9736Syamt if (bufq_peek(sc->sc_tab) == NULL) 9810f968376Sgmcgarry sc->sc_active = 0; 9820f968376Sgmcgarry else 9830f968376Sgmcgarry mtustart(sc); 9840f968376Sgmcgarry } 9850f968376Sgmcgarry 9860f968376Sgmcgarry int 9873e484e61Scegger mtread(dev_t dev, struct uio *uio, int flags) 9880f968376Sgmcgarry { 9890f968376Sgmcgarry struct mt_softc *sc; 9900f968376Sgmcgarry 9913e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(dev)); 9920f968376Sgmcgarry 993610bc1e5Sad return (physio(mtstrategy, NULL, dev, B_READ, minphys, uio)); 9940f968376Sgmcgarry } 9950f968376Sgmcgarry 9960f968376Sgmcgarry int 9973e484e61Scegger mtwrite(dev_t dev, struct uio *uio, int flags) 9980f968376Sgmcgarry { 9990f968376Sgmcgarry struct mt_softc *sc; 10000f968376Sgmcgarry 10013e484e61Scegger sc = device_lookup_private(&mt_cd, MTUNIT(dev)); 10020f968376Sgmcgarry 1003610bc1e5Sad return (physio(mtstrategy, NULL, dev, B_WRITE, minphys, uio)); 10040f968376Sgmcgarry } 10050f968376Sgmcgarry 10060f968376Sgmcgarry int 1007454af1c0Sdsl mtioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 10080f968376Sgmcgarry { 10090f968376Sgmcgarry struct mtop *op; 10100f968376Sgmcgarry int cnt; 10110f968376Sgmcgarry 10120f968376Sgmcgarry switch (cmd) { 10130f968376Sgmcgarry case MTIOCTOP: 10140f968376Sgmcgarry op = (struct mtop *)data; 10150f968376Sgmcgarry switch(op->mt_op) { 10160f968376Sgmcgarry case MTWEOF: 10170f968376Sgmcgarry case MTFSF: 10180f968376Sgmcgarry case MTBSR: 10190f968376Sgmcgarry case MTBSF: 10200f968376Sgmcgarry case MTFSR: 10210f968376Sgmcgarry cnt = op->mt_count; 10220f968376Sgmcgarry break; 10230f968376Sgmcgarry 10240f968376Sgmcgarry case MTOFFL: 10250f968376Sgmcgarry case MTREW: 10260f968376Sgmcgarry case MTNOP: 10270f968376Sgmcgarry cnt = 0; 10280f968376Sgmcgarry break; 10290f968376Sgmcgarry 10300f968376Sgmcgarry default: 10310f968376Sgmcgarry return (EINVAL); 10320f968376Sgmcgarry } 10330f968376Sgmcgarry return (mtcommand(dev, op->mt_op, cnt)); 10340f968376Sgmcgarry 10350f968376Sgmcgarry case MTIOCGET: 10360f968376Sgmcgarry break; 10370f968376Sgmcgarry 10380f968376Sgmcgarry default: 10390f968376Sgmcgarry return (EINVAL); 10400f968376Sgmcgarry } 10410f968376Sgmcgarry return (0); 10420f968376Sgmcgarry } 1043