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.21 2003/05/10 23:12:46 thorpej 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.21 2003/05/10 23:12:46 thorpej 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/stat.h>
   56 #include <sys/dkio.h>
   57 #include <sys/fcntl.h>
   58 #include <sys/event.h>
   59 
   60 #include <ufs/ufs/dinode.h>
   61 #include <ufs/ffs/fs.h>
   62 
   63 #include <machine/bus.h>
   64 
   65 #include <dev/qbus/ubavar.h>
   66 #include <dev/qbus/rlreg.h>
   67 #include <dev/qbus/rlvar.h>
   68 
   69 #include "ioconf.h"
   70 #include "locators.h"
   71 
   72 static  int rlcmatch(struct device *, struct cfdata *, void *);
   73 static  void rlcattach(struct device *, struct device *, void *);
   74 static  int rlcprint(void *, const char *);
   75 static  void rlcintr(void *);
   76 static  int rlmatch(struct device *, struct cfdata *, void *);
   77 static  void rlattach(struct device *, struct device *, void *);
   78 static  void rlcstart(struct rlc_softc *, struct buf *);
   79 static  void waitcrdy(struct rlc_softc *);
   80 static  void rlcreset(struct device *);
   81 
   82 CFATTACH_DECL(rlc, sizeof(struct rlc_softc),
   83     rlcmatch, rlcattach, NULL, NULL);
   84 
   85 CFATTACH_DECL(rl, sizeof(struct rl_softc),
   86     rlmatch, rlattach, NULL, NULL);
   87 
   88 dev_type_open(rlopen);
   89 dev_type_close(rlclose);
   90 dev_type_read(rlread);
   91 dev_type_write(rlwrite);
   92 dev_type_ioctl(rlioctl);
   93 dev_type_strategy(rlstrategy);
   94 dev_type_dump(rldump);
   95 dev_type_size(rlsize);
   96 
   97 const struct bdevsw rl_bdevsw = {
   98         rlopen, rlclose, rlstrategy, rlioctl, rldump, rlsize, D_DISK
   99 };
  100 
  101 const struct cdevsw rl_cdevsw = {
  102         rlopen, rlclose, rlread, rlwrite, rlioctl,
  103         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
  104 };
  105 
  106 #define MAXRLXFER (RL_BPS * RL_SPT)
  107 
  108 #define RL_WREG(reg, val) \
  109         bus_space_write_2(sc->sc_iot, sc->sc_ioh, (reg), (val))
  110 #define RL_RREG(reg) \
  111         bus_space_read_2(sc->sc_iot, sc->sc_ioh, (reg))
  112 
  113 static char *rlstates[] = {
  114         "drive not loaded",
  115         "drive spinning up",
  116         "drive brushes out",
  117         "drive loading heads",
  118         "drive seeking",
  119         "drive ready",
  120         "drive unloading heads",
  121         "drive spun down",
  122 };
  123 
  124 static char *
  125 rlstate(struct rlc_softc *sc, int unit)
  126 {
  127         int i = 0;
  128 
  129         do {
  130                 RL_WREG(RL_DA, RLDA_GS);
  131                 RL_WREG(RL_CS, RLCS_GS|(unit << RLCS_USHFT));
  132                 waitcrdy(sc);
  133         } while (((RL_RREG(RL_CS) & RLCS_ERR) != 0) && i++ < 10);
  134         if (i == 10)
  135                 return NULL;
  136         i = RL_RREG(RL_MP) & RLMP_STATUS;
  137         return rlstates[i];
  138 }
  139 
  140 void
  141 waitcrdy(struct rlc_softc *sc)
  142 {
  143         int i;
  144 
  145         for (i = 0; i < 1000; i++) {
  146                 DELAY(10000);
  147                 if (RL_RREG(RL_CS) & RLCS_CRDY)
  148                         return;
  149         }
  150         printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?panic? */
  151 }
  152 
  153 int
  154 rlcprint(void *aux, const char *name)
  155 {
  156         struct rlc_attach_args *ra = aux;
  157 
  158         if (name)
  159                 aprint_normal("RL0%d at %s",
  160                     ra->type & RLMP_DT ? '2' : '1', name);
  161         aprint_normal(" drive %d", ra->hwid);
  162         return UNCONF;
  163 }
  164 
  165 /*
  166  * Force the controller to interrupt.
  167  */
  168 int
  169 rlcmatch(struct device *parent, struct cfdata *cf, void *aux)
  170 {
  171         struct uba_attach_args *ua = aux;
  172         struct rlc_softc ssc, *sc = &ssc;
  173         int i;
  174 
  175         sc->sc_iot = ua->ua_iot;
  176         sc->sc_ioh = ua->ua_ioh;
  177         /* Force interrupt by issuing a "Get Status" command */
  178         RL_WREG(RL_DA, RLDA_GS);
  179         RL_WREG(RL_CS, RLCS_GS|RLCS_IE);
  180 
  181         for (i = 0; i < 100; i++) {
  182                 DELAY(100000);
  183                 if (RL_RREG(RL_CS) & RLCS_CRDY)
  184                         return 1;
  185         }
  186         return 0;
  187 }
  188 
  189 void
  190 rlcattach(struct device *parent, struct device *self, void *aux)
  191 {
  192         struct rlc_softc *sc = (struct rlc_softc *)self;
  193         struct uba_attach_args *ua = aux;
  194         struct rlc_attach_args ra;
  195         int i, error;
  196 
  197         sc->sc_iot = ua->ua_iot;
  198         sc->sc_ioh = ua->ua_ioh;
  199         sc->sc_dmat = ua->ua_dmat;
  200         uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
  201                 rlcintr, sc, &sc->sc_intrcnt);
  202         evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  203                 sc->sc_dev.dv_xname, "intr");
  204         uba_reset_establish(rlcreset, self);
  205 
  206         printf("\n");
  207 
  208         /*
  209          * The RL11 can only have one transfer going at a time, 
  210          * and max transfer size is one track, so only one dmamap
  211          * is needed.
  212          */
  213         error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
  214             BUS_DMA_ALLOCNOW, &sc->sc_dmam);
  215         if (error) {
  216                 printf(": Failed to allocate DMA map, error %d\n", error);
  217                 return;
  218         }
  219         bufq_alloc(&sc->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
  220         for (i = 0; i < RL_MAXDPC; i++) {
  221                 waitcrdy(sc);
  222                 RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
  223                 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
  224                 waitcrdy(sc);
  225                 ra.type = RL_RREG(RL_MP);
  226                 ra.hwid = i;
  227                 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
  228                         config_found(&sc->sc_dev, &ra, rlcprint);
  229         }
  230 }
  231 
  232 int
  233 rlmatch(struct device *parent, struct cfdata *cf, void *aux)
  234 {
  235         struct rlc_attach_args *ra = aux;
  236 
  237         if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
  238             cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
  239                 return 0;
  240         return 1;
  241 }
  242 
  243 void
  244 rlattach(struct device *parent, struct device *self, void *aux)
  245 {
  246         struct rl_softc *rc = (struct rl_softc *)self;
  247         struct rlc_attach_args *ra = aux;
  248         struct disklabel *dl;
  249 
  250         rc->rc_hwid = ra->hwid;
  251         rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
  252         disk_attach(&rc->rc_disk);
  253         dl = rc->rc_disk.dk_label;
  254         dl->d_npartitions = 3;
  255         strcpy(dl->d_typename, "RL01");
  256         if (ra->type & RLMP_DT)
  257                 dl->d_typename[3] = '2';
  258         dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
  259         dl->d_nsectors = RL_SPT/2;
  260         dl->d_ntracks = RL_SPD;
  261         dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
  262         dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
  263         dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
  264         dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
  265             dl->d_secperunit;
  266         dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
  267         dl->d_interleave = dl->d_headswitch = 1;
  268         dl->d_bbsize = BBSIZE;
  269         dl->d_sbsize = SBLOCKSIZE;
  270         dl->d_rpm = 2400;
  271         dl->d_type = DTYPE_DEC;
  272         printf(": %s, %s\n", dl->d_typename,
  273             rlstate((struct rlc_softc *)parent, ra->hwid));
  274 }
  275 
  276 int
  277 rlopen(dev_t dev, int flag, int fmt, struct proc *p)
  278 {
  279         int part, unit, mask;
  280         struct disklabel *dl;
  281         struct rlc_softc *sc;
  282         struct rl_softc *rc;
  283         const char *msg;
  284 
  285         /*
  286          * Make sure this is a reasonable open request.
  287          */
  288         unit = DISKUNIT(dev);
  289         if (unit >= rl_cd.cd_ndevs)
  290                 return ENXIO;
  291         rc = rl_cd.cd_devs[unit];
  292         if (rc == 0)
  293                 return ENXIO;
  294 
  295         sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
  296         /* Check that the disk actually is useable */
  297         msg = rlstate(sc, rc->rc_hwid);
  298         if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
  299             msg == rlstates[RLMP_SPUNDOWN])
  300                 return ENXIO;
  301         /*
  302          * If this is the first open; read in where on the disk we are.
  303          */
  304         dl = rc->rc_disk.dk_label;
  305         if (rc->rc_state == DK_CLOSED) {
  306                 u_int16_t mp;
  307                 int maj;
  308                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  309                 waitcrdy(sc);
  310                 mp = RL_RREG(RL_MP);
  311                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  312                 rc->rc_cyl = (mp >> 7) & 0777;
  313                 rc->rc_state = DK_OPEN;
  314                 /* Get disk label */
  315                 printf("%s: ", rc->rc_dev.dv_xname);
  316                 maj = cdevsw_lookup_major(&rl_cdevsw);
  317                 if ((msg = readdisklabel(MAKEDISKDEV(maj,
  318                     rc->rc_dev.dv_unit, RAW_PART), rlstrategy, dl, NULL)))
  319                         printf("%s: ", msg);
  320                 printf("size %d sectors\n", dl->d_secperunit);
  321         }
  322         part = DISKPART(dev);
  323         if (part >= dl->d_npartitions)
  324                 return ENXIO;
  325 
  326         mask = 1 << part;
  327         switch (fmt) {
  328         case S_IFCHR:
  329                 rc->rc_disk.dk_copenmask |= mask;
  330                 break;
  331         case S_IFBLK:
  332                 rc->rc_disk.dk_bopenmask |= mask;
  333                 break;
  334         }
  335         rc->rc_disk.dk_openmask |= mask;
  336         return 0;
  337 }
  338 
  339 int
  340 rlclose(dev_t dev, int flag, int fmt, struct proc *p)
  341 {
  342         int unit = DISKUNIT(dev);
  343         struct rl_softc *rc = rl_cd.cd_devs[unit];
  344         int mask = (1 << DISKPART(dev));
  345 
  346         switch (fmt) {
  347         case S_IFCHR:
  348                 rc->rc_disk.dk_copenmask &= ~mask;
  349                 break;
  350         case S_IFBLK:
  351                 rc->rc_disk.dk_bopenmask &= ~mask;
  352                 break;
  353         }
  354         rc->rc_disk.dk_openmask =
  355             rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
  356 
  357         if (rc->rc_disk.dk_openmask == 0)
  358                 rc->rc_state = DK_CLOSED; /* May change pack */
  359         return 0;
  360 }
  361 
  362 void
  363 rlstrategy(struct buf *bp)
  364 {
  365         struct disklabel *lp;
  366         struct rlc_softc *sc;
  367         struct rl_softc *rc;
  368         int unit, s, err;
  369         /*
  370          * Make sure this is a reasonable drive to use.
  371          */
  372         unit = DISKUNIT(bp->b_dev);
  373         if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
  374                 bp->b_error = ENXIO;
  375                 bp->b_flags |= B_ERROR;
  376                 goto done;
  377         }
  378         if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
  379                 panic("rlstrategy: state impossible");
  380 
  381         lp = rc->rc_disk.dk_label;
  382         if ((err = bounds_check_with_label(&rc->rc_disk, bp, 1)) <= 0)
  383                 goto done;
  384 
  385         if (bp->b_bcount == 0)
  386                 goto done;
  387 
  388         bp->b_rawblkno =
  389             bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
  390         bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
  391         sc = (struct rlc_softc *)rc->rc_dev.dv_parent;
  392 
  393         s = splbio();
  394         BUFQ_PUT(&sc->sc_q, bp);
  395         rlcstart(sc, 0);
  396         splx(s);
  397         return;
  398 
  399 done:   biodone(bp);
  400 }
  401 
  402 int
  403 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  404 {
  405         struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
  406         struct disklabel *lp = rc->rc_disk.dk_label;
  407         int err = 0;
  408 #ifdef __HAVE_OLD_DISKLABEL
  409         struct disklabel newlabel;
  410 #endif
  411 
  412         switch (cmd) {
  413         case DIOCGDINFO:
  414                 bcopy(lp, addr, sizeof (struct disklabel));
  415                 break;
  416 
  417 #ifdef __HAVE_OLD_DISKLABEL
  418         case ODIOCGDINFO:
  419                 newlabel = *lp;
  420                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  421                         return ENOTTY;
  422                 bcopy(&newlabel, addr, sizeof (struct olddisklabel));
  423                 break;
  424 #endif
  425 
  426         case DIOCGPART:
  427                 ((struct partinfo *)addr)->disklab = lp;
  428                 ((struct partinfo *)addr)->part =
  429                     &lp->d_partitions[DISKPART(dev)];
  430                 break;
  431 
  432         case DIOCSDINFO:
  433         case DIOCWDINFO:
  434 #ifdef __HAVE_OLD_DISKLABEL
  435         case ODIOCWDINFO:
  436         case ODIOCSDINFO:
  437 #endif
  438         {
  439                 struct disklabel *tp;
  440 
  441 #ifdef __HAVE_OLD_DISKLABEL
  442                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
  443                         memset(&newlabel, 0, sizeof newlabel);
  444                         memcpy(&newlabel, addr, sizeof (struct olddisklabel));
  445                         tp = &newlabel;
  446                 } else
  447 #endif
  448                 tp = (struct disklabel *)addr;
  449 
  450                 if ((flag & FWRITE) == 0)
  451                         err = EBADF;
  452                 else
  453                         err = ((
  454 #ifdef __HAVE_OLD_DISKLABEL
  455                                cmd == ODIOCSDINFO ||
  456 #endif
  457                                cmd == DIOCSDINFO) ?
  458                             setdisklabel(lp, tp, 0, 0) :
  459                             writedisklabel(dev, rlstrategy, lp, 0));
  460                 break;
  461         }
  462 
  463         case DIOCWLABEL:
  464                 if ((flag & FWRITE) == 0)
  465                         err = EBADF;
  466                 break;
  467 
  468         default:
  469                 err = ENOTTY;
  470         }
  471         return err;
  472 }
  473 
  474 int
  475 rlsize(dev_t dev)
  476 {
  477         struct disklabel *dl;
  478         struct rl_softc *rc;
  479         int size, unit = DISKUNIT(dev);
  480 
  481         if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
  482                 return -1;
  483         dl = rc->rc_disk.dk_label;
  484         size = dl->d_partitions[DISKPART(dev)].p_size *
  485             (dl->d_secsize / DEV_BSIZE);
  486         return size;
  487 }
  488 
  489 int
  490 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  491 {
  492         /* Not likely... */
  493         return 0;
  494 }
  495 
  496 int
  497 rlread(dev_t dev, struct uio *uio, int ioflag)
  498 {
  499         return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
  500 }
  501 
  502 int
  503 rlwrite(dev_t dev, struct uio *uio, int ioflag)
  504 {
  505         return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
  506 }
  507 
  508 static char *rlerr[] = {
  509         "no",
  510         "operation incomplete",
  511         "read data CRC",
  512         "header CRC",
  513         "data late",
  514         "header not found",
  515         "",
  516         "",
  517         "non-existent memory",
  518         "memory parity error",
  519         "",
  520         "",
  521         "",
  522         "",
  523         "",
  524         "",
  525 };
  526 
  527 void
  528 rlcintr(void *arg)
  529 {
  530         struct rlc_softc *sc = arg;
  531         struct buf *bp;
  532         u_int16_t cs;
  533 
  534         bp = sc->sc_active;
  535         if (bp == 0) {
  536                 printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
  537                 return;
  538         }
  539         bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
  540         sc->sc_active = 0;
  541         cs = RL_RREG(RL_CS);
  542         if (cs & RLCS_ERR) {
  543                 int error = (cs & RLCS_ERRMSK) >> 10;
  544 
  545                 printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
  546                 bp->b_flags |= B_ERROR;
  547                 bp->b_error = EIO;
  548                 bp->b_resid = bp->b_bcount;
  549                 sc->sc_bytecnt = 0;
  550         }
  551         if (sc->sc_bytecnt == 0) /* Finished transfer */
  552                 biodone(bp);
  553         rlcstart(sc, sc->sc_bytecnt ? bp : 0);
  554 }
  555 
  556 /*
  557  * Start routine. First position the disk to the given position, 
  558  * then start reading/writing. An optimization would be to be able
  559  * to handle overlapping seeks between disks.
  560  */
  561 void
  562 rlcstart(struct rlc_softc *sc, struct buf *ob)
  563 {
  564         struct disklabel *lp;
  565         struct rl_softc *rc;
  566         struct buf *bp;
  567         int bn, cn, sn, tn, blks, err;
  568 
  569         if (sc->sc_active)
  570                 return; /* Already doing something */
  571 
  572         if (ob == 0) {
  573                 bp = BUFQ_GET(&sc->sc_q);
  574                 if (bp == NULL)
  575                         return; /* Nothing to do */
  576                 sc->sc_bufaddr = bp->b_data;
  577                 sc->sc_diskblk = bp->b_rawblkno;
  578                 sc->sc_bytecnt = bp->b_bcount;
  579                 bp->b_resid = 0;
  580         } else
  581                 bp = ob;
  582         sc->sc_active = bp;
  583 
  584         rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
  585         bn = sc->sc_diskblk;
  586         lp = rc->rc_disk.dk_label;
  587         if (bn) {
  588                 cn = bn / lp->d_secpercyl;
  589                 sn = bn % lp->d_secpercyl;
  590                 tn = sn / lp->d_nsectors;
  591                 sn = sn % lp->d_nsectors;
  592         } else
  593                 cn = sn = tn = 0;
  594 
  595         /*
  596          * Check if we have to position disk first.
  597          */
  598         if (rc->rc_cyl != cn || rc->rc_head != tn) {
  599                 u_int16_t da = RLDA_SEEK;
  600                 if (cn > rc->rc_cyl)
  601                         da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
  602                 else
  603                         da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
  604                 if (tn)
  605                         da |= RLDA_HSSEEK;
  606                 waitcrdy(sc);
  607                 RL_WREG(RL_DA, da);
  608                 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
  609                 waitcrdy(sc);
  610                 rc->rc_cyl = cn;
  611                 rc->rc_head = tn;
  612         }
  613         RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
  614         blks = sc->sc_bytecnt/DEV_BSIZE;
  615 
  616         if (sn + blks > RL_SPT/2)
  617                 blks = RL_SPT/2 - sn;
  618         RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
  619         err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
  620             (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
  621             BUS_DMA_NOWAIT);
  622         if (err)
  623                 panic("%s: bus_dmamap_load failed: %d",
  624                     sc->sc_dev.dv_xname, err);
  625         RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
  626 
  627         /* Count up vars */
  628         sc->sc_bufaddr += (blks*DEV_BSIZE);
  629         sc->sc_diskblk += blks;
  630         sc->sc_bytecnt -= (blks*DEV_BSIZE);
  631 
  632         if (bp->b_flags & B_READ)
  633                 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
  634         else
  635                 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
  636 }
  637 
  638 /*
  639  * Called once per controller when an ubareset occurs.
  640  * Retracts all disks and restarts active transfers.
  641  */
  642 void
  643 rlcreset(struct device *dev)
  644 {
  645         struct rlc_softc *sc = (struct rlc_softc *)dev;
  646         struct rl_softc *rc;
  647         int i;
  648         u_int16_t mp;
  649 
  650         for (i = 0; i < rl_cd.cd_ndevs; i++) {
  651                 if ((rc = rl_cd.cd_devs[i]) == NULL)
  652                         continue;
  653                 if (rc->rc_state != DK_OPEN)
  654                         continue;
  655 
  656                 printf(" %s", rc->rc_dev.dv_xname);
  657                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  658                 waitcrdy(sc);
  659                 mp = RL_RREG(RL_MP);
  660                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  661                 rc->rc_cyl = (mp >> 7) & 0777;
  662         }
  663         if (sc->sc_active == 0)
  664                 return;
  665 
  666         BUFQ_PUT(&sc->sc_q, sc->sc_active);
  667         sc->sc_active = 0;
  668         rlcstart(sc, 0);
  669 }

Cache object: 09a4f1490a327ac9afc0f3736215fa0f


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