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  * Copyright (c) 2000 Michael Smith
    3  * Copyright (c) 2001 Scott Long
    4  * Copyright (c) 2000 BSDi
    5  * Copyright (c) 2001 Adaptec, Inc.
    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  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/8.4/sys/dev/aac/aac_disk.c 240877 2012-09-23 20:31:45Z sbruno $");
   32 
   33 #include "opt_aac.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 
   40 #include <sys/bus.h>
   41 #include <sys/conf.h>
   42 #include <sys/disk.h>
   43 
   44 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 
   47 #include <machine/md_var.h>
   48 #include <machine/bus.h>
   49 #include <sys/rman.h>
   50 
   51 #include <dev/aac/aacreg.h>
   52 #include <sys/aac_ioctl.h>
   53 #include <dev/aac/aacvar.h>
   54 
   55 /*
   56  * Interface to parent.
   57  */
   58 static int aac_disk_probe(device_t dev);
   59 static int aac_disk_attach(device_t dev);
   60 static int aac_disk_detach(device_t dev);
   61 
   62 /*
   63  * Interface to the device switch.
   64  */
   65 static  disk_open_t     aac_disk_open;
   66 static  disk_close_t    aac_disk_close;
   67 static  disk_strategy_t aac_disk_strategy;
   68 static  dumper_t        aac_disk_dump;
   69 
   70 static devclass_t       aac_disk_devclass;
   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         { 0, 0 }
   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, aac_disk_devclass, 0, 0);
   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 paramters.
   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         /* perform accounting */
  165 
  166         /* pass the bio to the controller - it can work out who we are */
  167         mtx_lock(&sc->ad_controller->aac_io_lock);
  168         aac_submit_bio(bp);
  169         mtx_unlock(&sc->ad_controller->aac_io_lock);
  170 
  171         return;
  172 }
  173 
  174 /*
  175  * Map the S/G elements for doing a dump.
  176  */
  177 static void
  178 aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  179 {
  180         struct aac_fib *fib;
  181         struct aac_blockwrite *bw;
  182         struct aac_sg_table *sg;
  183         int i;
  184 
  185         fib = (struct aac_fib *)arg;
  186         bw = (struct aac_blockwrite *)&fib->data[0];
  187         sg = &bw->SgMap;
  188 
  189         if (sg != NULL) {
  190                 sg->SgCount = nsegs;
  191                 for (i = 0; i < nsegs; i++) {
  192                         if (segs[i].ds_addr >= BUS_SPACE_MAXADDR_32BIT)
  193                                 return;
  194                         sg->SgEntry[i].SgAddress = segs[i].ds_addr;
  195                         sg->SgEntry[i].SgByteCount = segs[i].ds_len;
  196                 }
  197                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
  198         }
  199 }
  200 
  201 /*
  202  * Map the S/G elements for doing a dump on 64-bit capable devices.
  203  */
  204 static void
  205 aac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  206 {
  207         struct aac_fib *fib;
  208         struct aac_blockwrite64 *bw;
  209         struct aac_sg_table64 *sg;
  210         int i;
  211 
  212         fib = (struct aac_fib *)arg;
  213         bw = (struct aac_blockwrite64 *)&fib->data[0];
  214         sg = &bw->SgMap64;
  215 
  216         if (sg != NULL) {
  217                 sg->SgCount = nsegs;
  218                 for (i = 0; i < nsegs; i++) {
  219                         sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
  220                         sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
  221                 }
  222                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64);
  223         }
  224 }
  225 
  226 /*
  227  * Dump memory out to an array
  228  *
  229  * Send out one command at a time with up to maxio of data.
  230  */
  231 static int
  232 aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
  233 {
  234         struct aac_disk *ad;
  235         struct aac_softc *sc;
  236         struct aac_fib *fib;
  237         size_t len, maxio;
  238         int size;
  239         static bus_dmamap_t dump_datamap;
  240         static int first = 0;
  241         struct disk *dp;
  242         bus_dmamap_callback_t *callback;
  243         u_int32_t command;
  244 
  245         dp = arg;
  246         ad = dp->d_drv1;
  247 
  248         if (ad == NULL)
  249                 return (EINVAL);
  250 
  251         sc= ad->ad_controller;
  252 
  253         if (!first) {
  254                 first = 1;
  255                 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
  256                         device_printf(sc->aac_dev,
  257                             "bus_dmamap_create failed\n");
  258                         return (ENOMEM);
  259                 }
  260         }
  261 
  262         /* Skip aac_alloc_sync_fib().  We don't want to mess with sleep locks */
  263         fib = &sc->aac_common->ac_sync_fib;
  264 
  265         while (length > 0) {
  266                 maxio = sc->aac_max_sectors << 9;
  267                 len = (length > maxio) ? maxio : length;
  268                 if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
  269                         struct aac_blockwrite *bw;
  270                         bw = (struct aac_blockwrite *)&fib->data[0];
  271                         bw->Command = VM_CtBlockWrite;
  272                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  273                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  274                         bw->ByteCount = len;
  275                         bw->Stable = CUNSTABLE;
  276                         command = ContainerCommand;
  277                         callback = aac_dump_map_sg;
  278                         size = sizeof(struct aac_blockwrite);
  279                 } else {
  280                         struct aac_blockwrite64 *bw;
  281                         bw = (struct aac_blockwrite64 *)&fib->data[0];
  282                         bw->Command = VM_CtHostWrite64;
  283                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  284                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  285                         bw->SectorCount = len / AAC_BLOCK_SIZE;
  286                         bw->Pad = 0;
  287                         bw->Flags = 0;
  288                         command = ContainerCommand64;
  289                         callback = aac_dump_map_sg64;
  290                         size = sizeof(struct aac_blockwrite64);
  291                 }
  292 
  293                 /*
  294                  * There really isn't any way to recover from errors or
  295                  * resource shortages here.  Oh well.  Because of that, don't
  296                  * bother trying to send the command from the callback; there
  297                  * is too much required context.
  298                  */
  299                 if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
  300                     len, callback, fib, BUS_DMA_NOWAIT) != 0)
  301                         return (ENOMEM);
  302 
  303                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  304                     BUS_DMASYNC_PREWRITE);
  305 
  306                 /* fib->Header.Size is set in aac_dump_map_sg */
  307                 size += fib->Header.Size;
  308 
  309                 if (aac_sync_fib(sc, command, 0, fib, size)) {
  310                         device_printf(sc->aac_dev,
  311                              "Error dumping block 0x%jx\n",
  312                              (uintmax_t)physical);
  313                         return (EIO);
  314                 }
  315 
  316                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  317                     BUS_DMASYNC_POSTWRITE);
  318 
  319                 bus_dmamap_unload(sc->aac_buffer_dmat, dump_datamap);
  320 
  321                 length -= len;
  322                 offset += len;
  323                 virtual = (uint8_t *)virtual + len;
  324         }
  325 
  326         return (0);
  327 }
  328 
  329 /*
  330  * Handle completion of an I/O request.
  331  */
  332 void
  333 aac_biodone(struct bio *bp)
  334 {
  335         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  336 
  337         if (bp->bio_flags & BIO_ERROR) {
  338                 bp->bio_resid = bp->bio_bcount;
  339                 disk_err(bp, "hard error", -1, 1);
  340         }
  341 
  342         biodone(bp);
  343 }
  344 
  345 /*
  346  * Stub only.
  347  */
  348 static int
  349 aac_disk_probe(device_t dev)
  350 {
  351 
  352         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  353 
  354         return (0);
  355 }
  356 
  357 /*
  358  * Attach a unit to the controller.
  359  */
  360 static int
  361 aac_disk_attach(device_t dev)
  362 {
  363         struct aac_disk *sc;
  364         
  365         sc = (struct aac_disk *)device_get_softc(dev);
  366         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  367 
  368         /* initialise our softc */
  369         sc->ad_controller =
  370             (struct aac_softc *)device_get_softc(device_get_parent(dev));
  371         sc->ad_container = device_get_ivars(dev);
  372         sc->ad_dev = dev;
  373 
  374         /*
  375          * require that extended translation be enabled - other drivers read the
  376          * disk!
  377          */
  378         sc->ad_size = sc->ad_container->co_mntobj.Capacity;
  379         if (sc->ad_controller->flags & AAC_FLAGS_LBA_64BIT)
  380                 sc->ad_size += (u_int64_t)
  381                         sc->ad_container->co_mntobj.CapacityHigh << 32;
  382         if (sc->ad_size >= (2 * 1024 * 1024)) {         /* 2GB */
  383                 sc->ad_heads = 255;
  384                 sc->ad_sectors = 63;
  385         } else if (sc->ad_size >= (1 * 1024 * 1024)) {  /* 1GB */
  386                 sc->ad_heads = 128;
  387                 sc->ad_sectors = 32;
  388         } else {
  389                 sc->ad_heads = 64;
  390                 sc->ad_sectors = 32;
  391         }
  392         sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
  393 
  394         device_printf(dev, "%juMB (%ju sectors)\n",
  395                       (intmax_t)sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
  396                       (intmax_t)sc->ad_size);
  397 
  398         /* attach a generic disk device to ourselves */
  399         sc->unit = device_get_unit(dev);
  400         sc->ad_disk = disk_alloc();
  401         sc->ad_disk->d_drv1 = sc;
  402         sc->ad_disk->d_name = "aacd";
  403         sc->ad_disk->d_maxsize = sc->ad_controller->aac_max_sectors << 9;
  404         sc->ad_disk->d_open = aac_disk_open;
  405         sc->ad_disk->d_close = aac_disk_close;
  406         sc->ad_disk->d_strategy = aac_disk_strategy;
  407         sc->ad_disk->d_dump = aac_disk_dump;
  408         sc->ad_disk->d_sectorsize = AAC_BLOCK_SIZE;
  409         sc->ad_disk->d_mediasize = (off_t)sc->ad_size * AAC_BLOCK_SIZE;
  410         sc->ad_disk->d_fwsectors = sc->ad_sectors;
  411         sc->ad_disk->d_fwheads = sc->ad_heads;
  412         sc->ad_disk->d_unit = sc->unit;
  413         disk_create(sc->ad_disk, DISK_VERSION);
  414 
  415         return (0);
  416 }
  417 
  418 /*
  419  * Disconnect ourselves from the system.
  420  */
  421 static int
  422 aac_disk_detach(device_t dev)
  423 {
  424         struct aac_disk *sc;
  425 
  426         sc = (struct aac_disk *)device_get_softc(dev);
  427         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  428 
  429         if (sc->ad_flags & AAC_DISK_OPEN)
  430                 return(EBUSY);
  431 
  432         disk_destroy(sc->ad_disk);
  433 
  434         return(0);
  435 }

Cache object: 293810476214404f1ee58c2817dd732b


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