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

Cache object: 319cfdfb35c6d4c880664cd5499394d9


[ 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.