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/raid/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  * $FreeBSD: src/sys/dev/aac/aac_disk.c,v 1.50 2012/07/07 17:20:24 eadler Exp $
   30  */
   31 
   32 #include "opt_aac.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 
   39 #include <sys/bus.h>
   40 #include <sys/conf.h>
   41 #include <sys/disk.h>
   42 #include <sys/dtype.h>
   43 
   44 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 
   47 #include <machine/md_var.h>
   48 #include <sys/rman.h>
   49 
   50 #include <dev/raid/aac/aacreg.h>
   51 #include <dev/raid/aac/aac_ioctl.h>
   52 #include <dev/raid/aac/aacvar.h>
   53 
   54 /*
   55  * Interface to parent.
   56  */
   57 static int aac_disk_probe(device_t dev);
   58 static int aac_disk_attach(device_t dev);
   59 static int aac_disk_detach(device_t dev);
   60 
   61 /*
   62  * Interface to the device switch.
   63  */
   64 static  d_open_t        aac_disk_open;
   65 static  d_close_t       aac_disk_close;
   66 static  d_strategy_t    aac_disk_strategy;
   67 static  d_dump_t        aac_disk_dump;
   68 
   69 static struct dev_ops aac_disk_ops = {
   70         { "aacd", 0, D_DISK },
   71         .d_open =               aac_disk_open,
   72         .d_close =              aac_disk_close,
   73         .d_read =               physread,
   74         .d_write =              physwrite,
   75         .d_strategy =           aac_disk_strategy,
   76         .d_dump =               aac_disk_dump,
   77 };
   78 
   79 static devclass_t       aac_disk_devclass;
   80 
   81 static device_method_t aac_disk_methods[] = {
   82         DEVMETHOD(device_probe, aac_disk_probe),
   83         DEVMETHOD(device_attach,        aac_disk_attach),
   84         DEVMETHOD(device_detach,        aac_disk_detach),
   85         DEVMETHOD_END
   86 };
   87 
   88 static driver_t aac_disk_driver = {
   89         "aacd",
   90         aac_disk_methods,
   91         sizeof(struct aac_disk)
   92 };
   93 
   94 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, NULL, NULL);
   95 
   96 /*
   97  * Handle open from generic layer.
   98  *
   99  * This is called by the diskslice code on first open in order to get the
  100  * basic device geometry paramters.
  101  */
  102 static int
  103 aac_disk_open(struct dev_open_args *ap)
  104 {
  105         struct aac_disk *sc;
  106 
  107         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  108 
  109         sc = ap->a_head.a_dev->si_drv1;
  110         
  111         if (sc == NULL) {
  112                 kprintf("aac_disk_open: No Softc\n");
  113                 return (ENXIO);
  114         }
  115 
  116         /* check that the controller is up and running */
  117         if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) {
  118                 device_printf(sc->ad_controller->aac_dev,
  119                     "Controller Suspended controller state = 0x%x\n",
  120                     sc->ad_controller->aac_state);
  121                 return(ENXIO);
  122         }
  123 
  124         sc->ad_flags |= AAC_DISK_OPEN;
  125         return (0);
  126 }
  127 
  128 /*
  129  * Handle last close of the disk device.
  130  */
  131 static int
  132 aac_disk_close(struct dev_close_args *ap)
  133 {
  134         struct aac_disk *sc;
  135 
  136         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  137 
  138         sc = ap->a_head.a_dev->si_drv1;
  139         
  140         if (sc == NULL)
  141                 return (ENXIO);
  142 
  143         sc->ad_flags &= ~AAC_DISK_OPEN;
  144         return (0);
  145 }
  146 
  147 /*
  148  * Handle an I/O request.
  149  */
  150 static int
  151 aac_disk_strategy(struct dev_strategy_args *ap)
  152 {
  153         struct bio *bio = ap->a_bio;
  154         struct buf *bp = bio->bio_buf;
  155         struct aac_disk *sc;
  156 
  157         sc = ap->a_head.a_dev->si_drv1;
  158         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  159 
  160         /* bogus disk? */
  161         if (sc == NULL) {
  162                 bp->b_flags |= B_ERROR;
  163                 bp->b_error = EINVAL;
  164                 biodone(bio);
  165                 return (0);
  166         }
  167 
  168         /* do-nothing operation? */
  169         if (bp->b_bcount == 0) {
  170                 bp->b_resid = bp->b_bcount;
  171                 biodone(bio);
  172                 return (0);
  173         }
  174 
  175         /* perform accounting */
  176 
  177         /* pass the bio to the controller - it can work out who we are */
  178         lockmgr(&sc->ad_controller->aac_io_lock, LK_EXCLUSIVE);
  179         devstat_start_transaction(&sc->ad_stats);
  180         aac_submit_bio(sc, bio);
  181         lockmgr(&sc->ad_controller->aac_io_lock, LK_RELEASE);
  182 
  183         return (0);
  184 }
  185 
  186 /*
  187  * Map the S/G elements for doing a dump.
  188  */
  189 static void
  190 aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  191 {
  192         struct aac_fib *fib;
  193         struct aac_blockwrite *bw;
  194         struct aac_sg_table *sg;
  195         int i;
  196 
  197         fib = (struct aac_fib *)arg;
  198         bw = (struct aac_blockwrite *)&fib->data[0];
  199         sg = &bw->SgMap;
  200 
  201         if (sg != NULL) {
  202                 sg->SgCount = nsegs;
  203                 for (i = 0; i < nsegs; i++) {
  204                         if (segs[i].ds_addr >= BUS_SPACE_MAXADDR_32BIT)
  205                                 return;
  206                         sg->SgEntry[i].SgAddress = segs[i].ds_addr;
  207                         sg->SgEntry[i].SgByteCount = segs[i].ds_len;
  208                 }
  209                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
  210         }
  211 }
  212 
  213 /*
  214  * Map the S/G elements for doing a dump on 64-bit capable devices.
  215  */
  216 static void
  217 aac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  218 {
  219         struct aac_fib *fib;
  220         struct aac_blockwrite64 *bw;
  221         struct aac_sg_table64 *sg;
  222         int i;
  223 
  224         fib = (struct aac_fib *)arg;
  225         bw = (struct aac_blockwrite64 *)&fib->data[0];
  226         sg = &bw->SgMap64;
  227 
  228         if (sg != NULL) {
  229                 sg->SgCount = nsegs;
  230                 for (i = 0; i < nsegs; i++) {
  231                         sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
  232                         sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
  233                 }
  234                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64);
  235         }
  236 }
  237 
  238 /*
  239  * Dump memory out to an array
  240  *
  241  * Send out one command at a time with up to maxio of data.
  242  */
  243 static int
  244 aac_disk_dump(struct dev_dump_args *ap)
  245 {
  246         cdev_t dev = ap->a_head.a_dev;
  247         size_t length = ap->a_length;
  248         off_t offset = ap->a_offset;
  249         void *virtual = ap->a_virtual;
  250         vm_offset_t physical = ap->a_physical;
  251         struct aac_disk *ad;
  252         struct aac_softc *sc;
  253         struct aac_fib *fib;
  254         size_t len, maxio;
  255         int size;
  256         static bus_dmamap_t dump_datamap;
  257         static int first = 0;
  258         bus_dmamap_callback_t *callback;
  259         u_int32_t command;
  260 
  261         ad = dev->si_drv1;
  262 
  263         if (ad == NULL)
  264                 return (EINVAL);
  265 
  266         sc= ad->ad_controller;
  267 
  268         if (!first) {
  269                 first = 1;
  270                 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
  271                         device_printf(sc->aac_dev,
  272                             "bus_dmamap_create failed\n");
  273                         return (ENOMEM);
  274                 }
  275         }
  276 
  277         /* Skip aac_alloc_sync_fib().  We don't want to mess with sleep locks */
  278         fib = &sc->aac_common->ac_sync_fib;
  279 
  280         while (length > 0) {
  281                 maxio = sc->aac_max_sectors << 9;
  282                 len = (length > maxio) ? maxio : length;
  283                 if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
  284                         struct aac_blockwrite *bw;
  285                         bw = (struct aac_blockwrite *)&fib->data[0];
  286                         bw->Command = VM_CtBlockWrite;
  287                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  288                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  289                         bw->ByteCount = len;
  290                         bw->Stable = CUNSTABLE;
  291                         command = ContainerCommand;
  292                         callback = aac_dump_map_sg;
  293                         size = sizeof(struct aac_blockwrite);
  294                 } else {
  295                         struct aac_blockwrite64 *bw;
  296                         bw = (struct aac_blockwrite64 *)&fib->data[0];
  297                         bw->Command = VM_CtHostWrite64;
  298                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
  299                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
  300                         bw->SectorCount = len / AAC_BLOCK_SIZE;
  301                         bw->Pad = 0;
  302                         bw->Flags = 0;
  303                         command = ContainerCommand64;
  304                         callback = aac_dump_map_sg64;
  305                         size = sizeof(struct aac_blockwrite64);
  306                 }
  307 
  308                 /*
  309                  * There really isn't any way to recover from errors or
  310                  * resource shortages here.  Oh well.  Because of that, don't
  311                  * bother trying to send the command from the callback; there
  312                  * is too much required context.
  313                  */
  314                 if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
  315                     len, callback, fib, BUS_DMA_NOWAIT) != 0)
  316                         return (ENOMEM);
  317 
  318                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  319                     BUS_DMASYNC_PREWRITE);
  320 
  321                 /* fib->Header.Size is set in aac_dump_map_sg */
  322                 size += fib->Header.Size;
  323 
  324                 if (aac_sync_fib(sc, command, 0, fib, size)) {
  325                         device_printf(sc->aac_dev,
  326                              "Error dumping block 0x%jx\n",
  327                              (uintmax_t)physical);
  328                         return (EIO);
  329                 }
  330 
  331                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
  332                     BUS_DMASYNC_POSTWRITE);
  333 
  334                 bus_dmamap_unload(sc->aac_buffer_dmat, dump_datamap);
  335 
  336                 length -= len;
  337                 offset += len;
  338                 virtual = (uint8_t *)virtual + len;
  339         }
  340 
  341         return (0);
  342 }
  343 
  344 /*
  345  * Handle completion of an I/O request.
  346  */
  347 void
  348 aac_biodone(struct bio *bio, const char *code)
  349 {
  350         struct buf *bp = bio->bio_buf;
  351         struct aac_disk *sc;
  352 
  353         sc = (struct aac_disk *)bio->bio_driver_info;
  354         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  355 
  356         devstat_end_transaction_buf(&sc->ad_stats, bp);
  357         if (bp->b_flags & B_ERROR) {
  358                 diskerr(bio, sc->ad_dev_t,
  359                         code, 0, 0);
  360         }
  361 
  362         biodone(bio);
  363 }
  364 
  365 /*
  366  * Stub only.
  367  */
  368 static int
  369 aac_disk_probe(device_t dev)
  370 {
  371 
  372         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  373 
  374         return (0);
  375 }
  376 
  377 /*
  378  * Attach a unit to the controller.
  379  */
  380 static int
  381 aac_disk_attach(device_t dev)
  382 {
  383         struct disk_info info;
  384         struct aac_disk *sc;
  385         
  386         sc = (struct aac_disk *)device_get_softc(dev);
  387         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  388 
  389         /* initialise our softc */
  390         sc->ad_controller =
  391             (struct aac_softc *)device_get_softc(device_get_parent(dev));
  392         sc->ad_container = device_get_ivars(dev);
  393         sc->ad_dev = dev;
  394 
  395         /*
  396          * require that extended translation be enabled - other drivers read the
  397          * disk!
  398          */
  399         sc->ad_size = sc->ad_container->co_mntobj.Capacity;
  400         if (sc->ad_controller->flags & AAC_FLAGS_LBA_64BIT)
  401                 sc->ad_size += (u_int64_t)
  402                         sc->ad_container->co_mntobj.CapacityHigh << 32;
  403         if (sc->ad_size >= (2 * 1024 * 1024)) {         /* 2GB */
  404                 sc->ad_heads = 255;
  405                 sc->ad_sectors = 63;
  406         } else if (sc->ad_size >= (1 * 1024 * 1024)) {  /* 1GB */
  407                 sc->ad_heads = 128;
  408                 sc->ad_sectors = 32;
  409         } else {
  410                 sc->ad_heads = 64;
  411                 sc->ad_sectors = 32;
  412         }
  413         sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
  414 
  415         device_printf(dev, "%juMB (%ju sectors)\n",
  416                       (intmax_t)sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
  417                       (intmax_t)sc->ad_size);
  418         devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
  419                           AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
  420                           DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 
  421                           DEVSTAT_PRIORITY_ARRAY);
  422 
  423         /* attach a generic disk device to ourselves */
  424         sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk,
  425                                    &aac_disk_ops);
  426         sc->ad_dev_t->si_drv1 = sc;
  427 
  428         sc->ad_dev_t->si_iosize_max = sc->ad_controller->aac_max_sectors << 9;
  429         sc->unit = device_get_unit(dev);
  430 
  431         /*
  432          * Set disk info, as it appears that all needed data is available already.
  433          * Setting the disk info will also cause the probing to start.
  434          */
  435         bzero(&info, sizeof(info));
  436         info.d_media_blksize= AAC_BLOCK_SIZE;           /* mandatory */
  437         info.d_media_blocks = sc->ad_size;
  438 
  439         info.d_type = DTYPE_ESDI;                       /* optional */
  440         info.d_secpertrack   = sc->ad_sectors;
  441         info.d_nheads   = sc->ad_heads;
  442         info.d_ncylinders = sc->ad_cylinders;
  443         info.d_secpercyl  = sc->ad_sectors * sc->ad_heads;
  444 
  445         disk_setdiskinfo(&sc->ad_disk, &info);
  446 
  447         return (0);
  448 }
  449 
  450 /*
  451  * Disconnect ourselves from the system.
  452  */
  453 static int
  454 aac_disk_detach(device_t dev)
  455 {
  456         struct aac_disk *sc;
  457 
  458         sc = (struct aac_disk *)device_get_softc(dev);
  459         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
  460 
  461         if (sc->ad_flags & AAC_DISK_OPEN)
  462                 return(EBUSY);
  463 
  464         devstat_remove_entry(&sc->ad_stats);
  465         disk_destroy(&sc->ad_disk);
  466 
  467         return(0);
  468 }

Cache object: b8f88d24ebbb258624fc97c69e2bc2e6


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