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/ofw/ofdisk.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: ofdisk.c,v 1.27 2003/05/10 23:12:46 thorpej Exp $      */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
    5  * Copyright (C) 1995, 1996 TooLs GmbH.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by TooLs GmbH.
   19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: ofdisk.c,v 1.27 2003/05/10 23:12:46 thorpej Exp $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/buf.h>
   39 #include <sys/device.h>
   40 #include <sys/conf.h>
   41 #include <sys/disklabel.h>
   42 #include <sys/disk.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/ioctl.h>
   45 #include <sys/stat.h>
   46 #include <sys/systm.h>
   47 #include <sys/proc.h>
   48 #include <sys/conf.h>
   49 
   50 #include <dev/ofw/openfirm.h>
   51 
   52 struct ofdisk_softc {
   53         struct device sc_dev;
   54         int sc_phandle;
   55         int sc_unit;
   56         int sc_flags;
   57         struct disk sc_dk;
   58         int sc_ihandle;
   59         u_long max_transfer;
   60         char sc_name[16];
   61 };
   62 
   63 /* sc_flags */
   64 #define OFDF_ISFLOPPY   0x01            /* we are a floppy drive */
   65 
   66 static int ofdisk_match (struct device *, struct cfdata *, void *);
   67 static void ofdisk_attach (struct device *, struct device *, void *);
   68 
   69 CFATTACH_DECL(ofdisk, sizeof(struct ofdisk_softc),
   70     ofdisk_match, ofdisk_attach, NULL, NULL);
   71 
   72 extern struct cfdriver ofdisk_cd;
   73 
   74 dev_type_open(ofdisk_open);
   75 dev_type_close(ofdisk_close);
   76 dev_type_read(ofdisk_read);
   77 dev_type_write(ofdisk_write);
   78 dev_type_ioctl(ofdisk_ioctl);
   79 dev_type_strategy(ofdisk_strategy);
   80 dev_type_dump(ofdisk_dump);
   81 dev_type_size(ofdisk_size);
   82 
   83 const struct bdevsw ofdisk_bdevsw = {
   84         ofdisk_open, ofdisk_close, ofdisk_strategy, ofdisk_ioctl,
   85         ofdisk_dump, ofdisk_size, D_DISK
   86 };
   87 
   88 const struct cdevsw ofdisk_cdevsw = {
   89         ofdisk_open, ofdisk_close, ofdisk_read, ofdisk_write, ofdisk_ioctl,
   90         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
   91 };
   92 
   93 struct dkdriver ofdisk_dkdriver = { ofdisk_strategy };
   94 
   95 void ofdisk_getdefaultlabel (struct ofdisk_softc *, struct disklabel *);
   96 void ofdisk_getdisklabel (dev_t);
   97 
   98 static int
   99 ofdisk_match(struct device *parent, struct cfdata *match, void *aux)
  100 {
  101         struct ofbus_attach_args *oba = aux;
  102         char type[8];
  103         int l;
  104         
  105         if (strcmp(oba->oba_busname, "ofw"))
  106                 return (0);
  107         if ((l = OF_getprop(oba->oba_phandle, "device_type", type,
  108             sizeof type - 1)) < 0)
  109                 return 0;
  110         if (l >= sizeof type)
  111                 return 0;
  112         type[l] = 0;
  113         return !strcmp(type, "block");
  114 }
  115 
  116 static void
  117 ofdisk_attach(struct device *parent, struct device *self, void *aux)
  118 {
  119         struct ofdisk_softc *of = (void *)self;
  120         struct ofbus_attach_args *oba = aux;
  121         char child[64];
  122         int l;
  123 
  124         if ((l = OF_getprop(oba->oba_phandle, "name", child,
  125             sizeof child - 1)) < 0)
  126                 panic("device without name?");
  127         if (l >= sizeof child)
  128                 l = sizeof child - 1;
  129         child[l] = 0;
  130 
  131         of->sc_flags = 0;
  132         of->sc_phandle = oba->oba_phandle;
  133         of->sc_unit = oba->oba_unit;
  134         of->sc_ihandle = 0;
  135         of->sc_dk.dk_driver = &ofdisk_dkdriver;
  136         of->sc_dk.dk_name = of->sc_name;
  137         strcpy(of->sc_name, of->sc_dev.dv_xname);
  138         disk_attach(&of->sc_dk);
  139         printf("\n");
  140 
  141         if (strcmp(child, "floppy") == 0)
  142                 of->sc_flags |= OFDF_ISFLOPPY;
  143 }
  144 
  145 int
  146 ofdisk_open(dev_t dev, int flags, int fmt, struct proc *p)
  147 {
  148         int unit = DISKUNIT(dev);
  149         struct ofdisk_softc *of;
  150         char path[256];
  151         int l;
  152         
  153         if (unit >= ofdisk_cd.cd_ndevs)
  154                 return ENXIO;
  155         if (!(of = ofdisk_cd.cd_devs[unit]))
  156                 return ENXIO;
  157 
  158         if (!of->sc_ihandle) {
  159                 if ((l = OF_package_to_path(of->sc_phandle, path,
  160                     sizeof path - 3)) < 0 ||
  161                     l >= sizeof path - 3)
  162                         return ENXIO;
  163                 path[l] = 0;
  164 
  165                 /*
  166                  * XXX This is for the benefit of SCSI/IDE disks that don't
  167                  * XXX have all their childs in the device tree.
  168                  * XXX YES, I DO THINK THIS IS A BUG IN OPENFIRMWARE!!!
  169                  * XXX And yes, this is a very gross hack!
  170                  * XXX See also ofscsi.c
  171                  */
  172                 if (!strcmp(path + l - 4, "disk")) {
  173                         path[l++] = '@';
  174                         path[l++] = '' + of->sc_unit;
  175                         path[l] = 0;
  176                 }
  177 
  178                 strcat(path, ":0");
  179 
  180                 if ((of->sc_ihandle = OF_open(path)) == -1)
  181                         return ENXIO;
  182 
  183                 /*
  184                  * Try to get characteristics of the disk.
  185                  */
  186                 of->max_transfer = OF_call_method_1("max-transfer",
  187                     of->sc_ihandle, 0);
  188                 if (of->max_transfer > MAXPHYS)
  189                         of->max_transfer = MAXPHYS;
  190 
  191                 ofdisk_getdisklabel(dev);
  192         }
  193 
  194         switch (fmt) {
  195         case S_IFCHR:
  196                 of->sc_dk.dk_copenmask |= 1 << DISKPART(dev);
  197                 break;
  198         case S_IFBLK:
  199                 of->sc_dk.dk_bopenmask |= 1 << DISKPART(dev);
  200                 break;
  201         }
  202         of->sc_dk.dk_openmask =
  203             of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
  204         
  205         return 0;
  206 }
  207 
  208 int
  209 ofdisk_close(dev_t dev, int flags, int fmt, struct proc *p)
  210 {
  211         struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
  212 
  213         switch (fmt) {
  214         case S_IFCHR:
  215                 of->sc_dk.dk_copenmask &= ~(1 << DISKPART(dev));
  216                 break;
  217         case S_IFBLK:
  218                 of->sc_dk.dk_bopenmask &= ~(1 << DISKPART(dev));
  219                 break;
  220         }
  221         of->sc_dk.dk_openmask = of->sc_dk.dk_copenmask | of->sc_dk.dk_bopenmask;
  222         
  223 #ifdef  FIRMWORKSBUGS
  224         /*
  225          * This is a hack to get the firmware to flush its buffers.
  226          */
  227         OF_seek(of->sc_ihandle, 0);
  228 #endif
  229         if (!of->sc_dk.dk_openmask) {
  230                 OF_close(of->sc_ihandle);
  231                 of->sc_ihandle = 0;
  232         }
  233 
  234         return 0;
  235 }
  236 
  237 void
  238 ofdisk_strategy(struct buf *bp)
  239 {
  240         struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
  241         struct partition *p;
  242         u_quad_t off;
  243         int read;
  244         int (*OF_io)(int, void *, int);
  245         daddr_t blkno = bp->b_blkno;
  246 
  247         bp->b_resid = 0;
  248         if (bp->b_bcount == 0)
  249                 goto done;
  250         
  251         OF_io = bp->b_flags & B_READ ? OF_read : OF_write;
  252 
  253         if (DISKPART(bp->b_dev) != RAW_PART) {
  254                 if (bounds_check_with_label(&of->sc_dk, bp, 0) <= 0) {
  255                         bp->b_resid = bp->b_bcount;
  256                         goto done;
  257                 }
  258                 p = &of->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
  259                 blkno = bp->b_blkno + p->p_offset;
  260         }
  261 
  262         disk_busy(&of->sc_dk);
  263 
  264         off = (u_quad_t)blkno * DEV_BSIZE;
  265         read = -1;
  266         do {
  267                 if (OF_seek(of->sc_ihandle, off) < 0)
  268                         break;
  269                 read = OF_io(of->sc_ihandle, bp->b_data, bp->b_bcount);
  270         } while (read == -2);
  271 
  272         if (read < 0) {
  273                 bp->b_error = EIO;
  274                 bp->b_flags |= B_ERROR;
  275                 bp->b_resid = bp->b_bcount;
  276         } else
  277                 bp->b_resid = bp->b_bcount - read;
  278 
  279         disk_unbusy(&of->sc_dk, bp->b_bcount - bp->b_resid,
  280             (bp->b_flags & B_READ));
  281 
  282 done:
  283         biodone(bp);
  284 }
  285 
  286 static void
  287 ofminphys(struct buf *bp)
  288 {
  289         struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(bp->b_dev)];
  290         
  291         if (bp->b_bcount > of->max_transfer)
  292                 bp->b_bcount = of->max_transfer;
  293 }
  294 
  295 int
  296 ofdisk_read(dev_t dev, struct uio *uio, int flags)
  297 {
  298         return physio(ofdisk_strategy, NULL, dev, B_READ, ofminphys, uio);
  299 }
  300 
  301 int
  302 ofdisk_write(dev_t dev, struct uio *uio, int flags)
  303 {
  304         return physio(ofdisk_strategy, NULL, dev, B_WRITE, ofminphys, uio);
  305 }
  306 
  307 int
  308 ofdisk_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  309 {
  310         struct ofdisk_softc *of = ofdisk_cd.cd_devs[DISKUNIT(dev)];
  311         int error;
  312 #ifdef __HAVE_OLD_DISKLABEL
  313         struct disklabel newlabel;
  314 #endif
  315         
  316         switch (cmd) {
  317         case DIOCGDINFO:
  318                 *(struct disklabel *)data = *of->sc_dk.dk_label;
  319                 return 0;
  320 #ifdef __HAVE_OLD_DISKLABEL
  321         case ODIOCGDINFO:
  322                 newlabel = *of->sc_dk.dk_label;
  323                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  324                         return ENOTTY;
  325                 memcpy(data, &newlabel, sizeof (struct olddisklabel));
  326                 return 0;
  327 #endif
  328                 
  329         case DIOCGPART:
  330                 ((struct partinfo *)data)->disklab = of->sc_dk.dk_label;
  331                 ((struct partinfo *)data)->part =
  332                         &of->sc_dk.dk_label->d_partitions[DISKPART(dev)];
  333                 return 0;
  334                 
  335         case DIOCWDINFO:
  336         case DIOCSDINFO:
  337 #ifdef __HAVE_OLD_DISKLABEL
  338         case ODIOCWDINFO:
  339         case ODIOCSDINFO:
  340 #endif
  341         {
  342                 struct disklabel *lp;
  343 
  344 #ifdef __HAVE_OLD_DISKLABEL
  345                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
  346                         memset(&newlabel, 0, sizeof newlabel);
  347                         memcpy(&newlabel, data, sizeof (struct olddisklabel));
  348                         lp = &newlabel;
  349                 } else
  350 #endif
  351                 lp = (struct disklabel *)data;
  352 
  353                 if ((flag & FWRITE) == 0)
  354                         return EBADF;
  355                 
  356                 error = setdisklabel(of->sc_dk.dk_label,
  357                     lp, /*of->sc_dk.dk_openmask */0,
  358                     of->sc_dk.dk_cpulabel);
  359                 if (error == 0 && cmd == DIOCWDINFO
  360 #ifdef __HAVE_OLD_DISKLABEL
  361                     || xfer == ODIOCWDINFO
  362 #endif
  363                     )
  364                         error = writedisklabel(MAKEDISKDEV(major(dev),
  365                             DISKUNIT(dev), RAW_PART), ofdisk_strategy,
  366                             of->sc_dk.dk_label, of->sc_dk.dk_cpulabel);
  367 
  368                 return error;
  369         }
  370 
  371         case DIOCGDEFLABEL:
  372                 ofdisk_getdefaultlabel(of, (struct disklabel *)data);
  373                 return 0;
  374 #ifdef __HAVE_OLD_DISKLABEL
  375         case DIOCGDEFLABEL:
  376                 ofdisk_getdefaultlabel(of, &newlabel);
  377                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  378                         return ENOTTY;
  379                 memcpy(data, &newlabel, sizeof (struct olddisklabel));
  380                 return 0;
  381 #endif
  382 
  383         default:
  384                 return ENOTTY;
  385         }
  386 }
  387 
  388 int
  389 ofdisk_dump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  390 {
  391         return EINVAL;
  392 }
  393 
  394 int
  395 ofdisk_size(dev_t dev)
  396 {
  397         struct ofdisk_softc *of;
  398         struct disklabel *lp;
  399         int size, part, omask, unit;
  400 
  401         unit = DISKUNIT(dev);
  402         if (unit >= ofdisk_cd.cd_ndevs ||
  403             (of = ofdisk_cd.cd_devs[unit]) == NULL)
  404                 return -1;
  405 
  406         part = DISKPART(dev);
  407         omask = of->sc_dk.dk_openmask & (1 << part);
  408         lp = of->sc_dk.dk_label;
  409 
  410         if (omask == 0 && ofdisk_open(dev, 0, S_IFBLK, curproc) != 0)
  411                 return -1;
  412 
  413         if (lp->d_partitions[part].p_fstype != FS_SWAP)
  414                 size = -1;
  415         else
  416                 size = lp->d_partitions[part].p_size *
  417                     (lp->d_secsize / DEV_BSIZE);
  418 
  419         if (omask == 0 && ofdisk_close(dev, 0, S_IFBLK, curproc) != 0)
  420                 return -1;
  421 
  422         return size;
  423 }
  424 
  425 void
  426 ofdisk_getdefaultlabel(struct ofdisk_softc *of, struct disklabel *lp)
  427 {
  428 
  429         memset(lp, 0, sizeof *lp);
  430 
  431         /*
  432          * XXX Firmware bug?  Asking for block size gives a
  433          * XXX ridiculous number!  So we use what the boot program
  434          * XXX uses.
  435          */
  436         lp->d_secsize = DEV_BSIZE;
  437 
  438         lp->d_secperunit = OF_call_method_1("#blocks",
  439             of->sc_ihandle, 0);
  440         if (lp->d_secperunit == (u_int32_t)-1)
  441                 lp->d_secperunit = 0x7fffffff;
  442 
  443         lp->d_secpercyl = 1;
  444         lp->d_nsectors = 1;
  445         lp->d_ntracks = 1;
  446         lp->d_ncylinders = lp->d_secperunit;
  447 
  448         lp->d_partitions[RAW_PART].p_offset = 0;
  449         lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
  450         lp->d_npartitions = RAW_PART + 1;
  451 
  452         lp->d_magic = DISKMAGIC;
  453         lp->d_magic2 = DISKMAGIC;
  454         lp->d_checksum = dkcksum(lp);
  455 }
  456 
  457 void
  458 ofdisk_getdisklabel(dev)
  459         dev_t dev;
  460 {
  461         int unit = DISKUNIT(dev);
  462         struct ofdisk_softc *of = ofdisk_cd.cd_devs[unit];
  463         struct disklabel *lp = of->sc_dk.dk_label;
  464         const char *errmes;
  465         int l;
  466 
  467         ofdisk_getdefaultlabel(of, lp);
  468 
  469         /*
  470          * Don't read the disklabel on a floppy; simply
  471          * assign all partitions the same size/offset as
  472          * RAW_PART.  (This is essentially what the ISA
  473          * floppy driver does, but we don't deal with
  474          * density stuff.)
  475          */
  476         if (of->sc_flags & OFDF_ISFLOPPY) {
  477                 lp->d_npartitions = MAXPARTITIONS;
  478                 for (l = 0; l < lp->d_npartitions; l++) {
  479                         if (l == RAW_PART)
  480                                 continue;
  481                         /* struct copy */
  482                         lp->d_partitions[l] =
  483                             lp->d_partitions[RAW_PART];
  484                 }
  485                 lp->d_checksum = dkcksum(lp);
  486         } else {
  487                 errmes = readdisklabel(MAKEDISKDEV(major(dev),
  488                     unit, RAW_PART), ofdisk_strategy, lp,
  489                     of->sc_dk.dk_cpulabel);
  490                 if (errmes != NULL)
  491                         printf("%s: %s\n", of->sc_dev.dv_xname, errmes);
  492         }
  493 }

Cache object: 22286391a4d917edd3af24deb71d383c


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