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/rl.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: rl.c,v 1.39 2008/06/11 17:27:59 drochner Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed at Ludd, University of
   17  *      Lule}, Sweden and its contributors.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * RL11/RLV11/RLV12 disk controller driver and
   35  * RL01/RL02 disk device driver.
   36  *
   37  * TODO:
   38  *      Handle disk errors more gracefully
   39  *      Do overlapping seeks on multiple drives
   40  *
   41  * Implementation comments:
   42  *
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __KERNEL_RCSID(0, "$NetBSD: rl.c,v 1.39 2008/06/11 17:27:59 drochner Exp $");
   47 
   48 #include <sys/param.h>
   49 #include <sys/device.h>
   50 #include <sys/systm.h>
   51 #include <sys/conf.h>
   52 #include <sys/disk.h>
   53 #include <sys/disklabel.h>
   54 #include <sys/buf.h>
   55 #include <sys/bufq.h>
   56 #include <sys/stat.h>
   57 #include <sys/dkio.h>
   58 #include <sys/fcntl.h>
   59 #include <sys/event.h>
   60 
   61 #include <ufs/ufs/dinode.h>
   62 #include <ufs/ffs/fs.h>
   63 
   64 #include <sys/bus.h>
   65 
   66 #include <dev/qbus/ubavar.h>
   67 #include <dev/qbus/rlreg.h>
   68 #include <dev/qbus/rlvar.h>
   69 
   70 #include "ioconf.h"
   71 #include "locators.h"
   72 
   73 static  int rlcmatch(device_t, cfdata_t, void *);
   74 static  void rlcattach(device_t, device_t, void *);
   75 static  int rlcprint(void *, const char *);
   76 static  void rlcintr(void *);
   77 static  int rlmatch(device_t, cfdata_t, void *);
   78 static  void rlattach(device_t, device_t, void *);
   79 static  void rlcstart(struct rlc_softc *, struct buf *);
   80 static  void waitcrdy(struct rlc_softc *);
   81 static  void rlcreset(device_t);
   82 
   83 CFATTACH_DECL_NEW(rlc, sizeof(struct rlc_softc),
   84     rlcmatch, rlcattach, NULL, NULL);
   85 
   86 CFATTACH_DECL_NEW(rl, sizeof(struct rl_softc),
   87     rlmatch, rlattach, NULL, NULL);
   88 
   89 static dev_type_open(rlopen);
   90 static dev_type_close(rlclose);
   91 static dev_type_read(rlread);
   92 static dev_type_write(rlwrite);
   93 static dev_type_ioctl(rlioctl);
   94 static dev_type_strategy(rlstrategy);
   95 static dev_type_dump(rldump);
   96 static dev_type_size(rlpsize);
   97 
   98 const struct bdevsw rl_bdevsw = {
   99         rlopen, rlclose, rlstrategy, rlioctl, rldump, rlpsize, D_DISK
  100 };
  101 
  102 const struct cdevsw rl_cdevsw = {
  103         rlopen, rlclose, rlread, rlwrite, rlioctl,
  104         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
  105 };
  106 
  107 #define MAXRLXFER (RL_BPS * RL_SPT)
  108 
  109 #define RL_WREG(reg, val) \
  110         bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
  111 #define RL_RREG(reg) \
  112         bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
  113 
  114 static const char * const rlstates[] = {
  115         "drive not loaded",
  116         "drive spinning up",
  117         "drive brushes out",
  118         "drive loading heads",
  119         "drive seeking",
  120         "drive ready",
  121         "drive unloading heads",
  122         "drive spun down",
  123 };
  124 
  125 static const struct dkdriver rldkdriver = {
  126         rlstrategy, minphys
  127 };
  128 
  129 static const char *
  130 rlstate(struct rlc_softc *sc, int unit)
  131 {
  132         int i = 0;
  133 
  134         do {
  135                 RL_WREG(RL_DA, RLDA_GS);
  136                 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
  137                 waitcrdy(sc);
  138         } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
  139         if (i == 10)
  140                 return NULL;
  141         i = RL_RREG(RL_MP) & RLMP_STATUS;
  142         return rlstates[i];
  143 }
  144 
  145 void
  146 waitcrdy(struct rlc_softc *sc)
  147 {
  148         int i;
  149 
  150         for (i = 0; i < 1000; i++) {
  151                 DELAY(10000);
  152                 if (RL_RREG(RL_CS) & RLCS_CRDY)
  153                         return;
  154         }
  155         aprint_error_dev(sc->sc_dev, "never got ready\n"); /* ?panic? */
  156 }
  157 
  158 int
  159 rlcprint(void *aux, const char *name)
  160 {
  161         struct rlc_attach_args *ra = aux;
  162 
  163         if (name)
  164                 aprint_normal("RL0%d at %s",
  165                     ra->type & RLMP_DT ? '2' : '1', name);
  166         aprint_normal(" drive %d", ra->hwid);
  167         return UNCONF;
  168 }
  169 
  170 /*
  171  * Force the controller to interrupt.
  172  */
  173 int
  174 rlcmatch(device_t parent, cfdata_t cf, void *aux)
  175 {
  176         struct uba_attach_args *ua = aux;
  177         struct rlc_softc ssc, *sc = &ssc;
  178         int i;
  179 
  180         sc->sc_iot = ua->ua_iot;
  181         sc->sc_ioh = ua->ua_ioh;
  182         /* Force interrupt by issuing a "Get Status" command */
  183         RL_WREG(RL_DA, RLDA_GS);
  184         RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
  185 
  186         for (i = 0; i < 100; i++) {
  187                 DELAY(100000);
  188                 if (RL_RREG(RL_CS) & RLCS_CRDY)
  189                         return 1;
  190         }
  191         return 0;
  192 }
  193 
  194 void
  195 rlcattach(device_t parent, device_t self, void *aux)
  196 {
  197         struct rlc_softc *sc = device_private(self);
  198         struct uba_attach_args *ua = aux;
  199         struct rlc_attach_args ra;
  200         int i, error;
  201 
  202         sc->sc_dev = self;
  203         sc->sc_uh = device_private(parent);
  204         sc->sc_iot = ua->ua_iot;
  205         sc->sc_ioh = ua->ua_ioh;
  206         sc->sc_dmat = ua->ua_dmat;
  207         uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
  208                 rlcintr, sc, &sc->sc_intrcnt);
  209         evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  210                 device_xname(sc->sc_dev), "intr");
  211         uba_reset_establish(rlcreset, self);
  212 
  213         printf("\n");
  214 
  215         /*
  216          * The RL11 can only have one transfer going at a time,
  217          * and max transfer size is one track, so only one dmamap
  218          * is needed.
  219          */
  220         error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
  221             BUS_DMA_ALLOCNOW, &sc->sc_dmam);
  222         if (error) {
  223                 aprint_error(": Failed to allocate DMA map, error %d\n", error);
  224                 return;
  225         }
  226         bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER);
  227         for (i = 0; i < RL_MAXDPC; i++) {
  228                 waitcrdy(sc);
  229                 RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
  230                 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
  231                 waitcrdy(sc);
  232                 ra.type = RL_RREG(RL_MP);
  233                 ra.hwid = i;
  234                 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
  235                         config_found(sc->sc_dev, &ra, rlcprint);
  236         }
  237 }
  238 
  239 int
  240 rlmatch(device_t parent, cfdata_t cf, void *aux)
  241 {
  242         struct rlc_attach_args *ra = aux;
  243 
  244         if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
  245             cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
  246                 return 0;
  247         return 1;
  248 }
  249 
  250 void
  251 rlattach(device_t parent, device_t self, void *aux)
  252 {
  253         struct rl_softc *rc = device_private(self);
  254         struct rlc_attach_args *ra = aux;
  255         struct disklabel *dl;
  256 
  257         rc->rc_dev = self;
  258         rc->rc_rlc = device_private(parent);
  259         rc->rc_hwid = ra->hwid;
  260         disk_init(&rc->rc_disk, device_xname(rc->rc_dev), &rldkdriver);
  261         disk_attach(&rc->rc_disk);
  262         dl = rc->rc_disk.dk_label;
  263         dl->d_npartitions = 3;
  264         strcpy(dl->d_typename, "RL01");
  265         if (ra->type & RLMP_DT)
  266                 dl->d_typename[3] = '2';
  267         dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
  268         dl->d_nsectors = RL_SPT/2;
  269         dl->d_ntracks = RL_SPD;
  270         dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
  271         dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
  272         dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
  273         dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
  274             dl->d_secperunit;
  275         dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
  276         dl->d_interleave = dl->d_headswitch = 1;
  277         dl->d_bbsize = BBSIZE;
  278         dl->d_sbsize = SBLOCKSIZE;
  279         dl->d_rpm = 2400;
  280         dl->d_type = DTYPE_DEC;
  281         printf(": %s, %s\n", dl->d_typename, rlstate(rc->rc_rlc, ra->hwid));
  282 
  283         /*
  284          * XXX We should try to discovery wedges here, but
  285          * XXX that would mean loading up the pack and being
  286          * XXX able to do I/O.  Should use config_defer() here.
  287          */
  288 }
  289 
  290 int
  291 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
  292 {
  293         struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
  294         struct rlc_softc *sc;
  295         int error, part, mask;
  296         struct disklabel *dl;
  297         const char *msg;
  298 
  299         /*
  300          * Make sure this is a reasonable open request.
  301          */
  302         if (rc == NULL)
  303                 return ENXIO;
  304 
  305         sc = rc->rc_rlc;
  306         part = DISKPART(dev);
  307 
  308         mutex_enter(&rc->rc_disk.dk_openlock);
  309 
  310         /*
  311          * If there are wedges, and this is not RAW_PART, then we
  312          * need to fail.
  313          */
  314         if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
  315                 error = EBUSY;
  316                 goto bad1;
  317         }
  318 
  319         /* Check that the disk actually is useable */
  320         msg = rlstate(sc, rc->rc_hwid);
  321         if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
  322             msg == rlstates[RLMP_SPUNDOWN]) {
  323                 error = ENXIO;
  324                 goto bad1;
  325         }
  326         /*
  327          * If this is the first open; read in where on the disk we are.
  328          */
  329         dl = rc->rc_disk.dk_label;
  330         if (rc->rc_state == DK_CLOSED) {
  331                 u_int16_t mp;
  332                 int maj;
  333                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  334                 waitcrdy(sc);
  335                 mp = RL_RREG(RL_MP);
  336                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  337                 rc->rc_cyl = (mp >> 7) & 0777;
  338                 rc->rc_state = DK_OPEN;
  339                 /* Get disk label */
  340                 maj = cdevsw_lookup_major(&rl_cdevsw);
  341                 if ((msg = readdisklabel(MAKEDISKDEV(maj,
  342                     device_unit(rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
  343                         aprint_normal_dev(rc->rc_dev, "%s", msg);
  344                 aprint_normal_dev(rc->rc_dev, "size %d sectors\n",
  345                     dl->d_secperunit);
  346         }
  347         if (part >= dl->d_npartitions) {
  348                 error = ENXIO;
  349                 goto bad1;
  350         }
  351 
  352         mask = 1 << part;
  353         switch (fmt) {
  354         case S_IFCHR:
  355                 rc->rc_disk.dk_copenmask |= mask;
  356                 break;
  357         case S_IFBLK:
  358                 rc->rc_disk.dk_bopenmask |= mask;
  359                 break;
  360         }
  361         rc->rc_disk.dk_openmask |= mask;
  362         error = 0;
  363  bad1:
  364         mutex_exit(&rc->rc_disk.dk_openlock);
  365         return (error);
  366 }
  367 
  368 int
  369 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
  370 {
  371         int unit = DISKUNIT(dev);
  372         struct rl_softc *rc = device_lookup_private(&rl_cd, unit);
  373         int mask = (1 << DISKPART(dev));
  374 
  375         mutex_enter(&rc->rc_disk.dk_openlock);
  376 
  377         switch (fmt) {
  378         case S_IFCHR:
  379                 rc->rc_disk.dk_copenmask &= ~mask;
  380                 break;
  381         case S_IFBLK:
  382                 rc->rc_disk.dk_bopenmask &= ~mask;
  383                 break;
  384         }
  385         rc->rc_disk.dk_openmask =
  386             rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
  387 
  388         if (rc->rc_disk.dk_openmask == 0)
  389                 rc->rc_state = DK_CLOSED; /* May change pack */
  390         mutex_exit(&rc->rc_disk.dk_openlock);
  391         return 0;
  392 }
  393 
  394 void
  395 rlstrategy(struct buf *bp)
  396 {
  397         struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
  398         struct disklabel *lp;
  399         int s;
  400 
  401         if (rc == NULL || rc->rc_state != DK_OPEN) /* How did we end up here at all? */
  402                 panic("rlstrategy: state impossible");
  403 
  404         lp = rc->rc_disk.dk_label;
  405         if (bounds_check_with_label(&rc->rc_disk, bp, 1) <= 0)
  406                 goto done;
  407 
  408         if (bp->b_bcount == 0)
  409                 goto done;
  410 
  411         bp->b_rawblkno =
  412             bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
  413         bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
  414 
  415         s = splbio();
  416         BUFQ_PUT(rc->rc_rlc->sc_q, bp);
  417         rlcstart(rc->rc_rlc, 0);
  418         splx(s);
  419         return;
  420 
  421 done:   biodone(bp);
  422 }
  423 
  424 int
  425 rlioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
  426 {
  427         struct rl_softc *rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
  428         struct disklabel *lp = rc->rc_disk.dk_label;
  429         int err = 0;
  430 #ifdef __HAVE_OLD_DISKLABEL
  431         struct disklabel newlabel;
  432 #endif
  433 
  434         switch (cmd) {
  435         case DIOCGDINFO:
  436                 bcopy(lp, addr, sizeof (struct disklabel));
  437                 break;
  438 
  439 #ifdef __HAVE_OLD_DISKLABEL
  440         case ODIOCGDINFO:
  441                 newlabel = *lp;
  442                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  443                         return ENOTTY;
  444                 bcopy(&newlabel, addr, sizeof (struct olddisklabel));
  445                 break;
  446 #endif
  447 
  448         case DIOCGPART:
  449                 ((struct partinfo *)addr)->disklab = lp;
  450                 ((struct partinfo *)addr)->part =
  451                     &lp->d_partitions[DISKPART(dev)];
  452                 break;
  453 
  454         case DIOCSDINFO:
  455         case DIOCWDINFO:
  456 #ifdef __HAVE_OLD_DISKLABEL
  457         case ODIOCWDINFO:
  458         case ODIOCSDINFO:
  459 #endif
  460         {
  461                 struct disklabel *tp;
  462 
  463 #ifdef __HAVE_OLD_DISKLABEL
  464                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
  465                         memset(&newlabel, 0, sizeof newlabel);
  466                         memcpy(&newlabel, addr, sizeof (struct olddisklabel));
  467                         tp = &newlabel;
  468                 } else
  469 #endif
  470                 tp = (struct disklabel *)addr;
  471 
  472                 if ((flag & FWRITE) == 0)
  473                         err = EBADF;
  474                 else {
  475                         mutex_enter(&rc->rc_disk.dk_openlock);
  476                         err = ((
  477 #ifdef __HAVE_OLD_DISKLABEL
  478                                cmd == ODIOCSDINFO ||
  479 #endif
  480                                cmd == DIOCSDINFO) ?
  481                             setdisklabel(lp, tp, 0, 0) :
  482                             writedisklabel(dev, rlstrategy, lp, 0));
  483                         mutex_exit(&rc->rc_disk.dk_openlock);
  484                 }
  485                 break;
  486         }
  487 
  488         case DIOCWLABEL:
  489                 if ((flag & FWRITE) == 0)
  490                         err = EBADF;
  491                 break;
  492 
  493         case DIOCAWEDGE: {
  494                 struct dkwedge_info *dkw = (void *) addr;
  495 
  496                 if ((flag & FWRITE) == 0)
  497                         return (EBADF);
  498 
  499                 /* If the ioctl happens here, the parent is us. */
  500                 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
  501                 return dkwedge_add(dkw);
  502         }
  503 
  504         case DIOCDWEDGE: {
  505                 struct dkwedge_info *dkw = (void *) addr;
  506 
  507                 if ((flag & FWRITE) == 0)
  508                         return (EBADF);
  509 
  510                 /* If the ioctl happens here, the parent is us. */
  511                 strcpy(dkw->dkw_parent, device_xname(rc->rc_dev));
  512                 return dkwedge_del(dkw);
  513         }
  514 
  515         case DIOCLWEDGES: {
  516                 struct dkwedge_list *dkwl = (void *) addr;
  517 
  518                 return dkwedge_list(&rc->rc_disk, dkwl, l);
  519         }
  520 
  521         default:
  522                 err = ENOTTY;
  523                 break;
  524         }
  525         return err;
  526 }
  527 
  528 int
  529 rlpsize(dev_t dev)
  530 {
  531         struct rl_softc * const rc = device_lookup_private(&rl_cd, DISKUNIT(dev));
  532         struct disklabel *dl;
  533         int size;
  534 
  535         if (rc == NULL)
  536                 return -1;
  537         dl = rc->rc_disk.dk_label;
  538         size = dl->d_partitions[DISKPART(dev)].p_size *
  539             (dl->d_secsize / DEV_BSIZE);
  540         return size;
  541 }
  542 
  543 int
  544 rldump(dev_t dev, daddr_t blkno, void *va, size_t size)
  545 {
  546         /* Not likely... */
  547         return 0;
  548 }
  549 
  550 int
  551 rlread(dev_t dev, struct uio *uio, int ioflag)
  552 {
  553         return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
  554 }
  555 
  556 int
  557 rlwrite(dev_t dev, struct uio *uio, int ioflag)
  558 {
  559         return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
  560 }
  561 
  562 static const char * const rlerr[] = {
  563         "no",
  564         "operation incomplete",
  565         "read data CRC",
  566         "header CRC",
  567         "data late",
  568         "header not found",
  569         "",
  570         "",
  571         "non-existent memory",
  572         "memory parity error",
  573         "",
  574         "",
  575         "",
  576         "",
  577         "",
  578         "",
  579 };
  580 
  581 void
  582 rlcintr(void *arg)
  583 {
  584         struct rlc_softc *sc = arg;
  585         struct buf *bp;
  586         u_int16_t cs;
  587 
  588         bp = sc->sc_active;
  589         if (bp == 0) {
  590                 aprint_error_dev(sc->sc_dev, "strange interrupt\n");
  591                 return;
  592         }
  593         bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
  594         sc->sc_active = 0;
  595         cs = RL_RREG(RL_CS);
  596         if (cs & RLCS_ERR) {
  597                 int error = (cs & RLCS_ERRMSK) >> 10;
  598 
  599                 aprint_error_dev(sc->sc_dev, "%s\n", rlerr[error]);
  600                 bp->b_error = EIO;
  601                 bp->b_resid = bp->b_bcount;
  602                 sc->sc_bytecnt = 0;
  603         }
  604         if (sc->sc_bytecnt == 0) /* Finished transfer */
  605                 biodone(bp);
  606         rlcstart(sc, sc->sc_bytecnt ? bp : 0);
  607 }
  608 
  609 /*
  610  * Start routine. First position the disk to the given position,
  611  * then start reading/writing. An optimization would be to be able
  612  * to handle overlapping seeks between disks.
  613  */
  614 void
  615 rlcstart(struct rlc_softc *sc, struct buf *ob)
  616 {
  617         struct disklabel *lp;
  618         struct rl_softc *rc;
  619         struct buf *bp;
  620         int bn, cn, sn, tn, blks, err;
  621 
  622         if (sc->sc_active)
  623                 return; /* Already doing something */
  624 
  625         if (ob == 0) {
  626                 bp = BUFQ_GET(sc->sc_q);
  627                 if (bp == NULL)
  628                         return; /* Nothing to do */
  629                 sc->sc_bufaddr = bp->b_data;
  630                 sc->sc_diskblk = bp->b_rawblkno;
  631                 sc->sc_bytecnt = bp->b_bcount;
  632                 bp->b_resid = 0;
  633         } else
  634                 bp = ob;
  635         sc->sc_active = bp;
  636 
  637         rc = device_lookup_private(&rl_cd, DISKUNIT(bp->b_dev));
  638         bn = sc->sc_diskblk;
  639         lp = rc->rc_disk.dk_label;
  640         if (bn) {
  641                 cn = bn / lp->d_secpercyl;
  642                 sn = bn % lp->d_secpercyl;
  643                 tn = sn / lp->d_nsectors;
  644                 sn = sn % lp->d_nsectors;
  645         } else
  646                 cn = sn = tn = 0;
  647 
  648         /*
  649          * Check if we have to position disk first.
  650          */
  651         if (rc->rc_cyl != cn || rc->rc_head != tn) {
  652                 u_int16_t da = RLDA_SEEK;
  653                 if (cn > rc->rc_cyl)
  654                         da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
  655                 else
  656                         da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
  657                 if (tn)
  658                         da |= RLDA_HSSEEK;
  659                 waitcrdy(sc);
  660                 RL_WREG(RL_DA, da);
  661                 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
  662                 waitcrdy(sc);
  663                 rc->rc_cyl = cn;
  664                 rc->rc_head = tn;
  665         }
  666         RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
  667         blks = sc->sc_bytecnt/DEV_BSIZE;
  668 
  669         if (sn + blks > RL_SPT/2)
  670                 blks = RL_SPT/2 - sn;
  671         RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
  672         err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
  673             (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
  674             BUS_DMA_NOWAIT);
  675         if (err)
  676                 panic("%s: bus_dmamap_load failed: %d",
  677                     device_xname(sc->sc_dev), err);
  678         RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
  679 
  680         /* Count up vars */
  681         sc->sc_bufaddr = (char *)sc->sc_bufaddr + (blks*DEV_BSIZE);
  682         sc->sc_diskblk += blks;
  683         sc->sc_bytecnt -= (blks*DEV_BSIZE);
  684 
  685         if (bp->b_flags & B_READ)
  686                 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
  687         else
  688                 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
  689 }
  690 
  691 /*
  692  * Called once per controller when an ubareset occurs.
  693  * Retracts all disks and restarts active transfers.
  694  */
  695 void
  696 rlcreset(device_t dev)
  697 {
  698         struct rlc_softc *sc = device_private(dev);
  699         struct rl_softc *rc;
  700         int i;
  701         u_int16_t mp;
  702 
  703         for (i = 0; i < rl_cd.cd_ndevs; i++) {
  704                 if ((rc = device_lookup_private(&rl_cd, i)) == NULL)
  705                         continue;
  706                 if (rc->rc_state != DK_OPEN)
  707                         continue;
  708                 if (rc->rc_rlc != sc)
  709                         continue;
  710 
  711                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  712                 waitcrdy(sc);
  713                 mp = RL_RREG(RL_MP);
  714                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  715                 rc->rc_cyl = (mp >> 7) & 0777;
  716         }
  717         if (sc->sc_active == 0)
  718                 return;
  719 
  720         BUFQ_PUT(sc->sc_q, sc->sc_active);
  721         sc->sc_active = 0;
  722         rlcstart(sc, 0);
  723 }

Cache object: 3e40459fe3e50cb454b90a5659ceed2b


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