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

Cache object: e99dbdfcf5e8ccfc1e44da5ff1babe3c


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