The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/qbus/ts.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ts.c,v 1.25 2008/04/05 19:16:49 cegger Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1991 The Regents of the University of California.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)tmscp.c     7.16 (Berkeley) 5/9/91
   32  */
   33 
   34 /*
   35  * sccsid = "@(#)tmscp.c        1.24    (ULTRIX)        1/21/86";
   36  */
   37 
   38 /************************************************************************
   39  *                                                                      *
   40  *        Licensed from Digital Equipment Corporation                   *
   41  *                       Copyright (c)                                  *
   42  *               Digital Equipment Corporation                          *
   43  *                   Maynard, Massachusetts                             *
   44  *                         1985, 1986                                   *
   45  *                    All rights reserved.                              *
   46  *                                                                      *
   47  *        The Information in this software is subject to change         *
   48  *   without notice and should not be construed as a commitment         *
   49  *   by  Digital  Equipment  Corporation.   Digital   makes  no         *
   50  *   representations about the suitability of this software for         *
   51  *   any purpose.  It is supplied "As Is" without expressed  or         *
   52  *   implied  warranty.                                                 *
   53  *                                                                      *
   54  *        If the Regents of the University of California or its         *
   55  *   licensees modify the software in a manner creating                 *
   56  *   derivative copyright rights, appropriate copyright                 *
   57  *   legends may be placed on  the derivative work in addition          *
   58  *   to that set forth above.                                           *
   59  *                                                                      *
   60  ************************************************************************/
   61 
   62 /*
   63  * TSV05/TS05 device driver, written by Bertram Barth.
   64  *
   65  * should be TS11 compatible (untested)
   66  */
   67 
   68 #include <sys/cdefs.h>
   69 __KERNEL_RCSID(0, "$NetBSD: ts.c,v 1.25 2008/04/05 19:16:49 cegger Exp $");
   70 
   71 #undef  TSDEBUG
   72 
   73 /*
   74  * TODO:
   75  *
   76  * Keep track of tape position so that lseek et al works.
   77  * Use tprintf to inform the user, not the system console.
   78  */
   79 
   80 
   81 #include <sys/param.h>
   82 #include <sys/systm.h>
   83 #include <sys/kernel.h>
   84 #include <sys/buf.h>
   85 #include <sys/bufq.h>
   86 #include <sys/conf.h>
   87 #include <sys/errno.h>
   88 #include <sys/file.h>
   89 #include <sys/syslog.h>
   90 #include <sys/ioctl.h>
   91 #include <sys/mtio.h>
   92 #include <sys/uio.h>
   93 #include <sys/proc.h>
   94 
   95 #include <sys/bus.h>
   96 
   97 #include <dev/qbus/ubareg.h>
   98 #include <dev/qbus/ubavar.h>
   99 
  100 #include <dev/qbus/tsreg.h>
  101 
  102 #include "ioconf.h"
  103 
  104 struct ts {
  105         struct cmd cmd; /* command packet */
  106         struct chr chr; /* characteristics packet */
  107         struct status status;   /* status packet */
  108 };
  109 
  110 /*
  111  * Software status, per controller.
  112  * also status per tape-unit, since only one unit per controller
  113  * (thus we have no struct ts_info)
  114  */
  115 struct ts_softc {
  116         device_t sc_dev;                /* Autoconf ... */
  117         struct uba_softc *sc_uh;        /* the parent UBA */
  118         struct uba_unit sc_unit;        /* Struct common for UBA to talk */
  119         struct evcnt sc_intrcnt;        /* Interrupt counting */
  120         struct ubinfo sc_ui;            /* mapping info for struct ts */
  121         struct uba_unit sc_uu;          /* Struct for UBA to communicate */
  122         bus_space_tag_t sc_iot;
  123         bus_addr_t sc_ioh;
  124         bus_dma_tag_t sc_dmat;
  125         bus_dmamap_t sc_dmam;
  126         volatile struct ts *sc_vts;     /* Memory address of ts struct */
  127         struct ts *sc_bts;              /* Unibus address of ts struct */
  128         int     sc_type;                /* TS11 or TS05? */
  129         short   sc_waddr;               /* Value to write to TSDB */
  130         struct bufq_state *sc_bufq;     /* pending I/O requests */
  131 
  132         short   sc_mapped;              /* Unibus map allocated ? */
  133         short   sc_state;               /* see below: ST_xxx */
  134         short   sc_rtc;                 /* retry count for lcmd */
  135         short   sc_openf;               /* lock against multiple opens */
  136         short   sc_liowf;               /* last operation was write */
  137         struct buf ts_cbuf;             /* internal cmd buffer (for ioctls) */
  138 };
  139 
  140 #define TS_WCSR(csr, val) \
  141         bus_space_write_2(sc->sc_iot, sc->sc_ioh, csr, val)
  142 #define TS_RCSR(csr) \
  143         bus_space_read_2(sc->sc_iot, sc->sc_ioh, csr)
  144 
  145 #define LOWORD(x)       ((int)(x) & 0xffff)
  146 #define HIWORD(x)       (((int)(x) >> 16) & 0x3f)
  147 
  148 #define TYPE_TS11       0
  149 #define TYPE_TS05       1
  150 #define TYPE_TU80       2
  151 
  152 #define TS_INVALID      0
  153 #define TS_INIT         1
  154 #define TS_RUNNING      2
  155 #define TS_FASTREPOS    3
  156 
  157 static  void tsintr(void *);
  158 static  void tsinit(struct ts_softc *);
  159 static  void tscommand(struct ts_softc *, dev_t, int, int);
  160 static  int tsstart(struct ts_softc *, int);
  161 static  void tswchar(struct ts_softc *);
  162 static  bool tsreset(struct ts_softc *);
  163 static  int tsmatch(device_t, cfdata_t, void *);
  164 static  void tsattach(device_t, device_t, void *);
  165 static  int tsready(struct uba_unit *);
  166 
  167 CFATTACH_DECL_NEW(ts, sizeof(struct ts_softc),
  168     tsmatch, tsattach, NULL, NULL);
  169 
  170 dev_type_open(tsopen);
  171 dev_type_close(tsclose);
  172 dev_type_read(tsread);
  173 dev_type_write(tswrite);
  174 dev_type_ioctl(tsioctl);
  175 dev_type_strategy(tsstrategy);
  176 dev_type_dump(tsdump);
  177 
  178 const struct bdevsw ts_bdevsw = {
  179         tsopen, tsclose, tsstrategy, tsioctl, tsdump, nosize, D_TAPE
  180 };
  181 
  182 const struct cdevsw ts_cdevsw = {
  183         tsopen, tsclose, tsread, tswrite, tsioctl,
  184         nostop, notty, nopoll, nommap, nokqfilter, D_TAPE
  185 };
  186 
  187 /* Bits in minor device */
  188 #define TS_UNIT(dev)    (minor(dev)&03)
  189 #define TS_HIDENSITY    010
  190 
  191 #define TS_PRI  LOG_INFO
  192 
  193 
  194 /*
  195  * Probe for device. If found, try to raise an interrupt.
  196  */
  197 int
  198 tsmatch(device_t parent, cfdata_t match, void *aux)
  199 {
  200         struct device tsdev;
  201         struct ts_softc ssc;
  202         struct ts_softc *sc = &ssc;
  203         struct uba_attach_args *ua = aux;
  204         int i;
  205 
  206         sc->sc_iot = ua->ua_iot;
  207         sc->sc_ioh = ua->ua_ioh;
  208         sc->sc_mapped = 0;
  209         sc->sc_dev = &tsdev;
  210         sc->sc_uh = device_private(parent);
  211         strcpy(sc->sc_dev->dv_xname, "ts");
  212 
  213         /* Try to reset the device */
  214         for (i = 0; i < 3; i++) {
  215                 if (tsreset(sc))
  216                         break;
  217         }
  218 
  219         if (i == 3)
  220                 return 0;
  221 
  222         tsinit(sc);
  223         tswchar(sc);            /* write charact. to enable interrupts */
  224                                 /* completion of this will raise the intr. */
  225 
  226         DELAY(1000000);         /* Wait for interrupt */
  227         ubmemfree(sc->sc_uh, &sc->sc_ui);
  228         return 1;
  229 }
  230 
  231 /*
  232  */
  233 void
  234 tsattach(device_t parent, device_t self, void *aux)
  235 {
  236         struct ts_softc *sc = device_private(self);
  237         struct uba_attach_args *ua = aux;
  238         int error;
  239         const char *t;
  240 
  241         sc->sc_dev = self;
  242         sc->sc_uh = device_private(parent);
  243         sc->sc_iot = ua->ua_iot;
  244         sc->sc_ioh = ua->ua_ioh;
  245         sc->sc_dmat = ua->ua_dmat;
  246 
  247         sc->sc_uu.uu_dev = self;
  248         sc->sc_uu.uu_ready = tsready;
  249 
  250         tsinit(sc);     /* reset and map */
  251 
  252         error = bus_dmamap_create(sc->sc_dmat, (64*1024), 16, (64*1024),
  253             0, BUS_DMA_NOWAIT, &sc->sc_dmam);
  254         if (error) {
  255                 aprint_error(": failed create DMA map %d\n", error);
  256                 return;
  257         }
  258 
  259         bufq_alloc(&sc->sc_bufq, "fcfs", 0);
  260 
  261         /*
  262          * write the characteristics (again)
  263          */
  264         sc->sc_state = TS_INIT;         /* tsintr() checks this ... */
  265         tswchar(sc);
  266         if (tsleep(sc, PRIBIO, "tsattach", 100)) {
  267                 aprint_error(": failed SET CHARACTERISTICS\n");
  268                 return;
  269         }
  270 
  271         sc->sc_state = TS_RUNNING;
  272         if (sc->sc_uh->uh_type == UBA_UBA) {
  273                 if (sc->sc_vts->status.xst2 & TS_SF_TU80) {
  274                         sc->sc_type = TYPE_TU80;
  275                         t = "TU80";
  276                 } else {
  277                         sc->sc_type = TYPE_TS11;
  278                         t = "TS11";
  279                 }
  280         } else {
  281                 sc->sc_type = TYPE_TS05;
  282                 t = "TS05";
  283         }
  284 
  285         aprint_normal(": %s\n", t);
  286         aprint_normal_dev(sc->sc_dev, 
  287             "rev %d, extended features %s, transport %s\n",
  288             (sc->sc_vts->status.xst2 & TS_SF_MCRL) >> 2,
  289             (sc->sc_vts->status.xst2 & TS_SF_EFES ? "enabled" : "disabled"),
  290             (TS_RCSR(TSSR) & TS_OFL ? "offline" : "online"));
  291 
  292         uba_intr_establish(ua->ua_icookie, ua->ua_cvec, tsintr,
  293             sc, &sc->sc_intrcnt);
  294         evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  295             device_xname(sc->sc_dev), "intr");
  296 }
  297 
  298 /*
  299  * Initialize a TS device. Set up UBA mapping registers,
  300  * initialize data structures, what else ???
  301  */
  302 void
  303 tsinit(struct ts_softc *sc)
  304 {
  305         if (sc->sc_mapped == 0) {
  306 
  307                 /*
  308                  * Map the communications area and command and message
  309                  * buffer into Unibus address space.
  310                  */
  311                 sc->sc_ui.ui_size = sizeof(struct ts);
  312                 if (ubmemalloc(sc->sc_uh, &sc->sc_ui, UBA_CANTWAIT))
  313                         return;
  314                 sc->sc_vts = (void *)sc->sc_ui.ui_vaddr;
  315                 sc->sc_bts = (void *)sc->sc_ui.ui_baddr;
  316                 sc->sc_waddr = sc->sc_ui.ui_baddr |
  317                     ((sc->sc_ui.ui_baddr >> 16) & 3);
  318                 sc->sc_mapped = 1;
  319         }
  320         tsreset(sc);
  321 }
  322 
  323 /*
  324  * Execute a (ioctl) command on the tape drive a specified number of times.
  325  * This routine sets up a buffer and calls the strategy routine which
  326  * issues the command to the controller.
  327  */
  328 void
  329 tscommand(struct ts_softc *sc, dev_t dev, int cmd, int count)
  330 {
  331         struct buf *bp;
  332 
  333 #ifdef TSDEBUG
  334         printf("tscommand (%x, %d)\n", cmd, count);
  335 #endif
  336 
  337         bp = &sc->ts_cbuf;
  338 
  339         mutex_enter(&bufcache_lock);
  340         while (bp->b_cflags & BC_BUSY) {
  341                 /*
  342                  * This special check is because BC_BUSY never
  343                  * gets cleared in the non-waiting rewind case. ???
  344                  */
  345                 if (bp->b_bcount == 0 && (bp->b_oflags & BO_DONE))
  346                         break;
  347                 if (bbusy(bp, false, 0, NULL) == 0)
  348                         break;
  349                 /* check MOT-flag !!! */
  350         }
  351         bp->b_flags = B_READ;
  352         mutex_exit(&bufcache_lock);
  353 
  354         /*
  355          * Load the buffer.  The b_count field gets used to hold the command
  356          * count.  the b_resid field gets used to hold the command mneumonic.
  357          * These 2 fields are "known" to be "safe" to use for this purpose.
  358          * (Most other drivers also use these fields in this way.)
  359          */
  360         bp->b_dev = dev;
  361         bp->b_bcount = count;
  362         bp->b_resid = cmd;
  363         bp->b_blkno = 0;
  364         bp->b_oflags = 0;
  365         bp->b_objlock = &buffer_lock;
  366         tsstrategy(bp);
  367         /*
  368          * In case of rewind from close, don't wait.
  369          * This is the only case where count can be 0.
  370          */
  371         if (count == 0)
  372                 return;
  373         biowait(bp);
  374         mutex_enter(&bufcache_lock);
  375         cv_broadcast(&bp->b_busy);
  376         bp->b_cflags = 0;
  377         mutex_exit(&bufcache_lock);
  378 }
  379 
  380 /*
  381  * Start an I/O operation on TS05 controller
  382  */
  383 int
  384 tsstart(struct ts_softc *sc, int isloaded)
  385 {
  386         struct buf *bp;
  387         int cmd;
  388 
  389         bp = BUFQ_PEEK(sc->sc_bufq);
  390         if (bp == NULL) {
  391                 return 0;
  392         }
  393 #ifdef TSDEBUG
  394         printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno);
  395 #endif
  396         /*
  397          * Check if command is an ioctl or not (ie. read or write).
  398          * If it's an ioctl then just set the flags for later use;
  399          * For other commands attempt to setup a buffer pointer.
  400          */
  401         if (bp == &sc->ts_cbuf) {
  402                 switch ((int)bp->b_resid) {
  403                 case MTWEOF:
  404                         cmd = TS_CMD_WTM;
  405                         break;
  406                 case MTFSF:
  407                         cmd = TS_CMD_STMF;
  408                         sc->sc_vts->cmd.cw1 = bp->b_bcount;
  409                         break;
  410                 case MTBSF:
  411                         cmd = TS_CMD_STMR;
  412                         sc->sc_vts->cmd.cw1 = bp->b_bcount;
  413                         break;
  414                 case MTFSR:
  415                         cmd = TS_CMD_SRF;
  416                         sc->sc_vts->cmd.cw1 = bp->b_bcount;
  417                         break;
  418                 case MTBSR:
  419                         cmd = TS_CMD_SRR;
  420                         sc->sc_vts->cmd.cw1 = bp->b_bcount;
  421                         break;
  422                 case MTREW:
  423                         cmd = TS_CMD_RWND;
  424                         break;
  425                 case MTOFFL:
  426                         cmd = TS_CMD_RWUL;
  427                         break;
  428                 case MTNOP:
  429                         cmd = TS_CMD_STAT;
  430                         break;
  431                 default:
  432                         aprint_error_dev(sc->sc_dev, "bad ioctl %d\n",
  433                                 (int)bp->b_resid);
  434                         /* Need a no-op. get status */
  435                         cmd = TS_CMD_STAT;
  436                 } /* end switch (bp->b_resid) */
  437         } else {
  438                 if (isloaded == 0) {
  439                         /*
  440                          * now we try to map the buffer into uba map space (???)
  441                          */
  442                         if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam,
  443                             bp->b_data,
  444                             bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT)) {
  445                                 uba_enqueue(&sc->sc_uu);
  446                                 return 0;
  447                         }
  448                         sc->sc_rtc = 0;
  449                 }
  450                 sc->sc_vts->cmd.cw1 = LOWORD(sc->sc_dmam->dm_segs[0].ds_addr);
  451                 sc->sc_vts->cmd.cw2 = HIWORD(sc->sc_dmam->dm_segs[0].ds_addr);
  452                 sc->sc_vts->cmd.cw3 = bp->b_bcount;
  453                 bp->b_error = 0; /* Used for error count */
  454 #ifdef TSDEBUG
  455                 printf("tsstart-1: err %d\n", bp->b_error);
  456 #endif
  457                 if (bp->b_flags & B_READ)
  458                         cmd = TS_CMD_RNF;
  459                 else
  460                         cmd = TS_CMD_WD;
  461         }
  462 
  463         /*
  464          * Now that the command-buffer is setup, give it to the controller
  465          */
  466         sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | cmd;
  467 #ifdef TSDEBUG
  468         printf("tsstart: sending cmdr %x\n", sc->sc_vts->cmd.cmdr);
  469 #endif
  470         TS_WCSR(TSDB, sc->sc_waddr);
  471         return 1;
  472 }
  473 
  474 /*
  475  * Called when there are free uba resources.
  476  */
  477 int
  478 tsready(struct uba_unit *uu)
  479 {
  480         struct ts_softc *sc = device_private(uu->uu_dev);
  481         struct buf *bp = BUFQ_PEEK(sc->sc_bufq);
  482 
  483         if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, bp->b_data,
  484             bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT))
  485                 return 0;
  486 
  487         tsstart(sc, 1);
  488         return 1;
  489 }
  490 
  491 /*
  492  * initialize the controller by sending WRITE CHARACTERISTICS command.
  493  * contents of command- and message-buffer are assembled during this
  494  * function.
  495  */
  496 void
  497 tswchar(struct ts_softc *sc)
  498 {
  499         /*
  500          * assemble and send "WRITE CHARACTERISTICS" command
  501          */
  502 
  503         sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_WCHAR;
  504         sc->sc_vts->cmd.cw1  = LOWORD(&sc->sc_bts->chr);
  505         sc->sc_vts->cmd.cw2  = HIWORD(&sc->sc_bts->chr);
  506         sc->sc_vts->cmd.cw3  = 010;                /* size of charact.-data */
  507 
  508         sc->sc_vts->chr.sadrl = LOWORD(&sc->sc_bts->status);
  509         sc->sc_vts->chr.sadrh = HIWORD(&sc->sc_bts->status);
  510         sc->sc_vts->chr.onesix = (sc->sc_type == TYPE_TS05 ? 020 : 016);
  511         sc->sc_vts->chr.chrw = TS_WC_ESS;
  512         sc->sc_vts->chr.xchrw = TS_WCX_HSP|TS_WCX_RBUF|TS_WCX_WBUF;
  513 
  514         TS_WCSR(TSDB, sc->sc_waddr);
  515 }
  516 
  517 /*
  518  * Reset the TS11. Return 1 if failed, 0 if succeeded.
  519  */
  520 bool
  521 tsreset(struct ts_softc *sc)
  522 {
  523         int timeout;
  524 
  525         /*
  526          * reset ctlr by writing into TSSR, then write characteristics
  527          */
  528         timeout = 0;            /* timeout in 10 seconds */
  529         TS_WCSR(TSSR, 0);       /* start initialization */
  530         while ((TS_RCSR(TSSR) & TS_SSR) == 0) {
  531                 DELAY(10000);
  532                 if (timeout++ > 1000)
  533                         return false;
  534         }
  535         return true;
  536 }
  537 
  538 static void
  539 prtstat(struct ts_softc *sc, int sr)
  540 {
  541         char buf[100];
  542 
  543         bitmask_snprintf(sr, TS_TSSR_BITS, buf, sizeof(buf));
  544         aprint_normal_dev(sc->sc_dev, "TSSR=%s\n", buf);
  545         bitmask_snprintf(sc->sc_vts->status.xst0,TS_XST0_BITS,buf,sizeof(buf));
  546         aprint_normal_dev(sc->sc_dev, "XST0=%s\n", buf);
  547 }
  548 
  549 /*
  550  * TSV05/TS05 interrupt routine
  551  */
  552 static void
  553 tsintr(void *arg)
  554 {
  555         struct ts_softc *sc = arg;
  556         struct buf *bp;
  557 
  558         unsigned short sr = TS_RCSR(TSSR);      /* save TSSR */
  559         unsigned short mh = sc->sc_vts->status.hdr;     /* and msg-header */
  560                 /* clear the message header ??? */
  561 
  562         short ccode = sc->sc_vts->cmd.cmdr & TS_CF_CCODE;
  563 
  564         bp = BUFQ_PEEK(sc->sc_bufq);
  565 #ifdef TSDEBUG
  566         {
  567                 char buf[100];
  568                 bitmask_snprintf(sr, TS_TSSR_BITS, buf, sizeof(buf));
  569                 printf("tsintr: sr %x mh %x\n", sr, mh);
  570                 printf("srbits: %s\n", buf);
  571         }
  572 #endif
  573         /*
  574          * There are two different things which can (and should) be checked:
  575          * the actual (internal) state and the device's result (tssr/msg.hdr)
  576          *
  577          * For each state there's only one "normal" interrupt. Anything else
  578          * has to be checked more intensively. Thus in a first run according
  579          * to the internal state the expected interrupt is checked/handled.
  580          *
  581          * In a second run the remaining (not yet handled) interrupts are
  582          * checked according to the drive's result.
  583          */
  584         switch (sc->sc_state) {
  585 
  586         case TS_INVALID:
  587                 /*
  588                  * Ignore unsolicited interrupts.
  589                  */
  590                 log(LOG_WARNING, "%s: stray intr [%x,%x]\n",
  591                         device_xname(sc->sc_dev), sr, mh);
  592                 return;
  593 
  594         case TS_INIT:
  595                 /*
  596                  * Init phase ready.
  597                  */
  598                 wakeup(sc);
  599                 return;
  600 
  601         case TS_RUNNING:
  602         case TS_FASTREPOS:
  603                 /*
  604                  * Here we expect interrupts indicating the end of
  605                  * commands or indicating problems.
  606                  */
  607                 /*
  608                  * Anything else is handled outside this switch ...
  609                  */
  610                 break;
  611 
  612         default:
  613                 aprint_error_dev(sc->sc_dev,
  614                     "unexpected interrupt during state %d [%x,%x]\n",
  615                     sc->sc_state, sr, mh);
  616                 return;
  617         }
  618 
  619         /*
  620          * now we check the termination class.
  621          */
  622         switch (sr & TS_TC) {
  623 
  624         case TS_TC_NORM:
  625                 /*
  626                  * Normal termination -- The operation is completed
  627                  * witout incident.
  628                  */
  629                 if (sc->sc_state == TS_FASTREPOS) {
  630 #ifdef TSDEBUG
  631                         printf("Fast repos interrupt\n");
  632 #endif
  633                         /* Fast repos succeeded, start normal data xfer */
  634                         sc->sc_state = TS_RUNNING;
  635                         tsstart(sc, 1);
  636                         return;
  637                 }
  638                 sc->sc_liowf = (ccode == TS_CC_WRITE);
  639                 break;
  640 
  641         case TS_TC_ATTN:
  642                 /*
  643                  * Attention condition -- this code indicates that the
  644                  * drive has undergone a status change, such as going
  645                  * off-line or coming on-line.
  646                  * (Without EAI enabled, no Attention interrupts occur.
  647                  * drive status changes are signaled by the VCK flag.)
  648                  */
  649                 return;
  650 
  651         case TS_TC_TSA:
  652                 /*
  653                  * Tape Status Alert -- A status condition is encountered
  654                  * that may have significance to the program. Bits of
  655                  * interest in the extended status registers include
  656                  * TMK, EOT and RLL.
  657                  */
  658 #ifdef TSDEBUG
  659                 {
  660                         char buf[100];
  661                         bitmask_snprintf(sc->sc_vts->status.xst0,
  662                             TS_XST0_BITS, buf, sizeof(buf));
  663                         printf("TSA: sr %x bits %s\n",
  664                             sc->sc_vts->status.xst0, buf);
  665                 }
  666 #endif
  667                 if (sc->sc_vts->status.xst0 & TS_SF_TMK) {
  668 #ifdef TSDEBUG
  669                         printf(("Tape Mark detected"));
  670 #endif
  671                         /* Read to end-of-file. No error. */
  672                         break;
  673                 }
  674                 if (sc->sc_vts->status.xst0 & TS_SF_EOT) {
  675                         /* End of tape. Bad. */
  676 #ifdef TSDEBUG
  677                         printf("TS_TC_TSA: EOT\n");
  678 #endif
  679                         if (bp != NULL)
  680                                 bp->b_error = EIO;
  681                         break;
  682                 }
  683                 if (sc->sc_vts->status.xst0 & TS_SF_RLS)
  684                         break;
  685 #ifndef TSDEBUG
  686                 {
  687                         char buf[100];
  688                         bitmask_snprintf(sc->sc_vts->status.xst0,
  689                             TS_XST0_BITS, buf, sizeof(buf));
  690                         printf("TSA: sr %x bits %s\n",
  691                             sc->sc_vts->status.xst0, buf);
  692                 }
  693 #endif
  694                 break;
  695 
  696         case TS_TC_FR:
  697                 /*
  698                  * Function Reject -- The specified function was not
  699                  * initiated. Bits of interest include OFL, VCK, BOT,
  700                  * WLE, ILC and ILA.
  701                  */
  702                 if (sr & TS_OFL)
  703                         printf("tape is off-line.\n");
  704 #ifdef TSDEBUG
  705                 {
  706                         char buf[100];
  707                         bitmask_snprintf(sc->sc_vts->status.xst0,
  708                             TS_XST0_BITS, buf, sizeof(buf));
  709                         printf("FR: sr %x bits %s\n",
  710                             sc->sc_vts->status.xst0, buf);
  711                 }
  712 #endif
  713                 if (sc->sc_vts->status.xst0 & TS_SF_VCK)
  714                         printf("Volume check\n");
  715                 if (sc->sc_vts->status.xst0 & TS_SF_BOT)
  716                         printf("Start of tape.\n");
  717                 if (sc->sc_vts->status.xst0 & TS_SF_WLE)
  718                         printf("Write Lock Error\n");
  719                 if (sc->sc_vts->status.xst0 & TS_SF_EOT)
  720                         printf("End of tape.\n");
  721                 break;
  722 
  723         case TS_TC_TPD:
  724                 /*
  725                  * Recoverable Error -- Tape position is a record beyond
  726                  * what its position was when the function was initiated.
  727                  * Suggested recovery procedure is to log the error and
  728                  * issue the appropriate retry command.
  729                  *
  730                  * Do a fast repositioning one record back.
  731                  */
  732                 sc->sc_state = TS_FASTREPOS;
  733 #ifdef TSDEBUG
  734                 printf("TS_TC_TPD: errcnt %d\n", sc->sc_rtc);
  735 #endif
  736                 if (sc->sc_rtc++ == 8) {
  737                         aprint_error_dev(sc->sc_dev, "failed 8 retries\n");
  738                         prtstat(sc, sr);
  739                         if (bp != NULL)
  740                                 bp->b_error = EIO;
  741                         break;
  742                 }
  743                 sc->sc_vts->cmd.cmdr = TS_CF_ACK | TS_CF_IE | TS_CMD_SRR;
  744                 sc->sc_vts->cmd.cw1 = 1;
  745                 TS_WCSR(TSDB, sc->sc_waddr);
  746                 return;
  747 
  748         case TS_TC_TNM:
  749                 /*
  750                  * Recoverable Error -- Tape position has not changed.
  751                  * Suggested recovery procedure is to log the error and
  752                  * reissue the original command.
  753                  */
  754                 if (sc->sc_rtc++ == 8) {
  755                         aprint_error_dev(sc->sc_dev, "failed 8 retries\n");
  756                         prtstat(sc, sr);
  757                         if (bp != NULL)
  758                                 bp->b_error = EIO;
  759                         break;
  760                 }
  761                 tsstart(sc, 1);
  762                 return;
  763 
  764         case TS_TC_TPL:
  765                 /*
  766                  * Unrecoverable Error -- Tape position has been lost.
  767                  * No valid recovery procedures exist unless the tape
  768                  * has labels or sequence numbers.
  769                  */
  770                 aprint_error_dev(sc->sc_dev, "tape position lost\n");
  771                 if (bp != NULL)
  772                         bp->b_error = EIO;
  773                 break;
  774 
  775         case TS_TC_FCE:
  776                 /*
  777                  * Fatal subsytem Error -- The subsytem is incapable
  778                  * of properly performing commands, or at least its
  779                  * integrity is seriously questionable. Refer to the
  780                  * fatal class code field in the TSSR register for
  781                  * additional information on the type of fatal error.
  782                  */
  783                 aprint_error_dev(sc->sc_dev, "fatal controller error\n");
  784                 prtstat(sc, sr);
  785                 break;
  786 
  787         default:
  788                 aprint_error_dev(sc->sc_dev,
  789                     "error 0x%x, resetting controller\n", sr & TS_TC);
  790                 tsreset(sc);
  791         }
  792         if ((bp = BUFQ_GET(sc->sc_bufq)) != NULL) {
  793 #ifdef TSDEBUG
  794                 printf("tsintr2: que %p\n", BUFQ_PEEK(sc->sc_bufq));
  795 #endif
  796                 if (bp != &sc->ts_cbuf) {       /* no ioctl */
  797                         bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
  798                         uba_done(sc->sc_uh);
  799                 }
  800                 bp->b_resid = sc->sc_vts->status.rbpcr;
  801                 biodone (bp);
  802         }
  803         tsstart(sc, 0);
  804 }
  805 
  806 
  807 /*
  808  * Open a ts device and set the unit online.  If the controller is not
  809  * in the run state, call init to initialize the ts controller first.
  810  */
  811 int
  812 tsopen(dev_t dev, int flag, int type, struct lwp *l)
  813 {
  814         struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(dev));
  815 
  816         if (sc == NULL)
  817                 return ENXIO;
  818 
  819         if (sc->sc_state < TS_RUNNING)
  820                 return ENXIO;
  821 
  822         if (sc->sc_openf)
  823                 return EBUSY;
  824         sc->sc_openf = 1;
  825 
  826         /*
  827          * check if transport is really online.
  828          * (without attention-interrupts enabled, we really don't know
  829          * the actual state of the transport. Thus we call get-status
  830          * (ie. MTNOP) once and check the actual status.)
  831          */
  832         if (TS_RCSR(TSSR) & TS_OFL) {
  833                 uprintf("%s: transport is offline.\n", device_xname(sc->sc_dev));
  834                 sc->sc_openf = 0;
  835                 return EIO;             /* transport is offline */
  836         }
  837         tscommand(sc, dev, MTNOP, 1);
  838         if ((flag & FWRITE) && (sc->sc_vts->status.xst0 & TS_SF_WLK)) {
  839                 uprintf("%s: no write ring.\n", device_xname(sc->sc_dev));
  840                 sc->sc_openf = 0;
  841                 return EROFS;
  842         }
  843         if (sc->sc_vts->status.xst0 & TS_SF_VCK) {
  844                 sc->sc_vts->cmd.cmdr = TS_CF_CVC|TS_CF_ACK;
  845                 TS_WCSR(TSDB, sc->sc_waddr);
  846         }
  847         tscommand(sc, dev, MTNOP, 1);
  848 #ifdef TSDEBUG
  849         {
  850                 char buf[100];
  851                 bitmask_snprintf(sc->sc_vts->status.xst0,
  852                     TS_XST0_BITS, buf, sizeof(buf));
  853                 printf("tsopen: xst0 %s\n", buf);
  854         }
  855 #endif
  856         sc->sc_liowf = 0;
  857         return 0;
  858 }
  859 
  860 
  861 /*
  862  * Close tape device.
  863  *
  864  * If tape was open for writing or last operation was
  865  * a write, then write two EOF's and backspace over the last one.
  866  * Unless this is a non-rewinding special file, rewind the tape.
  867  *
  868  * Make the tape available to others, by clearing openf flag.
  869  */
  870 int
  871 tsclose(dev_t dev, int flag, int type, struct lwp *l)
  872 {
  873         struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(dev));
  874 
  875         if (flag == FWRITE || ((flag & FWRITE) && sc->sc_liowf)) {
  876                 /*
  877                  * We are writing two tape marks (EOT), but place the tape
  878                  * before the second one, so that another write operation
  879                  * will overwrite the second one and leave and EOF-mark.
  880                  */
  881                 tscommand(sc, dev, MTWEOF, 1);  /* Write Tape Mark */
  882                 tscommand(sc, dev, MTWEOF, 1);  /* Write Tape Mark */
  883                 tscommand(sc, dev, MTBSF, 1);   /* Skip Tape Marks Reverse */
  884         }
  885 
  886         if ((dev & T_NOREWIND) == 0)
  887                 tscommand(sc, dev, MTREW, 0);
  888 
  889         sc->sc_openf = 0;
  890         sc->sc_liowf = 0;
  891         return 0;
  892 }
  893 
  894 
  895 /*
  896  * Manage buffers and perform block mode read and write operations.
  897  */
  898 void
  899 tsstrategy(struct buf *bp)
  900 {
  901         struct ts_softc *sc = device_lookup_private(&ts_cd, TS_UNIT(bp->b_dev));
  902         bool empty;
  903         int s;
  904 
  905 #ifdef TSDEBUG
  906         printf("buf: %p bcount %ld blkno %d\n", bp, bp->b_bcount, bp->b_blkno);
  907 #endif
  908         s = splbio ();
  909         empty = (BUFQ_PEEK(sc->sc_bufq) == NULL);
  910         BUFQ_PUT(sc->sc_bufq, bp);
  911         if (empty)
  912                 tsstart(sc, 0);
  913         splx(s);
  914 }
  915 
  916 
  917 /*
  918  * Catch ioctl commands, and call the "command" routine to do them.
  919  */
  920 int
  921 tsioctl(dev_t dev,
  922         u_long cmd,
  923         void *data,
  924         int flag,
  925         struct lwp *l)
  926 {
  927         struct buf *bp;
  928         struct ts_softc * const sc = device_lookup_private(&ts_cd, TS_UNIT(dev));
  929         struct mtop *mtop;      /* mag tape cmd op to perform */
  930         struct mtget *mtget;    /* mag tape struct to get info in */
  931         int callcount;          /* number of times to call routine */
  932         int scount;                     /* number of files/records to space */
  933         int spaceop = 0;                /* flag for skip/space operation */
  934         int error = 0;
  935 
  936 #ifdef TSDEBUG
  937         printf("tsioctl (%x, %lx, %p, %d)\n", dev, cmd, data, flag);
  938 #endif
  939 
  940         bp = &sc->ts_cbuf;
  941 
  942         switch (cmd) {
  943         case MTIOCTOP:                  /* do a mag tape op */
  944                 mtop = (struct mtop *)data;
  945                 switch (mtop->mt_op) {
  946                 case MTWEOF:            /* write an end-of-file record */
  947                         callcount = mtop->mt_count;
  948                         scount = 1;
  949                         break;
  950                 case MTFSR:             /* forward space record */
  951                 case MTBSR:             /* backward space record */
  952                         spaceop = 1;
  953                 case MTFSF:             /* forward space file */
  954                 case MTBSF:             /* backward space file */
  955                         callcount = 1;
  956                         scount = mtop->mt_count;
  957                         break;
  958                 case MTREW:             /* rewind */
  959                 case MTOFFL:            /* rewind and put the drive offline */
  960                 case MTNOP:             /* no operation, sets status only */
  961                         callcount = 1;
  962                         scount = 1;             /* wait for this rewind */
  963                         break;
  964                 case MTRETEN:           /* retension */
  965                 case MTERASE:           /* erase entire tape */
  966                 case MTEOM:             /* forward to end of media */
  967                 case MTNBSF:            /* backward space to begin of file */
  968                 case MTCACHE:           /* enable controller cache */
  969                 case MTNOCACHE:         /* disable controller cache */
  970                 case MTSETBSIZ:         /* set block size; 0 for variable */
  971                 case MTSETDNSTY:        /* set density code for current mode */
  972                         printf("ioctl %d not implemented.\n", mtop->mt_op);
  973                         return (ENXIO);
  974                 default:
  975 #ifdef TSDEBUG
  976                         printf("invalid ioctl %d\n", mtop->mt_op);
  977 #endif
  978                         return (ENXIO);
  979                 }       /* switch (mtop->mt_op) */
  980 
  981                 if (callcount <= 0 || scount <= 0) {
  982 #ifdef TSDEBUG
  983                         printf("invalid values %d/%d\n", callcount, scount);
  984 #endif
  985                         return (EINVAL);
  986                 }
  987                 do {
  988                         tscommand(sc, dev, mtop->mt_op, scount);
  989                         if (spaceop && bp->b_resid) {
  990 #ifdef TSDEBUG
  991                                 printf(("spaceop didn't complete\n"));
  992 #endif
  993                                 return (EIO);
  994                         }
  995                         if (bp->b_error != 0) {
  996 #ifdef TSDEBUG
  997                                 printf("error in ioctl %d\n", mtop->mt_op);
  998 #endif
  999                                 break;
 1000                         }
 1001                 } while (--callcount > 0);
 1002                 if (bp->b_error != 0)
 1003                         error = bp->b_error;
 1004                 return (error);
 1005 
 1006         case MTIOCGET:                  /* get tape status */
 1007                 mtget = (struct mtget *)data;
 1008                 mtget->mt_type = MT_ISTS;
 1009                 mtget->mt_dsreg = TS_RCSR(TSSR);
 1010                 mtget->mt_erreg = sc->sc_vts->status.xst0;
 1011                 mtget->mt_resid = 0;            /* ??? */
 1012                 mtget->mt_density = 0;          /* ??? */
 1013                 break;
 1014 
 1015         case MTIOCIEOT:                 /* ignore EOT error */
 1016 #ifdef TSDEBUG
 1017                 printf(("MTIOCIEOT not implemented.\n"));
 1018 #endif
 1019                 return (ENXIO);
 1020 
 1021         case MTIOCEEOT:                 /* enable EOT error */
 1022 #ifdef TSDEBUG
 1023                 printf(("MTIOCEEOT not implemented.\n"));
 1024 #endif
 1025                 return (ENXIO);
 1026 
 1027         default:
 1028 #ifdef TSDEBUG
 1029                 printf("invalid ioctl cmd 0x%lx\n", cmd);
 1030 #endif
 1031                 return (ENXIO);
 1032         }
 1033 
 1034         return (0);
 1035 }
 1036 
 1037 
 1038 /*
 1039  *
 1040  */
 1041 int
 1042 tsread(dev_t dev, struct uio *uio, int flag)
 1043 {
 1044         return (physio (tsstrategy, NULL, dev, B_READ, minphys, uio));
 1045 }
 1046 
 1047 /*
 1048  *
 1049  */
 1050 int
 1051 tswrite(dev_t dev, struct uio *uio, int flag)
 1052 {
 1053         return (physio (tsstrategy, NULL, dev, B_WRITE, minphys, uio));
 1054 }
 1055 
 1056 /*
 1057  *
 1058  */
 1059 int
 1060 tsdump(dev_t dev, daddr_t blkno, void *va, size_t size)
 1061 {
 1062         return EIO;
 1063 }

Cache object: b788cced2bb9916ee1cfafc4a4498a07


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.