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.30 2006/03/29 18:17:36 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.30 2006/03/29 18:17:36 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/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 <machine/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(struct device *, struct cfdata *, void *);
   74 static  void rlcattach(struct device *, struct device *, void *);
   75 static  int rlcprint(void *, const char *);
   76 static  void rlcintr(void *);
   77 static  int rlmatch(struct device *, struct cfdata *, void *);
   78 static  void rlattach(struct device *, struct device *, void *);
   79 static  void rlcstart(struct rlc_softc *, struct buf *);
   80 static  void waitcrdy(struct rlc_softc *);
   81 static  void rlcreset(struct device *);
   82 
   83 CFATTACH_DECL(rlc, sizeof(struct rlc_softc),
   84     rlcmatch, rlcattach, NULL, NULL);
   85 
   86 CFATTACH_DECL(rl, sizeof(struct rl_softc),
   87     rlmatch, rlattach, NULL, NULL);
   88 
   89 dev_type_open(rlopen);
   90 dev_type_close(rlclose);
   91 dev_type_read(rlread);
   92 dev_type_write(rlwrite);
   93 dev_type_ioctl(rlioctl);
   94 dev_type_strategy(rlstrategy);
   95 dev_type_dump(rldump);
   96 dev_type_size(rlsize);
   97 
   98 const struct bdevsw rl_bdevsw = {
   99         rlopen, rlclose, rlstrategy, rlioctl, rldump, rlsize, 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 *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 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         printf("%s: never got ready\n", sc->sc_dev.dv_xname); /* ?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(struct device *parent, struct cfdata *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(struct device *parent, struct device *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_iot = ua->ua_iot;
  203         sc->sc_ioh = ua->ua_ioh;
  204         sc->sc_dmat = ua->ua_dmat;
  205         uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
  206                 rlcintr, sc, &sc->sc_intrcnt);
  207         evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  208                 sc->sc_dev.dv_xname, "intr");
  209         uba_reset_establish(rlcreset, self);
  210 
  211         printf("\n");
  212 
  213         /*
  214          * The RL11 can only have one transfer going at a time,
  215          * and max transfer size is one track, so only one dmamap
  216          * is needed.
  217          */
  218         error = bus_dmamap_create(sc->sc_dmat, MAXRLXFER, 1, MAXRLXFER, 0,
  219             BUS_DMA_ALLOCNOW, &sc->sc_dmam);
  220         if (error) {
  221                 printf(": Failed to allocate DMA map, error %d\n", error);
  222                 return;
  223         }
  224         bufq_alloc(&sc->sc_q, "disksort", BUFQ_SORT_CYLINDER);
  225         for (i = 0; i < RL_MAXDPC; i++) {
  226                 waitcrdy(sc);
  227                 RL_WREG(RL_DA, RLDA_GS|RLDA_RST);
  228                 RL_WREG(RL_CS, RLCS_GS|(i << RLCS_USHFT));
  229                 waitcrdy(sc);
  230                 ra.type = RL_RREG(RL_MP);
  231                 ra.hwid = i;
  232                 if ((RL_RREG(RL_CS) & RLCS_ERR) == 0)
  233                         config_found(&sc->sc_dev, &ra, rlcprint);
  234         }
  235 }
  236 
  237 int
  238 rlmatch(struct device *parent, struct cfdata *cf, void *aux)
  239 {
  240         struct rlc_attach_args *ra = aux;
  241 
  242         if (cf->cf_loc[RLCCF_DRIVE] != RLCCF_DRIVE_DEFAULT &&
  243             cf->cf_loc[RLCCF_DRIVE] != ra->hwid)
  244                 return 0;
  245         return 1;
  246 }
  247 
  248 void
  249 rlattach(struct device *parent, struct device *self, void *aux)
  250 {
  251         struct rl_softc *rc = device_private(self);
  252         struct rlc_attach_args *ra = aux;
  253         struct disklabel *dl;
  254 
  255         rc->rc_hwid = ra->hwid;
  256         rc->rc_disk.dk_name = rc->rc_dev.dv_xname;
  257         rc->rc_disk.dk_driver = &rldkdriver;
  258         disk_attach(&rc->rc_disk);
  259         dl = rc->rc_disk.dk_label;
  260         dl->d_npartitions = 3;
  261         strcpy(dl->d_typename, "RL01");
  262         if (ra->type & RLMP_DT)
  263                 dl->d_typename[3] = '2';
  264         dl->d_secsize = DEV_BSIZE; /* XXX - wrong, but OK for now */
  265         dl->d_nsectors = RL_SPT/2;
  266         dl->d_ntracks = RL_SPD;
  267         dl->d_ncylinders = ra->type & RLMP_DT ? RL_TPS02 : RL_TPS01;
  268         dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
  269         dl->d_secperunit = dl->d_ncylinders * dl->d_secpercyl;
  270         dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
  271             dl->d_secperunit;
  272         dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
  273         dl->d_interleave = dl->d_headswitch = 1;
  274         dl->d_bbsize = BBSIZE;
  275         dl->d_sbsize = SBLOCKSIZE;
  276         dl->d_rpm = 2400;
  277         dl->d_type = DTYPE_DEC;
  278         printf(": %s, %s\n", dl->d_typename,
  279             rlstate((struct rlc_softc *)parent, ra->hwid));
  280 
  281         /*
  282          * XXX We should try to discovery wedges here, but
  283          * XXX that would mean loading up the pack and being
  284          * XXX able to do I/O.  Should use config_defer() here.
  285          */
  286 }
  287 
  288 int
  289 rlopen(dev_t dev, int flag, int fmt, struct lwp *l)
  290 {
  291         int error, part, unit, mask;
  292         struct disklabel *dl;
  293         struct rlc_softc *sc;
  294         struct rl_softc *rc;
  295         const char *msg;
  296 
  297         /*
  298          * Make sure this is a reasonable open request.
  299          */
  300         unit = DISKUNIT(dev);
  301         if (unit >= rl_cd.cd_ndevs)
  302                 return ENXIO;
  303         rc = rl_cd.cd_devs[unit];
  304         if (rc == 0)
  305                 return ENXIO;
  306 
  307         part = DISKPART(dev);
  308 
  309         if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
  310                              NULL)) != 0)
  311                 return (error);
  312 
  313         /*
  314          * If there are wedges, and this is not RAW_PART, then we
  315          * need to fail.
  316          */
  317         if (rc->rc_disk.dk_nwedges != 0 && part != RAW_PART) {
  318                 error = EBUSY;
  319                 goto bad1;
  320         }
  321 
  322         sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
  323         /* Check that the disk actually is useable */
  324         msg = rlstate(sc, rc->rc_hwid);
  325         if (msg == NULL || msg == rlstates[RLMP_UNLOAD] ||
  326             msg == rlstates[RLMP_SPUNDOWN]) {
  327                 error = ENXIO;
  328                 goto bad1;
  329         }
  330         /*
  331          * If this is the first open; read in where on the disk we are.
  332          */
  333         dl = rc->rc_disk.dk_label;
  334         if (rc->rc_state == DK_CLOSED) {
  335                 u_int16_t mp;
  336                 int maj;
  337                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  338                 waitcrdy(sc);
  339                 mp = RL_RREG(RL_MP);
  340                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  341                 rc->rc_cyl = (mp >> 7) & 0777;
  342                 rc->rc_state = DK_OPEN;
  343                 /* Get disk label */
  344                 printf("%s: ", rc->rc_dev.dv_xname);
  345                 maj = cdevsw_lookup_major(&rl_cdevsw);
  346                 if ((msg = readdisklabel(MAKEDISKDEV(maj,
  347                     device_unit(&rc->rc_dev), RAW_PART), rlstrategy, dl, NULL)))
  348                         printf("%s: ", msg);
  349                 printf("size %d sectors\n", dl->d_secperunit);
  350         }
  351         if (part >= dl->d_npartitions) {
  352                 error = ENXIO;
  353                 goto bad1;
  354         }
  355 
  356         mask = 1 << part;
  357         switch (fmt) {
  358         case S_IFCHR:
  359                 rc->rc_disk.dk_copenmask |= mask;
  360                 break;
  361         case S_IFBLK:
  362                 rc->rc_disk.dk_bopenmask |= mask;
  363                 break;
  364         }
  365         rc->rc_disk.dk_openmask |= mask;
  366         (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
  367         return 0;
  368 
  369  bad1:
  370         (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
  371         return (error);
  372 }
  373 
  374 int
  375 rlclose(dev_t dev, int flag, int fmt, struct lwp *l)
  376 {
  377         int error, unit = DISKUNIT(dev);
  378         struct rl_softc *rc = rl_cd.cd_devs[unit];
  379         int mask = (1 << DISKPART(dev));
  380 
  381         if ((error = lockmgr(&rc->rc_disk.dk_openlock, LK_EXCLUSIVE,
  382                              NULL)) != 0)
  383                 return (error);
  384 
  385         switch (fmt) {
  386         case S_IFCHR:
  387                 rc->rc_disk.dk_copenmask &= ~mask;
  388                 break;
  389         case S_IFBLK:
  390                 rc->rc_disk.dk_bopenmask &= ~mask;
  391                 break;
  392         }
  393         rc->rc_disk.dk_openmask =
  394             rc->rc_disk.dk_copenmask | rc->rc_disk.dk_bopenmask;
  395 
  396         if (rc->rc_disk.dk_openmask == 0)
  397                 rc->rc_state = DK_CLOSED; /* May change pack */
  398         (void) lockmgr(&rc->rc_disk.dk_openlock, LK_RELEASE, NULL);
  399         return 0;
  400 }
  401 
  402 void
  403 rlstrategy(struct buf *bp)
  404 {
  405         struct disklabel *lp;
  406         struct rlc_softc *sc;
  407         struct rl_softc *rc;
  408         int unit, s, err;
  409         /*
  410          * Make sure this is a reasonable drive to use.
  411          */
  412         unit = DISKUNIT(bp->b_dev);
  413         if (unit > rl_cd.cd_ndevs || (rc = rl_cd.cd_devs[unit]) == NULL) {
  414                 bp->b_error = ENXIO;
  415                 bp->b_flags |= B_ERROR;
  416                 goto done;
  417         }
  418         if (rc->rc_state != DK_OPEN) /* How did we end up here at all? */
  419                 panic("rlstrategy: state impossible");
  420 
  421         lp = rc->rc_disk.dk_label;
  422         if ((err = bounds_check_with_label(&rc->rc_disk, bp, 1)) <= 0)
  423                 goto done;
  424 
  425         if (bp->b_bcount == 0)
  426                 goto done;
  427 
  428         bp->b_rawblkno =
  429             bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
  430         bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
  431         sc = (struct rlc_softc *)device_parent(&rc->rc_dev);
  432 
  433         s = splbio();
  434         BUFQ_PUT(sc->sc_q, bp);
  435         rlcstart(sc, 0);
  436         splx(s);
  437         return;
  438 
  439 done:   biodone(bp);
  440 }
  441 
  442 int
  443 rlioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l)
  444 {
  445         struct rl_softc *rc = rl_cd.cd_devs[DISKUNIT(dev)];
  446         struct disklabel *lp = rc->rc_disk.dk_label;
  447         int err = 0;
  448 #ifdef __HAVE_OLD_DISKLABEL
  449         struct disklabel newlabel;
  450 #endif
  451 
  452         switch (cmd) {
  453         case DIOCGDINFO:
  454                 bcopy(lp, addr, sizeof (struct disklabel));
  455                 break;
  456 
  457 #ifdef __HAVE_OLD_DISKLABEL
  458         case ODIOCGDINFO:
  459                 newlabel = *lp;
  460                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  461                         return ENOTTY;
  462                 bcopy(&newlabel, addr, sizeof (struct olddisklabel));
  463                 break;
  464 #endif
  465 
  466         case DIOCGPART:
  467                 ((struct partinfo *)addr)->disklab = lp;
  468                 ((struct partinfo *)addr)->part =
  469                     &lp->d_partitions[DISKPART(dev)];
  470                 break;
  471 
  472         case DIOCSDINFO:
  473         case DIOCWDINFO:
  474 #ifdef __HAVE_OLD_DISKLABEL
  475         case ODIOCWDINFO:
  476         case ODIOCSDINFO:
  477 #endif
  478         {
  479                 struct disklabel *tp;
  480 
  481 #ifdef __HAVE_OLD_DISKLABEL
  482                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
  483                         memset(&newlabel, 0, sizeof newlabel);
  484                         memcpy(&newlabel, addr, sizeof (struct olddisklabel));
  485                         tp = &newlabel;
  486                 } else
  487 #endif
  488                 tp = (struct disklabel *)addr;
  489 
  490                 if ((flag & FWRITE) == 0)
  491                         err = EBADF;
  492                 else {
  493                         if ((err = lockmgr(&rc->rc_disk.dk_openlock,
  494                                            LK_EXCLUSIVE, NULL)) != 0)
  495                                 break;
  496                         err = ((
  497 #ifdef __HAVE_OLD_DISKLABEL
  498                                cmd == ODIOCSDINFO ||
  499 #endif
  500                                cmd == DIOCSDINFO) ?
  501                             setdisklabel(lp, tp, 0, 0) :
  502                             writedisklabel(dev, rlstrategy, lp, 0));
  503                         (void) lockmgr(&rc->rc_disk.dk_openlock,
  504                                        LK_RELEASE, NULL);
  505                 }
  506                 break;
  507         }
  508 
  509         case DIOCWLABEL:
  510                 if ((flag & FWRITE) == 0)
  511                         err = EBADF;
  512                 break;
  513 
  514         case DIOCAWEDGE:
  515             {
  516                 struct dkwedge_info *dkw = (void *) addr;
  517 
  518                 if ((flag & FWRITE) == 0)
  519                         return (EBADF);
  520 
  521                 /* If the ioctl happens here, the parent is us. */
  522                 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
  523                 return (dkwedge_add(dkw));
  524             }
  525 
  526         case DIOCDWEDGE:
  527             {
  528                 struct dkwedge_info *dkw = (void *) addr;
  529 
  530                 if ((flag & FWRITE) == 0)
  531                         return (EBADF);
  532 
  533                 /* If the ioctl happens here, the parent is us. */
  534                 strcpy(dkw->dkw_parent, rc->rc_dev.dv_xname);
  535                 return (dkwedge_del(dkw));
  536             }
  537 
  538         case DIOCLWEDGES:
  539             {
  540                 struct dkwedge_list *dkwl = (void *) addr;
  541 
  542                 return (dkwedge_list(&rc->rc_disk, dkwl, l));
  543             }
  544 
  545         default:
  546                 err = ENOTTY;
  547         }
  548         return err;
  549 }
  550 
  551 int
  552 rlsize(dev_t dev)
  553 {
  554         struct disklabel *dl;
  555         struct rl_softc *rc;
  556         int size, unit = DISKUNIT(dev);
  557 
  558         if ((unit >= rl_cd.cd_ndevs) || ((rc = rl_cd.cd_devs[unit]) == 0))
  559                 return -1;
  560         dl = rc->rc_disk.dk_label;
  561         size = dl->d_partitions[DISKPART(dev)].p_size *
  562             (dl->d_secsize / DEV_BSIZE);
  563         return size;
  564 }
  565 
  566 int
  567 rldump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  568 {
  569         /* Not likely... */
  570         return 0;
  571 }
  572 
  573 int
  574 rlread(dev_t dev, struct uio *uio, int ioflag)
  575 {
  576         return (physio(rlstrategy, NULL, dev, B_READ, minphys, uio));
  577 }
  578 
  579 int
  580 rlwrite(dev_t dev, struct uio *uio, int ioflag)
  581 {
  582         return (physio(rlstrategy, NULL, dev, B_WRITE, minphys, uio));
  583 }
  584 
  585 static const char *rlerr[] = {
  586         "no",
  587         "operation incomplete",
  588         "read data CRC",
  589         "header CRC",
  590         "data late",
  591         "header not found",
  592         "",
  593         "",
  594         "non-existent memory",
  595         "memory parity error",
  596         "",
  597         "",
  598         "",
  599         "",
  600         "",
  601         "",
  602 };
  603 
  604 void
  605 rlcintr(void *arg)
  606 {
  607         struct rlc_softc *sc = arg;
  608         struct buf *bp;
  609         u_int16_t cs;
  610 
  611         bp = sc->sc_active;
  612         if (bp == 0) {
  613                 printf("%s: strange interrupt\n", sc->sc_dev.dv_xname);
  614                 return;
  615         }
  616         bus_dmamap_unload(sc->sc_dmat, sc->sc_dmam);
  617         sc->sc_active = 0;
  618         cs = RL_RREG(RL_CS);
  619         if (cs & RLCS_ERR) {
  620                 int error = (cs & RLCS_ERRMSK) >> 10;
  621 
  622                 printf("%s: %s\n", sc->sc_dev.dv_xname, rlerr[error]);
  623                 bp->b_flags |= B_ERROR;
  624                 bp->b_error = EIO;
  625                 bp->b_resid = bp->b_bcount;
  626                 sc->sc_bytecnt = 0;
  627         }
  628         if (sc->sc_bytecnt == 0) /* Finished transfer */
  629                 biodone(bp);
  630         rlcstart(sc, sc->sc_bytecnt ? bp : 0);
  631 }
  632 
  633 /*
  634  * Start routine. First position the disk to the given position,
  635  * then start reading/writing. An optimization would be to be able
  636  * to handle overlapping seeks between disks.
  637  */
  638 void
  639 rlcstart(struct rlc_softc *sc, struct buf *ob)
  640 {
  641         struct disklabel *lp;
  642         struct rl_softc *rc;
  643         struct buf *bp;
  644         int bn, cn, sn, tn, blks, err;
  645 
  646         if (sc->sc_active)
  647                 return; /* Already doing something */
  648 
  649         if (ob == 0) {
  650                 bp = BUFQ_GET(sc->sc_q);
  651                 if (bp == NULL)
  652                         return; /* Nothing to do */
  653                 sc->sc_bufaddr = bp->b_data;
  654                 sc->sc_diskblk = bp->b_rawblkno;
  655                 sc->sc_bytecnt = bp->b_bcount;
  656                 bp->b_resid = 0;
  657         } else
  658                 bp = ob;
  659         sc->sc_active = bp;
  660 
  661         rc = rl_cd.cd_devs[DISKUNIT(bp->b_dev)];
  662         bn = sc->sc_diskblk;
  663         lp = rc->rc_disk.dk_label;
  664         if (bn) {
  665                 cn = bn / lp->d_secpercyl;
  666                 sn = bn % lp->d_secpercyl;
  667                 tn = sn / lp->d_nsectors;
  668                 sn = sn % lp->d_nsectors;
  669         } else
  670                 cn = sn = tn = 0;
  671 
  672         /*
  673          * Check if we have to position disk first.
  674          */
  675         if (rc->rc_cyl != cn || rc->rc_head != tn) {
  676                 u_int16_t da = RLDA_SEEK;
  677                 if (cn > rc->rc_cyl)
  678                         da |= ((cn - rc->rc_cyl) << RLDA_CYLSHFT) | RLDA_DIR;
  679                 else
  680                         da |= ((rc->rc_cyl - cn) << RLDA_CYLSHFT);
  681                 if (tn)
  682                         da |= RLDA_HSSEEK;
  683                 waitcrdy(sc);
  684                 RL_WREG(RL_DA, da);
  685                 RL_WREG(RL_CS, RLCS_SEEK | (rc->rc_hwid << RLCS_USHFT));
  686                 waitcrdy(sc);
  687                 rc->rc_cyl = cn;
  688                 rc->rc_head = tn;
  689         }
  690         RL_WREG(RL_DA, (cn << RLDA_CYLSHFT) | (tn ? RLDA_HSRW : 0) | (sn << 1));
  691         blks = sc->sc_bytecnt/DEV_BSIZE;
  692 
  693         if (sn + blks > RL_SPT/2)
  694                 blks = RL_SPT/2 - sn;
  695         RL_WREG(RL_MP, -(blks*DEV_BSIZE)/2);
  696         err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmam, sc->sc_bufaddr,
  697             (blks*DEV_BSIZE), (bp->b_flags & B_PHYS ? bp->b_proc : 0),
  698             BUS_DMA_NOWAIT);
  699         if (err)
  700                 panic("%s: bus_dmamap_load failed: %d",
  701                     sc->sc_dev.dv_xname, err);
  702         RL_WREG(RL_BA, (sc->sc_dmam->dm_segs[0].ds_addr & 0xffff));
  703 
  704         /* Count up vars */
  705         sc->sc_bufaddr += (blks*DEV_BSIZE);
  706         sc->sc_diskblk += blks;
  707         sc->sc_bytecnt -= (blks*DEV_BSIZE);
  708 
  709         if (bp->b_flags & B_READ)
  710                 RL_WREG(RL_CS, RLCS_IE|RLCS_RD|(rc->rc_hwid << RLCS_USHFT));
  711         else
  712                 RL_WREG(RL_CS, RLCS_IE|RLCS_WD|(rc->rc_hwid << RLCS_USHFT));
  713 }
  714 
  715 /*
  716  * Called once per controller when an ubareset occurs.
  717  * Retracts all disks and restarts active transfers.
  718  */
  719 void
  720 rlcreset(struct device *dev)
  721 {
  722         struct rlc_softc *sc = (struct rlc_softc *)dev;
  723         struct rl_softc *rc;
  724         int i;
  725         u_int16_t mp;
  726 
  727         for (i = 0; i < rl_cd.cd_ndevs; i++) {
  728                 if ((rc = rl_cd.cd_devs[i]) == NULL)
  729                         continue;
  730                 if (rc->rc_state != DK_OPEN)
  731                         continue;
  732 
  733                 printf(" %s", rc->rc_dev.dv_xname);
  734                 RL_WREG(RL_CS, RLCS_RHDR|(rc->rc_hwid << RLCS_USHFT));
  735                 waitcrdy(sc);
  736                 mp = RL_RREG(RL_MP);
  737                 rc->rc_head = ((mp & RLMP_HS) == RLMP_HS);
  738                 rc->rc_cyl = (mp >> 7) & 0777;
  739         }
  740         if (sc->sc_active == 0)
  741                 return;
  742 
  743         BUFQ_PUT(sc->sc_q, sc->sc_active);
  744         sc->sc_active = 0;
  745         rlcstart(sc, 0);
  746 }

Cache object: 7356e7c912e6cb6d22fe1201ce2b7f7b


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