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/powerpc/ps3/ps3disk.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) 2011 glevand (geoffrey.levand@mail.ru)
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/sysctl.h>
   35 #include <sys/disk.h>
   36 #include <sys/bio.h>
   37 #include <sys/bus.h>
   38 #include <sys/conf.h>
   39 #include <sys/kernel.h>
   40 #include <sys/kthread.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/module.h>
   44 #include <sys/mutex.h>
   45 
   46 #include <vm/vm.h>
   47 #include <vm/pmap.h>
   48 
   49 #include <machine/pio.h>
   50 #include <machine/bus.h>
   51 #include <machine/platform.h>
   52 #include <machine/resource.h>
   53 #include <sys/bus.h>
   54 #include <sys/rman.h>
   55 
   56 #include <geom/geom_disk.h>
   57 
   58 #include "ps3bus.h"
   59 #include "ps3-hvcall.h"
   60 
   61 #define PS3DISK_LOCK_INIT(_sc)          \
   62         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3disk", MTX_DEF)
   63 #define PS3DISK_LOCK_DESTROY(_sc)       mtx_destroy(&_sc->sc_mtx);
   64 #define PS3DISK_LOCK(_sc)               mtx_lock(&(_sc)->sc_mtx)
   65 #define PS3DISK_UNLOCK(_sc)             mtx_unlock(&(_sc)->sc_mtx)
   66 #define PS3DISK_ASSERT_LOCKED(_sc)      mtx_assert(&_sc->sc_mtx, MA_OWNED);
   67 #define PS3DISK_ASSERT_UNLOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
   68 
   69 #define LV1_STORAGE_ATA_HDDOUT          0x23
   70 
   71 static SYSCTL_NODE(_hw, OID_AUTO, ps3disk, CTLFLAG_RD, 0,
   72     "PS3 Disk driver parameters");
   73 
   74 #ifdef PS3DISK_DEBUG
   75 static int ps3disk_debug = 0;
   76 SYSCTL_INT(_hw_ps3disk, OID_AUTO, debug, CTLFLAG_RW, &ps3disk_debug,
   77         0, "control debugging printfs");
   78 TUNABLE_INT("hw.ps3disk.debug", &ps3disk_debug);
   79 enum {
   80         PS3DISK_DEBUG_INTR      = 0x00000001,
   81         PS3DISK_DEBUG_TASK      = 0x00000002,
   82         PS3DISK_DEBUG_READ      = 0x00000004,
   83         PS3DISK_DEBUG_WRITE     = 0x00000008,
   84         PS3DISK_DEBUG_FLUSH     = 0x00000010,
   85         PS3DISK_DEBUG_ANY       = 0xffffffff
   86 };
   87 #define DPRINTF(sc, m, fmt, ...)                                \
   88 do {                                                            \
   89         if (sc->sc_debug & (m))                                 \
   90                 printf(fmt, __VA_ARGS__);                       \
   91 } while (0)
   92 #else
   93 #define DPRINTF(sc, m, fmt, ...)
   94 #endif
   95 
   96 struct ps3disk_region {
   97         uint64_t r_id;
   98         uint64_t r_start;
   99         uint64_t r_size;
  100         uint64_t r_flags;
  101 };
  102 
  103 struct ps3disk_softc {
  104         device_t sc_dev;
  105 
  106         struct mtx sc_mtx;
  107 
  108         uint64_t sc_blksize;
  109         uint64_t sc_nblocks;
  110 
  111         uint64_t sc_nregs;
  112         struct ps3disk_region *sc_reg;
  113 
  114         int sc_irqid;
  115         struct resource *sc_irq;
  116         void *sc_irqctx;
  117 
  118         struct disk **sc_disk;
  119 
  120         struct bio_queue_head sc_bioq;
  121         struct bio_queue_head sc_deferredq;
  122         struct proc *sc_task;   
  123 
  124         bus_dma_tag_t sc_dmatag;
  125 
  126         int sc_running;
  127         int sc_debug;
  128 };
  129 
  130 static int ps3disk_open(struct disk *dp);
  131 static int ps3disk_close(struct disk *dp);
  132 static void ps3disk_strategy(struct bio *bp);
  133 
  134 static void ps3disk_task(void *arg);
  135 static void ps3disk_intr(void *arg);
  136 static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc);
  137 static int ps3disk_enum_regions(struct ps3disk_softc *sc);
  138 static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
  139     int error);
  140 
  141 static void ps3disk_sysctlattach(struct ps3disk_softc *sc);
  142 
  143 static MALLOC_DEFINE(M_PS3DISK, "ps3disk", "PS3 Disk");
  144 
  145 static int
  146 ps3disk_probe(device_t dev)
  147 {
  148         if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
  149             ps3bus_get_devtype(dev) != PS3_DEVTYPE_DISK)
  150                 return (ENXIO);
  151 
  152         device_set_desc(dev, "Playstation 3 Disk");
  153 
  154         return (BUS_PROBE_SPECIFIC);
  155 }
  156 
  157 static int
  158 ps3disk_attach(device_t dev)
  159 {
  160         struct ps3disk_softc *sc;
  161         struct disk *d;
  162         intmax_t mb;
  163         uint64_t junk;
  164         char unit;
  165         int i, err;
  166 
  167         sc = device_get_softc(dev);
  168         sc->sc_dev = dev;
  169 
  170         PS3DISK_LOCK_INIT(sc);
  171 
  172         err = ps3disk_get_disk_geometry(sc);
  173         if (err) {
  174                 device_printf(dev, "Could not get disk geometry\n");
  175                 err = ENXIO;
  176                 goto fail_destroy_lock;
  177         }
  178 
  179         device_printf(dev, "block size %lu total blocks %lu\n",
  180             sc->sc_blksize, sc->sc_nblocks);
  181 
  182         err = ps3disk_enum_regions(sc);
  183         if (err) {
  184                 device_printf(dev, "Could not enumerate disk regions\n");
  185                 err = ENXIO;
  186                 goto fail_destroy_lock;
  187         }
  188 
  189         device_printf(dev, "Found %lu regions\n", sc->sc_nregs);
  190 
  191         if (!sc->sc_nregs) {
  192                 err = ENXIO;
  193                 goto fail_destroy_lock;
  194         }
  195 
  196         /* Setup interrupt handler */
  197         sc->sc_irqid = 0;
  198         sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
  199             RF_ACTIVE);
  200         if (!sc->sc_irq) {
  201                 device_printf(dev, "Could not allocate IRQ\n");
  202                 err = ENXIO;
  203                 goto fail_free_regions;
  204         }
  205 
  206         err = bus_setup_intr(dev, sc->sc_irq,
  207             INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
  208             NULL, ps3disk_intr, sc, &sc->sc_irqctx);
  209         if (err) {
  210                 device_printf(dev, "Could not setup IRQ\n");
  211                 err = ENXIO;
  212                 goto fail_release_intr;
  213         }
  214 
  215         /* Setup DMA */
  216         err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
  217             BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
  218             BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
  219             busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
  220         if (err) {
  221                 device_printf(dev, "Could not create DMA tag\n");
  222                 err = ENXIO;
  223                 goto fail_teardown_intr;
  224         }
  225 
  226         /* Setup disks */
  227 
  228         sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *),
  229             M_PS3DISK, M_ZERO | M_WAITOK);
  230         if (!sc->sc_disk) {
  231                 device_printf(dev, "Could not allocate disk(s)\n");
  232                 err = ENOMEM;
  233                 goto fail_teardown_intr;
  234         }
  235 
  236         for (i = 0; i < sc->sc_nregs; i++) {
  237                 struct ps3disk_region *rp = &sc->sc_reg[i];
  238 
  239                 d = sc->sc_disk[i] = disk_alloc();
  240                 d->d_open = ps3disk_open;
  241                 d->d_close = ps3disk_close;
  242                 d->d_strategy = ps3disk_strategy;
  243                 d->d_name = "ps3disk";
  244                 d->d_drv1 = sc;
  245                 d->d_maxsize = PAGE_SIZE;
  246                 d->d_sectorsize = sc->sc_blksize;
  247                 d->d_unit = i;
  248                 d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize;
  249                 d->d_flags |= DISKFLAG_CANFLUSHCACHE;
  250 
  251                 mb = d->d_mediasize >> 20;
  252                 unit = 'M';
  253                 if (mb >= 10240) {
  254                         unit = 'G';
  255                         mb /= 1024;
  256                 }
  257 
  258                 /* Test to see if we can read this region */
  259                 err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit,
  260                     0, 0, rp->r_flags, 0, &junk);
  261                 device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit,
  262                     (err == LV1_DENIED_BY_POLICY) ?  " (hypervisor protected)"
  263                     : "");
  264 
  265                 if (err != LV1_DENIED_BY_POLICY)
  266                         disk_create(d, DISK_VERSION);
  267         }
  268         err = 0;
  269 
  270         bioq_init(&sc->sc_bioq);
  271         bioq_init(&sc->sc_deferredq);
  272         kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk");
  273 
  274         ps3disk_sysctlattach(sc);
  275         sc->sc_running = 1;
  276         return (0);
  277 
  278 fail_teardown_intr:
  279         bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
  280 fail_release_intr:
  281         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
  282 fail_free_regions:
  283         free(sc->sc_reg, M_PS3DISK);
  284 fail_destroy_lock:
  285         PS3DISK_LOCK_DESTROY(sc);
  286         return (err);
  287 }
  288 
  289 static int
  290 ps3disk_detach(device_t dev)
  291 {
  292         struct ps3disk_softc *sc = device_get_softc(dev);
  293         int i;
  294 
  295         for (i = 0; i < sc->sc_nregs; i++)
  296                 disk_destroy(sc->sc_disk[i]);
  297 
  298         bus_dma_tag_destroy(sc->sc_dmatag);
  299 
  300         bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
  301         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
  302 
  303         free(sc->sc_disk, M_PS3DISK);
  304         free(sc->sc_reg, M_PS3DISK);
  305 
  306         PS3DISK_LOCK_DESTROY(sc);
  307 
  308         return (0);
  309 }
  310 
  311 static int
  312 ps3disk_open(struct disk *dp)
  313 {
  314         return (0);
  315 }
  316 
  317 static int
  318 ps3disk_close(struct disk *dp)
  319 {
  320         return (0);
  321 }
  322 
  323 /* Process deferred blocks */
  324 static void
  325 ps3disk_task(void *arg)
  326 {
  327         struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
  328         struct bio *bp;
  329 
  330         
  331         while (1) {
  332                 kproc_suspend_check(sc->sc_task);
  333                 tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10);
  334 
  335                 PS3DISK_LOCK(sc);
  336                 bp = bioq_takefirst(&sc->sc_deferredq);
  337                 PS3DISK_UNLOCK(sc);
  338 
  339                 if (bp == NULL)
  340                         continue;
  341 
  342                 if (bp->bio_driver1 != NULL) {
  343                         bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
  344                             bp->bio_driver1);
  345                         bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
  346                             bp->bio_driver1);
  347                 }
  348 
  349                 ps3disk_strategy(bp);
  350         }
  351 
  352         kproc_exit(0);
  353 }
  354 
  355 static void
  356 ps3disk_strategy(struct bio *bp)
  357 {
  358         struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
  359         int err;
  360 
  361         if (sc == NULL) {
  362                 bp->bio_flags |= BIO_ERROR;
  363                 bp->bio_error = EINVAL;
  364                 biodone(bp);
  365                 return;
  366         }
  367 
  368         PS3DISK_LOCK(sc);
  369         bp->bio_resid = bp->bio_bcount;
  370         bioq_insert_tail(&sc->sc_bioq, bp);
  371 
  372         DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n",
  373             __func__, bp->bio_cmd);
  374 
  375         err = 0;
  376         if (bp->bio_cmd == BIO_FLUSH) {
  377                 bp->bio_driver1 = 0;
  378                 err = lv1_storage_send_device_command(
  379                     ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT,
  380                     0, 0, 0, 0, (uint64_t *)&bp->bio_driver2);
  381                 if (err == LV1_BUSY)
  382                         err = EAGAIN;
  383         } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
  384                 if (bp->bio_bcount % sc->sc_blksize != 0) {
  385                         err = EINVAL;
  386                 } else {
  387                         bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
  388                             (bus_dmamap_t *)(&bp->bio_driver1));
  389                         err = bus_dmamap_load(sc->sc_dmatag,
  390                             (bus_dmamap_t)(bp->bio_driver1), bp->bio_data,
  391                             bp->bio_bcount, ps3disk_transfer, bp, 0);
  392                         if (err == EINPROGRESS)
  393                                 err = 0;
  394                 }
  395         } else {
  396                 err = EINVAL;
  397         }
  398 
  399         if (err == EAGAIN) {
  400                 bioq_remove(&sc->sc_bioq, bp);
  401                 bioq_insert_tail(&sc->sc_deferredq, bp);
  402         } else if (err != 0) {
  403                 bp->bio_error = err;
  404                 bp->bio_flags |= BIO_ERROR;
  405                 bioq_remove(&sc->sc_bioq, bp);
  406                 disk_err(bp, "hard error", -1, 1);
  407                 biodone(bp);
  408         }
  409 
  410         PS3DISK_UNLOCK(sc);
  411 }
  412 
  413 static void
  414 ps3disk_intr(void *arg)
  415 {
  416         struct ps3disk_softc *sc = (struct ps3disk_softc *) arg;
  417         device_t dev = sc->sc_dev;
  418         uint64_t devid = ps3bus_get_device(dev);
  419         struct bio *bp;
  420         uint64_t tag, status;
  421 
  422         if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
  423                 return;
  424         
  425         PS3DISK_LOCK(sc);
  426 
  427         DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx "
  428             "status 0x%016lx\n", __func__, tag, status);
  429 
  430         /* Locate the matching request */
  431         TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) {
  432                 if ((uint64_t)bp->bio_driver2 != tag)
  433                         continue;
  434 
  435                 if (status != 0) {
  436                         device_printf(sc->sc_dev, "%s error (%#lx)\n",
  437                             (bp->bio_cmd == BIO_READ) ? "Read" : "Write",
  438                             status);
  439                         bp->bio_error = EIO;
  440                         bp->bio_flags |= BIO_ERROR;
  441                 } else {
  442                         bp->bio_error = 0;
  443                         bp->bio_resid = 0;
  444                         bp->bio_flags |= BIO_DONE;
  445                 }
  446 
  447                 if (bp->bio_driver1 != NULL) {
  448                         if (bp->bio_cmd == BIO_READ)
  449                                 bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t)
  450                                     bp->bio_driver1, BUS_DMASYNC_POSTREAD);
  451                         bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
  452                             bp->bio_driver1);
  453                         bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
  454                             bp->bio_driver1);
  455                 }
  456 
  457                 bioq_remove(&sc->sc_bioq, bp);
  458                 biodone(bp);
  459                 break;
  460         }
  461 
  462         if (bioq_first(&sc->sc_deferredq) != NULL)
  463                 wakeup(&sc->sc_deferredq);
  464 
  465         PS3DISK_UNLOCK(sc);
  466 }
  467 
  468 static int
  469 ps3disk_get_disk_geometry(struct ps3disk_softc *sc)
  470 {
  471         device_t dev = sc->sc_dev;
  472         uint64_t bus_index = ps3bus_get_busidx(dev);
  473         uint64_t dev_index = ps3bus_get_devidx(dev);
  474         uint64_t junk;
  475         int err;
  476 
  477         err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  478             (lv1_repository_string("bus") >> 32) | bus_index,
  479             lv1_repository_string("dev") | dev_index,
  480             lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk);
  481         if (err) {
  482                 device_printf(dev, "Could not get block size (0x%08x)\n", err);
  483                 return (ENXIO);
  484         }
  485 
  486         err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  487             (lv1_repository_string("bus") >> 32) | bus_index,
  488             lv1_repository_string("dev") | dev_index,
  489             lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk);
  490         if (err) {
  491                 device_printf(dev, "Could not get total number of blocks "
  492                     "(0x%08x)\n", err);
  493                 err = ENXIO;
  494         }
  495 
  496         return (err);
  497 }
  498 
  499 static int
  500 ps3disk_enum_regions(struct ps3disk_softc *sc)
  501 {
  502         device_t dev = sc->sc_dev;
  503         uint64_t bus_index = ps3bus_get_busidx(dev);
  504         uint64_t dev_index = ps3bus_get_devidx(dev);
  505         uint64_t junk;
  506         int i, err;
  507 
  508         /* Read number of regions */
  509 
  510         err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  511             (lv1_repository_string("bus") >> 32) | bus_index,
  512             lv1_repository_string("dev") | dev_index,
  513             lv1_repository_string("n_regs"), 0, &sc->sc_nregs, &junk);
  514         if (err) {
  515                 device_printf(dev, "Could not get number of regions (0x%08x)\n",
  516                     err);
  517                 err = ENXIO;
  518                 goto fail;
  519         }
  520 
  521         if (!sc->sc_nregs)
  522                 return 0;
  523 
  524         sc->sc_reg = malloc(sc->sc_nregs * sizeof(struct ps3disk_region),
  525             M_PS3DISK, M_ZERO | M_WAITOK);
  526         if (!sc->sc_reg) {
  527                 err = ENOMEM;
  528                 goto fail;
  529         }
  530 
  531         /* Setup regions */
  532 
  533         for (i = 0; i < sc->sc_nregs; i++) {
  534                 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  535                     (lv1_repository_string("bus") >> 32) | bus_index,
  536                     lv1_repository_string("dev") | dev_index,
  537                     lv1_repository_string("region") | i,
  538                     lv1_repository_string("id"), &sc->sc_reg[i].r_id, &junk);
  539                 if (err) {
  540                         device_printf(dev, "Could not get region id (0x%08x)\n",
  541                             err);
  542                         err = ENXIO;
  543                         goto fail;
  544                 }
  545 
  546                 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  547                     (lv1_repository_string("bus") >> 32) | bus_index,
  548                     lv1_repository_string("dev") | dev_index,
  549                     lv1_repository_string("region") | i,
  550                     lv1_repository_string("start"), &sc->sc_reg[i].r_start,
  551                     &junk);
  552                 if (err) {
  553                         device_printf(dev, "Could not get region start "
  554                             "(0x%08x)\n", err);
  555                         err = ENXIO;
  556                         goto fail;
  557                 }
  558 
  559                 err = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
  560                     (lv1_repository_string("bus") >> 32) | bus_index,
  561                     lv1_repository_string("dev") | dev_index,
  562                     lv1_repository_string("region") | i,
  563                     lv1_repository_string("size"), &sc->sc_reg[i].r_size,
  564                     &junk);
  565                 if (err) {
  566                         device_printf(dev, "Could not get region size "
  567                             "(0x%08x)\n", err);
  568                         err = ENXIO;
  569                         goto fail;
  570                 }
  571 
  572                 if (i == 0)
  573                         sc->sc_reg[i].r_flags = 0x2;
  574                 else
  575                         sc->sc_reg[i].r_flags = 0;
  576         }
  577 
  578         return (0);
  579 
  580 fail:
  581 
  582         sc->sc_nregs = 0;
  583         if (sc->sc_reg)
  584                 free(sc->sc_reg, M_PS3DISK);
  585 
  586         return (err);
  587 }
  588 
  589 static void
  590 ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  591 {
  592         struct bio *bp = (struct bio *)(arg);
  593         struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1;
  594         struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit];
  595         uint64_t devid = ps3bus_get_device(sc->sc_dev);
  596         uint64_t block;
  597         int i, err;
  598 
  599         /* Locks already held by busdma */
  600         PS3DISK_ASSERT_LOCKED(sc);
  601 
  602         if (error) {
  603                 bp->bio_error = error;
  604                 bp->bio_flags |= BIO_ERROR;
  605                 bioq_remove(&sc->sc_bioq, bp);
  606                 biodone(bp);
  607                 return;
  608         }
  609 
  610         block = bp->bio_pblkno;
  611         for (i = 0; i < nsegs; i++) {
  612                 KASSERT((segs[i].ds_len % sc->sc_blksize) == 0,
  613                     ("DMA fragments not blocksize multiples"));
  614 
  615                 if (bp->bio_cmd == BIO_READ) {
  616                         err = lv1_storage_read(devid, rp->r_id,
  617                             block, segs[i].ds_len/sc->sc_blksize,
  618                             rp->r_flags, segs[i].ds_addr,
  619                             (uint64_t *)&bp->bio_driver2);
  620                 } else {
  621                         bus_dmamap_sync(sc->sc_dmatag,
  622                             (bus_dmamap_t)bp->bio_driver1,
  623                             BUS_DMASYNC_PREWRITE);
  624                         err = lv1_storage_write(devid, rp->r_id,
  625                             block, segs[i].ds_len/sc->sc_blksize,
  626                             rp->r_flags, segs[i].ds_addr,
  627                             (uint64_t *)&bp->bio_driver2);
  628                 }
  629 
  630                 if (err) {
  631                         if (err == LV1_BUSY) {
  632                                 bioq_remove(&sc->sc_bioq, bp);
  633                                 bioq_insert_tail(&sc->sc_deferredq, bp);
  634                         } else {
  635                                 bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t)
  636                                     bp->bio_driver1);
  637                                 bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t)
  638                                     bp->bio_driver1);
  639                                 device_printf(sc->sc_dev, "Could not read "
  640                                     "sectors (0x%08x)\n", err);
  641                                 bp->bio_error = EINVAL;
  642                                 bp->bio_flags |= BIO_ERROR;
  643                                 bioq_remove(&sc->sc_bioq, bp);
  644                                 biodone(bp);
  645                         }
  646 
  647                         break;
  648                 }
  649 
  650                 DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n",
  651                     __func__, sc->sc_bounce_tag);
  652         }
  653 }
  654 
  655 #ifdef PS3DISK_DEBUG
  656 static int
  657 ps3disk_sysctl_debug(SYSCTL_HANDLER_ARGS)
  658 {
  659         struct ps3disk_softc *sc = arg1;
  660         int debug, error;
  661 
  662         debug = sc->sc_debug;
  663 
  664         error = sysctl_handle_int(oidp, &debug, 0, req);
  665         if (error || !req->newptr)
  666                 return error;
  667 
  668         sc->sc_debug = debug;
  669 
  670         return 0;
  671 }
  672 #endif
  673 
  674 static void
  675 ps3disk_sysctlattach(struct ps3disk_softc *sc)
  676 {
  677 #ifdef PS3DISK_DEBUG
  678         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
  679         struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
  680 
  681         sc->sc_debug = ps3disk_debug;
  682 
  683         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  684                 "debug", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
  685                 ps3disk_sysctl_debug, "I", "control debugging printfs");
  686 #endif
  687 }
  688 
  689 static device_method_t ps3disk_methods[] = {
  690         DEVMETHOD(device_probe,         ps3disk_probe),
  691         DEVMETHOD(device_attach,        ps3disk_attach),
  692         DEVMETHOD(device_detach,        ps3disk_detach),
  693         {0, 0},
  694 };
  695 
  696 static driver_t ps3disk_driver = {
  697         "ps3disk",
  698         ps3disk_methods,
  699         sizeof(struct ps3disk_softc),
  700 };
  701 
  702 static devclass_t ps3disk_devclass;
  703 
  704 DRIVER_MODULE(ps3disk, ps3bus, ps3disk_driver, ps3disk_devclass, 0, 0);

Cache object: 64a71376cc2cf4f76ffa95ca4e49bf3b


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