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/aac/aac_disk.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2000 Michael Smith
    5  * Copyright (c) 2001 Scott Long
    6  * Copyright (c) 2000 BSDi
    7  * Copyright (c) 2001 Adaptec, Inc.
    8  * All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include "opt_aac.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 
   42 #include <sys/bus.h>
   43 #include <sys/conf.h>
   44 #include <sys/disk.h>
   45 
   46 #include <vm/vm.h>
   47 #include <vm/pmap.h>
   48 
   49 #include <machine/md_var.h>
   50 #include <machine/bus.h>
   51 #include <sys/rman.h>
   52 
   53 #include <dev/aac/aacreg.h>
   54 #include <sys/aac_ioctl.h>
   55 #include <dev/aac/aacvar.h>
   56 
   57 /*
   58  * Interface to parent.
   59  */
   60 static int aac_disk_probe(device_t dev);
   61 static int aac_disk_attach(device_t dev);
   62 static int aac_disk_detach(device_t dev);
   63 
   64 /*
   65  * Interface to the device switch.
   66  */
   67 static  disk_open_t     aac_disk_open;
   68 static  disk_close_t    aac_disk_close;
   69 static  disk_strategy_t aac_disk_strategy;
   70 static  dumper_t        aac_disk_dump;
   71 
   72 static device_method_t aac_disk_methods[] = {
   73         DEVMETHOD(device_probe, aac_disk_probe),
   74         DEVMETHOD(device_attach,        aac_disk_attach),
   75         DEVMETHOD(device_detach,        aac_disk_detach),
   76         DEVMETHOD_END
   77 };
   78 
   79 static driver_t aac_disk_driver = {
   80         "aacd",
   81         aac_disk_methods,
   82         sizeof(struct aac_disk)
   83 };
   84 
   85 DRIVER_MODULE(aacd, aac, aac_disk_driver, NULL, NULL);
   86 
   87 /*
   88  * Handle open from generic layer.
   89  *
   90  * This is called by the diskslice code on first open in order to get the
   91  * basic device geometry parameters.
   92  */
   93 static int
   94 aac_disk_open(struct disk *dp)
   95 {
   96         struct aac_disk *sc;
   97 
   98         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
   99 
  100         sc = (struct aac_disk *)dp->d_drv1;
  101 
  102         if (sc == NULL) {
  103                 printf("aac_disk_open: No Softc\n");
  104                 return (ENXIO);
  105         }
  106 
  107         /* check that the controller is up and running */
  108         if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) {
  109                 device_printf(sc->ad_controller->aac_dev,
  110                     "Controller Suspended controller state = 0x%x\n",
  111                     sc->ad_controller->aac_state);
  112                 return(ENXIO);
  113         }
  114 
  115         sc->ad_flags |= AAC_DISK_OPEN;
  116         return (0);
  117 }
  118 
  119 /*
  120  * Handle last close of the disk device.
  121  */
  122 static int
  123 aac_disk_close(struct disk *dp)
  124 {
  125         struct aac_disk *sc;
  126 
  127         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  128 
  129         sc = (struct aac_disk *)dp->d_drv1;
  130 
  131         if (sc == NULL)
  132                 return (ENXIO);
  133 
  134         sc->ad_flags &= ~AAC_DISK_OPEN;
  135         return (0);
  136 }
  137 
  138 /*
  139  * Handle an I/O request.
  140  */
  141 static void
  142 aac_disk_strategy(struct bio *bp)
  143 {
  144         struct aac_disk *sc;
  145 
  146         sc = (struct aac_disk *)bp->bio_disk->d_drv1;
  147         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  148 
  149         /* bogus disk? */
  150         if (sc == NULL) {
  151                 bp->bio_flags |= BIO_ERROR;
  152                 bp->bio_error = EINVAL;
  153                 biodone(bp);
  154                 return;
  155         }
  156 
  157         /* do-nothing operation? */
  158         if (bp->bio_bcount == 0) {
  159                 bp->bio_resid = bp->bio_bcount;
  160                 biodone(bp);
  161                 return;
  162         }
  163 
  164         if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE)) {
  165                 biofinish(bp, NULL, EOPNOTSUPP);
  166                 return;
  167         }
  168 
  169         /* perform accounting */
  170 
  171         /* pass the bio to the controller - it can work out who we are */
  172         mtx_lock(&sc->ad_controller->aac_io_lock);
  173         aac_submit_bio(bp);
  174         mtx_unlock(&sc->ad_controller->aac_io_lock);
  175 }
  176 
  177 /*
  178  * Map the S/G elements for doing a dump.
  179  */
  180 static void
  181 aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  182 {
  183         struct aac_fib *fib;
  184         struct aac_blockwrite *bw;
  185         struct aac_sg_table *sg;
  186         int i;
  187 
  188         fib = (struct aac_fib *)arg;
  189         bw = (struct aac_blockwrite *)&fib->data[0];
  190         sg = &bw->SgMap;
  191 
  192         if (sg != NULL) {
  193                 sg->SgCount = nsegs;
  194                 for (i = 0; i < nsegs; i++) {
  195                         if (segs[i].ds_addr >= BUS_SPACE_MAXADDR_32BIT)
  196                                 return;
  197                         sg->SgEntry[i].SgAddress = segs[i].ds_addr;
  198                         sg->SgEntry[i].SgByteCount = segs[i].ds_len;
  199                 }
  200                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
  201         }
  202 }
  203 
  204 /*
  205  * Map the S/G elements for doing a dump on 64-bit capable devices.
  206  */
  207 static void
  208 aac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  209 {
  210         struct aac_fib *fib;
  211         struct aac_blockwrite64 *bw;
  212         struct aac_sg_table64 *sg;
  213         int i;
  214 
  215         fib = (struct aac_fib *)arg;
  216         bw = (struct aac_blockwrite64 *)&fib->data[0];
  217         sg = &bw->SgMap64;
  218 
  219         if (sg != NULL) {
  220                 sg->SgCount = nsegs;
  221                 for (i = 0; i < nsegs; i++) {
  222                         sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
  223                         sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
  224                 }
  225                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64);
  226         }
  227 }
  228 
  229 /*
  230  * Dump memory out to an array
  231  *
  232  * Send out one command at a time with up to maxio of data.
  233  */
  234 static int
  235 aac_disk_dump(void *arg, void *virtual, off_t offset, size_t length)
  236 {
  237         struct aac_disk *ad;
  238         struct aac_softc *sc;
  239         struct aac_fib *fib;
  240         size_t len, maxio;
  241         int size;
  242         static bus_dmamap_t dump_datamap;
  243         static int first = 0;
  244         struct disk *dp;
  245         bus_dmamap_callback_t *callback;
  246         u_int32_t command;
  247 
  248         dp = arg;
  249         ad = dp->d_drv1;
  250 
  251         if (ad == NULL)
  252                 return (EINVAL);
  253 
  254         sc= ad->ad_controller;
  255 
  256         if (!first) {
  257                 first = 1;
  258                 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
  259                         device_printf(sc->aac_dev,
  260                             "bus_dmamap_create failed\n");
  261                         return (ENOMEM);
  262                 }
  263         }
  264 
  265         /* Skip aac_alloc_sync_fib().  We don't want to mess with sleep locks */
  266         fib = &sc->aac_common->ac_sync_fib;
  267 
  268         while (length > 0) {
  269                 maxio = sc->aac_max_sectors << 9;
  270                 len = (length > maxio) ? maxio : length;
  271                 if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
  272                         struct aac_blockwrite *bw;
  273                         bw = (struct aac_blockwrite *)&fib->data[0];
  274                         bw->Command = VM_CtBlockWrite;
  275                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  276                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  277                         bw->ByteCount = len;
  278                         bw->Stable = CUNSTABLE;
  279                         command = ContainerCommand;
  280                         callback = aac_dump_map_sg;
  281                         size = sizeof(struct aac_blockwrite);
  282                 } else {
  283                         struct aac_blockwrite64 *bw;
  284                         bw = (struct aac_blockwrite64 *)&fib->data[0];
  285                         bw->Command = VM_CtHostWrite64;
  286                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  287                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  288                         bw->SectorCount = len / AAC_BLOCK_SIZE;
  289                         bw->Pad = 0;
  290                         bw->Flags = 0;
  291                         command = ContainerCommand64;
  292                         callback = aac_dump_map_sg64;
  293                         size = sizeof(struct aac_blockwrite64);
  294                 }
  295 
  296                 /*
  297                  * There really isn't any way to recover from errors or
  298                  * resource shortages here.  Oh well.  Because of that, don't
  299                  * bother trying to send the command from the callback; there
  300                  * is too much required context.
  301                  */
  302                 if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
  303                     len, callback, fib, BUS_DMA_NOWAIT) != 0)
  304                         return (ENOMEM);
  305 
  306                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  307                     BUS_DMASYNC_PREWRITE);
  308 
  309                 /* fib->Header.Size is set in aac_dump_map_sg */
  310                 size += fib->Header.Size;
  311 
  312                 if (aac_sync_fib(sc, command, 0, fib, size)) {
  313                         device_printf(sc->aac_dev,
  314                              "Error dumping block to 0x%jx\n",
  315                              (uintmax_t)offset);
  316                         return (EIO);
  317                 }
  318 
  319                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  320                     BUS_DMASYNC_POSTWRITE);
  321 
  322                 bus_dmamap_unload(sc->aac_buffer_dmat, dump_datamap);
  323 
  324                 length -= len;
  325                 offset += len;
  326                 virtual = (uint8_t *)virtual + len;
  327         }
  328 
  329         return (0);
  330 }
  331 
  332 /*
  333  * Handle completion of an I/O request.
  334  */
  335 void
  336 aac_biodone(struct bio *bp)
  337 {
  338         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  339 
  340         if (bp->bio_flags & BIO_ERROR) {
  341                 bp->bio_resid = bp->bio_bcount;
  342                 disk_err(bp, "hard error", -1, 1);
  343         }
  344 
  345         biodone(bp);
  346 }
  347 
  348 /*
  349  * Stub only.
  350  */
  351 static int
  352 aac_disk_probe(device_t dev)
  353 {
  354 
  355         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  356 
  357         return (0);
  358 }
  359 
  360 /*
  361  * Attach a unit to the controller.
  362  */
  363 static int
  364 aac_disk_attach(device_t dev)
  365 {
  366         struct aac_disk *sc;
  367 
  368         sc = (struct aac_disk *)device_get_softc(dev);
  369         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  370 
  371         /* initialise our softc */
  372         sc->ad_controller =
  373             (struct aac_softc *)device_get_softc(device_get_parent(dev));
  374         sc->ad_container = device_get_ivars(dev);
  375         sc->ad_dev = dev;
  376 
  377         /*
  378          * require that extended translation be enabled - other drivers read the
  379          * disk!
  380          */
  381         sc->ad_size = sc->ad_container->co_mntobj.Capacity;
  382         if (sc->ad_controller->flags & AAC_FLAGS_LBA_64BIT)
  383                 sc->ad_size += (u_int64_t)
  384                         sc->ad_container->co_mntobj.CapacityHigh << 32;
  385         if (sc->ad_size >= (2 * 1024 * 1024)) {         /* 2GB */
  386                 sc->ad_heads = 255;
  387                 sc->ad_sectors = 63;
  388         } else if (sc->ad_size >= (1 * 1024 * 1024)) {  /* 1GB */
  389                 sc->ad_heads = 128;
  390                 sc->ad_sectors = 32;
  391         } else {
  392                 sc->ad_heads = 64;
  393                 sc->ad_sectors = 32;
  394         }
  395         sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
  396 
  397         device_printf(dev, "%juMB (%ju sectors)\n",
  398                       (intmax_t)sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
  399                       (intmax_t)sc->ad_size);
  400 
  401         /* attach a generic disk device to ourselves */
  402         sc->unit = device_get_unit(dev);
  403         sc->ad_disk = disk_alloc();
  404         sc->ad_disk->d_drv1 = sc;
  405         sc->ad_disk->d_flags = DISKFLAG_UNMAPPED_BIO;
  406         sc->ad_disk->d_name = "aacd";
  407         sc->ad_disk->d_maxsize = sc->ad_controller->aac_max_sectors << 9;
  408         sc->ad_disk->d_open = aac_disk_open;
  409         sc->ad_disk->d_close = aac_disk_close;
  410         sc->ad_disk->d_strategy = aac_disk_strategy;
  411         sc->ad_disk->d_dump = aac_disk_dump;
  412         sc->ad_disk->d_sectorsize = AAC_BLOCK_SIZE;
  413         sc->ad_disk->d_mediasize = (off_t)sc->ad_size * AAC_BLOCK_SIZE;
  414         sc->ad_disk->d_fwsectors = sc->ad_sectors;
  415         sc->ad_disk->d_fwheads = sc->ad_heads;
  416         sc->ad_disk->d_unit = sc->unit;
  417         disk_create(sc->ad_disk, DISK_VERSION);
  418 
  419         return (0);
  420 }
  421 
  422 /*
  423  * Disconnect ourselves from the system.
  424  */
  425 static int
  426 aac_disk_detach(device_t dev)
  427 {
  428         struct aac_disk *sc;
  429 
  430         sc = (struct aac_disk *)device_get_softc(dev);
  431         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  432 
  433         if (sc->ad_flags & AAC_DISK_OPEN)
  434                 return(EBUSY);
  435 
  436         disk_destroy(sc->ad_disk);
  437 
  438         return(0);
  439 }

Cache object: 846e1491494c4f0f99430f0e68bf82ba


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