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

Cache object: 4d49ec7e4e398bf6e5cb5b7678398b7e


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