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

Cache object: dd5ef160c3f06a4e5a6e2e3d8fba3adb


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