Author: nwhitehorn
Date: Sun Aug 14 00:20:37 2011
New Revision: 224857
URL: http://svn.freebsd.org/changeset/base/224857

Log:
  Add support for the Blu-Ray drive found in the Sony Playstation 3 and fix
  some realted minor bugs in PS3 internal storage support.
  
  Submitted by: glevand <geoffrey.lev...@mail.ru>
  Approved by:  re (bz)

Added:
  head/sys/boot/powerpc/ps3/ps3cdrom.c   (contents, props changed)
  head/sys/powerpc/ps3/ps3cdrom.c   (contents, props changed)
Modified:
  head/sys/boot/powerpc/ps3/Makefile
  head/sys/boot/powerpc/ps3/conf.c
  head/sys/boot/powerpc/ps3/devicename.c
  head/sys/boot/powerpc/ps3/lv1call.S
  head/sys/boot/powerpc/ps3/lv1call.h
  head/sys/boot/powerpc/ps3/main.c
  head/sys/boot/powerpc/ps3/ps3stor.c
  head/sys/conf/files.powerpc

Modified: head/sys/boot/powerpc/ps3/Makefile
==============================================================================
--- head/sys/boot/powerpc/ps3/Makefile  Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/Makefile  Sun Aug 14 00:20:37 2011        
(r224857)
@@ -10,7 +10,8 @@ INSTALLFLAGS= -b
 
 # Architecture-specific loader code
 SRCS=          start.S conf.c metadata.c vers.c main.c devicename.c 
ppc64_elf_freebsd.c
-SRCS+=         lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c 
ps3stor.c ps3disk.c
+SRCS+=         lv1call.S ps3cons.c font.h ps3mmu.c ps3net.c ps3repo.c \
+               ps3stor.c ps3disk.c ps3cdrom.c
 SRCS+=         ucmpdi2.c
 
 LOADER_DISK_SUPPORT?=  yes

Modified: head/sys/boot/powerpc/ps3/conf.c
==============================================================================
--- head/sys/boot/powerpc/ps3/conf.c    Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/conf.c    Sun Aug 14 00:20:37 2011        
(r224857)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #endif
 
 extern struct devsw ps3disk;
+extern struct devsw ps3cdrom;
 
 /*
  * We could use linker sets for some or all of these, but
@@ -47,7 +48,10 @@ extern struct devsw ps3disk;
 
 /* Exported for libstand */
 struct devsw *devsw[] = {
-#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT)
+#if defined(LOADER_CD9660_SUPPORT)
+    &ps3cdrom,
+#endif
+#if defined(LOADER_DISK_SUPPORT)
     &ps3disk,
 #endif
 #if defined(LOADER_NET_SUPPORT)

Modified: head/sys/boot/powerpc/ps3/devicename.c
==============================================================================
--- head/sys/boot/powerpc/ps3/devicename.c      Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/devicename.c      Sun Aug 14 00:20:37 2011        
(r224857)
@@ -157,6 +157,7 @@ ps3_parsedev(struct ps3_devdesc **dev, c
                break;
 
        case DEVT_NET:
+       case DEVT_CD:
                /*
                 * PS3 only has one network interface (well, two, but
                 * netbooting over wireless is not something I'm going
@@ -213,6 +214,7 @@ ps3_fmtdev(void *vdev)
                break;
 
        case DEVT_NET:
+       case DEVT_CD:
                sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
                break;
        }

Modified: head/sys/boot/powerpc/ps3/lv1call.S
==============================================================================
--- head/sys/boot/powerpc/ps3/lv1call.S Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/lv1call.S Sun Aug 14 00:20:37 2011        
(r224857)
@@ -307,14 +307,8 @@ lv1_storage_read:
        sldi    %r6,%r9,32
        clrldi  %r7,%r10,32
        or      %r6,%r6,%r7
-       lwz     %r7,8(%r1)
-       lwz     %r8,12(%r1)
-       sldi    %r7,%r7,32
-       or      %r7,%r7,%r8
-       lwz     %r8,16(%r1)
-       lwz     %r9,20(%r1)
-       sldi    %r8,%r8,32
-       or      %r8,%r8,%r9
+       ld      %r7,8(%r1)
+       ld      %r8,16(%r1)
 
        li      %r11,245
        hc

Modified: head/sys/boot/powerpc/ps3/lv1call.h
==============================================================================
--- head/sys/boot/powerpc/ps3/lv1call.h Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/lv1call.h Sun Aug 14 00:20:37 2011        
(r224857)
@@ -69,12 +69,12 @@ int lv1_net_stop_tx_dma(int bus, int dev
 int lv1_net_stop_rx_dma(int bus, int dev, int);
 
 int lv1_get_repository_node_value(uint64_t lpar_id, uint64_t n1, uint64_t n2,
-       uint64_t n3, uint64_t n4, uint64_t *v1, uint64_t *v2);
+    uint64_t n3, uint64_t n4, uint64_t *v1, uint64_t *v2);
 
-int lv1_storage_read(uint64_t dev_id, uint64_t region_id,
-       uint64_t start_sector, uint64_t sector_count,
-       uint64_t flags, uint64_t buf, uint64_t *tag);
-int lv1_storage_check_async_status(uint64_t dev_id, uint64_t tag, uint64_t 
*status);
+int lv1_storage_read(uint64_t dev_id, uint64_t region_id, uint64_t 
start_sector,
+    uint64_t sector_count, uint64_t flags, uint64_t buf, uint64_t *tag);
+int lv1_storage_check_async_status(uint64_t dev_id, uint64_t tag,
+    uint64_t *status);
 
 #endif
 

Modified: head/sys/boot/powerpc/ps3/main.c
==============================================================================
--- head/sys/boot/powerpc/ps3/main.c    Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/main.c    Sun Aug 14 00:20:37 2011        
(r224857)
@@ -92,11 +92,17 @@ main(void)
                        }
                }
 
-               printf("\nDevice: %s\n", devsw[i]->dv_name);
-
                currdev.d_dev = devsw[i];
                currdev.d_type = currdev.d_dev->dv_type;
 
+               if (strcmp(devsw[i]->dv_name, "cd") == 0) {
+                       f.f_devdata = &currdev;
+                       currdev.d_unit = 0;
+
+                       if (devsw[i]->dv_open(&f, &currdev) == 0)
+                               break;
+               }
+
                if (strcmp(devsw[i]->dv_name, "disk") == 0) {
                        f.f_devdata = &currdev;
                        currdev.d_unit = 3;
@@ -113,6 +119,8 @@ main(void)
 
        if (devsw[i] == NULL)
                panic("No boot device found!");
+       else
+               printf("Boot device: %s\n", devsw[i]->dv_name);
 
        /*
         * Get timebase at boot.

Added: head/sys/boot/powerpc/ps3/ps3cdrom.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/boot/powerpc/ps3/ps3cdrom.c        Sun Aug 14 00:20:37 2011        
(r224857)
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (C) 2011 glevand <geoffrey.lev...@mail.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <machine/stdarg.h>
+#include <stand.h>
+
+#include "bootstrap.h"
+#include "ps3bus.h"
+#include "ps3devdesc.h"
+#include "ps3stor.h"
+
+#define dev_printf(dev, fmt, args...)  \
+       printf("%s%d: " fmt "\n", dev->d_dev->dv_name, dev->d_unit, ##args)
+
+#ifdef CD_DEBUG
+#define DEBUG(fmt, args...)            printf("%s:%d: " fmt "\n", __func__, 
__LINE__, ##args)
+#else
+#define DEBUG(fmt, args...)
+#endif
+
+static int ps3cdrom_init(void);
+static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk,
+       size_t size, char *buf, size_t *rsize);
+static int ps3cdrom_open(struct open_file *f, ...);
+static int ps3cdrom_close(struct open_file *f);
+static void ps3cdrom_print(int verbose);
+
+struct devsw ps3cdrom = {
+       "cd",
+       DEVT_CD,
+       ps3cdrom_init,
+       ps3cdrom_strategy,
+       ps3cdrom_open,
+       ps3cdrom_close,
+       noioctl,
+       ps3cdrom_print,
+};
+
+static struct ps3_stordev stor_dev;
+
+static int ps3cdrom_init(void)
+{
+       int err;
+
+       err = ps3stor_setup(&stor_dev, PS3_DEV_TYPE_STOR_CDROM);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk,
+       size_t size, char *buf, size_t *rsize)
+{
+       struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata;
+       int err;
+
+       DEBUG("d_unit=%u dblk=%llu size=%u", dev->d_unit, dblk, size);
+
+       if (flag != F_READ) {
+               dev_printf(dev, "write operation is not supported!");
+               return EROFS;
+       }
+
+       if (dblk % (stor_dev.sd_blksize / DEV_BSIZE) != 0)
+               return EINVAL;
+
+       dblk /= (stor_dev.sd_blksize / DEV_BSIZE);
+
+       if (size % stor_dev.sd_blksize) {
+               dev_printf(dev,
+                   "size=%u is not multiple of device block size=%llu", size,
+                   stor_dev.sd_blksize);
+               return EINVAL;
+       }
+
+       if (rsize)
+               *rsize = 0;
+
+       err = ps3stor_read_sectors(&stor_dev, dev->d_unit, dblk,
+               size / stor_dev.sd_blksize, 0, buf);
+
+       if (!err && rsize)
+               *rsize = size;
+
+       if (err)
+               dev_printf(dev,
+                   "read operation failed dblk=%llu size=%d err=%d", dblk,
+                   size, err);
+
+       return err;
+}
+
+static int ps3cdrom_open(struct open_file *f, ...)
+{
+       char buf[2048];
+       va_list ap;
+       struct ps3_devdesc *dev;
+       int err;
+
+       va_start(ap, f);
+       dev = va_arg(ap, struct ps3_devdesc *);
+       va_end(ap);
+
+       if (dev->d_unit > 0) {
+               dev_printf(dev, "attempt to open nonexistent disk");
+               return ENXIO;
+       }
+
+       err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 16, 1, 0, buf);
+       if (err)
+               return EIO;
+
+       /* Do not attach if not ISO9660 (workaround for buggy firmware) */
+       if (memcmp(buf, "\001CD001", 6) != 0)
+               return EIO;
+
+       return 0;
+}
+
+static int ps3cdrom_close(struct open_file *f)
+{
+       return 0;
+}
+
+static void ps3cdrom_print(int verbose)
+{
+}

Modified: head/sys/boot/powerpc/ps3/ps3stor.c
==============================================================================
--- head/sys/boot/powerpc/ps3/ps3stor.c Sat Aug 13 23:34:17 2011        
(r224856)
+++ head/sys/boot/powerpc/ps3/ps3stor.c Sun Aug 14 00:20:37 2011        
(r224857)
@@ -52,35 +52,39 @@ int ps3stor_setup(struct ps3_stordev *sd
        if (err)
                goto out;
 
-       err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx, 
&sd->sd_devid);
+       err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx,
+           &sd->sd_devid);
        if (err)
                goto out;
 
-       err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx, 
&sd->sd_blksize);
+       err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx,
+           &sd->sd_blksize);
        if (err)
                goto out;
 
-       err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx, 
&sd->sd_nblocks);
+       err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx,
+           &sd->sd_nblocks);
        if (err)
                goto out;
 
-       err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx, 
&sd->sd_nregs);
+       err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx,
+           &sd->sd_nregs);
        if (err)
                goto out;
 
        for (i = 0; i < sd->sd_nregs; i++) {
-               err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx, 
i,
-                       &sd->sd_regs[i].sr_id);
+               err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx,
+                   i, &sd->sd_regs[i].sr_id);
                if (err)
                        goto out;
 
-               err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx, 
sd->sd_devidx, i,
-                       &sd->sd_regs[i].sr_start);
+               err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx,
+                   sd->sd_devidx, i, &sd->sd_regs[i].sr_start);
                if (err)
                        goto out;
 
-               err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx, 
sd->sd_devidx, i,
-                       &sd->sd_regs[i].sr_size);
+               err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx,
+                   sd->sd_devidx, i, &sd->sd_regs[i].sr_size);
                if (err)
                        goto out;
        }
@@ -109,19 +113,20 @@ out:
        return err;
 }
 
+static char dma_buf[2048] __aligned(2048);
+
 int ps3stor_read_sectors(struct ps3_stordev *sd, int regidx,
         uint64_t start_sector, uint64_t sector_count, uint64_t flags, char 
*buf)
 {
 #define MIN(a, b)                      ((a) <= (b) ? (a) : (b))
-#define BOUNCE_SECTORS                 4
+#define BOUNCE_SECTORS                 (sizeof(dma_buf) / sd->sd_blksize)
 #define ASYNC_STATUS_POLL_PERIOD       100 /* microseconds */
 
        struct ps3_storreg *reg = &sd->sd_regs[regidx];
-       char dma_buf[sd->sd_blksize * BOUNCE_SECTORS];
        uint64_t nleft, nread, nsectors;
        uint64_t tag, status;
        unsigned int timeout;
-       int err;
+       int err = 0;
 
        nleft = sector_count;
        nread = 0;
@@ -129,8 +134,9 @@ int ps3stor_read_sectors(struct ps3_stor
        while (nleft) {
                nsectors = MIN(nleft, BOUNCE_SECTORS);
 
-               err = lv1_storage_read(sd->sd_devid, reg->sr_id, start_sector + 
nread, nsectors,
-                       flags, (uint32_t) dma_buf, &tag);
+               err = lv1_storage_read(sd->sd_devid, reg->sr_id,
+                   start_sector + nread, nsectors, flags, (uint32_t)dma_buf,
+                   &tag);
                if (err)
                        return err;
 
@@ -140,7 +146,8 @@ int ps3stor_read_sectors(struct ps3_stor
                        if (timeout < ASYNC_STATUS_POLL_PERIOD)
                                return ETIMEDOUT;
 
-                       err = lv1_storage_check_async_status(sd->sd_devid, tag, 
&status);
+                       err = lv1_storage_check_async_status(sd->sd_devid, tag,
+                           &status);
                        if (!err && !status)
                                break;
 
@@ -148,12 +155,16 @@ int ps3stor_read_sectors(struct ps3_stor
                        timeout -= ASYNC_STATUS_POLL_PERIOD;
                }
 
-               memcpy(buf + nread * sd->sd_blksize, (u_char *) dma_buf, 
nsectors * sd->sd_blksize);
+               if (status != 0)
+                       return EIO;
+
+               memcpy(buf + nread * sd->sd_blksize, (u_char *)dma_buf,
+                   nsectors * sd->sd_blksize);
                nread += nsectors;
                nleft -= nsectors;
        }
 
-       return 0;
+       return err;
 
 #undef MIN
 #undef BOUNCE_SECTORS

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc Sat Aug 13 23:34:17 2011        (r224856)
+++ head/sys/conf/files.powerpc Sun Aug 14 00:20:37 2011        (r224857)
@@ -207,8 +207,8 @@ powerpc/ps3/ohci_ps3.c              optional        ps3 ohc
 powerpc/ps3/if_glc.c           optional        ps3 glc
 powerpc/ps3/mmu_ps3.c          optional        ps3
 powerpc/ps3/platform_ps3.c     optional        ps3
-powerpc/ps3/ps3ata.c           optional        ps3 ps3ata
 powerpc/ps3/ps3bus.c           optional        ps3
+powerpc/ps3/ps3cdrom.c         optional        ps3 scbus
 powerpc/ps3/ps3disk.c          optional        ps3
 powerpc/ps3/ps3pic.c           optional        ps3
 powerpc/ps3/ps3_syscons.c      optional        ps3 sc

Added: head/sys/powerpc/ps3/ps3cdrom.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/ps3/ps3cdrom.c     Sun Aug 14 00:20:37 2011        
(r224857)
@@ -0,0 +1,703 @@
+/*-
+ * Copyright (C) 2010 Nathan Whitehorn
+ * Copyright (C) 2011 glevand <geoffrey.lev...@mail.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ata.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pio.h>
+#include <machine/bus.h>
+#include <machine/platform.h>
+#include <machine/pmap.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+#include <cam/scsi/scsi_all.h>
+
+#include "ps3bus.h"
+#include "ps3-hvcall.h"
+
+#define PS3CDROM_LOCK_INIT(_sc)                \
+       mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \
+           MTX_DEF)
+#define PS3CDROM_LOCK_DESTROY(_sc)     mtx_destroy(&_sc->sc_mtx);
+#define PS3CDROM_LOCK(_sc)             mtx_lock(&(_sc)->sc_mtx)
+#define        PS3CDROM_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
+#define PS3CDROM_ASSERT_LOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define PS3CDROM_ASSERT_UNLOCKED(_sc)  mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+#define PS3CDROM_MAX_XFERS             3
+
+#define        LV1_STORAGE_SEND_ATAPI_COMMAND  0x01
+
+struct ps3cdrom_softc;
+
+struct ps3cdrom_xfer {
+       TAILQ_ENTRY(ps3cdrom_xfer) x_queue;
+       struct ps3cdrom_softc *x_sc;
+       union ccb *x_ccb;
+       bus_dmamap_t x_dmamap;
+       uint64_t x_tag;
+};
+
+TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
+
+struct ps3cdrom_softc {
+       device_t sc_dev;
+
+       struct mtx sc_mtx;
+
+       uint64_t sc_blksize;
+       uint64_t sc_nblocks;
+
+       int sc_irqid;
+       struct resource *sc_irq;
+       void *sc_irqctx;
+
+       bus_dma_tag_t sc_dmatag;
+
+       struct cam_sim *sc_sim;
+       struct cam_path *sc_path;
+
+       struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS];
+       struct ps3cdrom_xferq sc_active_xferq;
+       struct ps3cdrom_xferq sc_free_xferq;
+};
+
+enum lv1_ata_proto {
+       NON_DATA_PROTO          = 0x00,
+       PIO_DATA_IN_PROTO       = 0x01,
+       PIO_DATA_OUT_PROTO      = 0x02,
+       DMA_PROTO               = 0x03
+};
+
+enum lv1_ata_in_out {
+       DIR_WRITE               = 0x00,
+       DIR_READ                = 0x01
+};
+
+struct lv1_atapi_cmd {
+       uint8_t pkt[32];
+       uint32_t pktlen;
+       uint32_t nblocks;
+       uint32_t blksize;
+       uint32_t proto;         /* enum lv1_ata_proto */
+       uint32_t in_out;        /* enum lv1_ata_in_out */
+       uint64_t buf;
+       uint32_t arglen;
+};
+
+static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
+static void ps3cdrom_poll(struct cam_sim *sim);
+static void ps3cdrom_async(void *callback_arg, u_int32_t code,
+    struct cam_path* path, void *arg);
+
+static void ps3cdrom_intr(void *arg);
+
+static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
+    int error);
+
+static int ps3cdrom_decode_lv1_status(uint64_t status,
+       u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
+
+static int
+ps3cdrom_probe(device_t dev)
+{
+       if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
+           ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM)
+               return (ENXIO);
+
+       device_set_desc(dev, "Playstation 3 CDROM");
+
+       return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+ps3cdrom_attach(device_t dev)
+{
+       struct ps3cdrom_softc *sc = device_get_softc(dev);
+       struct cam_devq *devq;
+       struct ps3cdrom_xfer *xp;
+       struct ccb_setasync csa;
+       int i, err;
+
+       sc->sc_dev = dev;
+
+       PS3CDROM_LOCK_INIT(sc);
+
+       /* Setup interrupt handler */
+
+       sc->sc_irqid = 0;
+       sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
+           RF_ACTIVE);
+       if (!sc->sc_irq) {
+               device_printf(dev, "Could not allocate IRQ\n");
+               err = ENXIO;
+               goto fail_destroy_lock;
+       }
+
+       err = bus_setup_intr(dev, sc->sc_irq,
+           INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
+           NULL, ps3cdrom_intr, sc, &sc->sc_irqctx);
+       if (err) {
+               device_printf(dev, "Could not setup IRQ\n");
+               err = ENXIO;
+               goto fail_release_intr;
+       }
+
+       /* Setup DMA */
+
+       err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
+           BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+           BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
+           busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
+       if (err) {
+               device_printf(dev, "Could not create DMA tag\n");
+               err = ENXIO;
+               goto fail_teardown_intr;
+       }
+
+       /* Setup transfer queues */
+
+       TAILQ_INIT(&sc->sc_active_xferq);
+       TAILQ_INIT(&sc->sc_free_xferq);
+
+       for (i = 0; i < PS3CDROM_MAX_XFERS; i++) {
+               xp = &sc->sc_xfer[i];
+               xp->x_sc = sc;
+
+               err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
+                   &xp->x_dmamap);
+               if (err) {
+                       device_printf(dev, "Could not create DMA map (%d)\n",
+                           err);
+                       goto fail_destroy_dmamap;
+               }
+
+               TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
+       }
+
+       /* Setup CAM */
+
+       devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1);
+       if (!devq) {
+               device_printf(dev, "Could not allocate SIM queue\n");
+               err = ENOMEM;
+               goto fail_destroy_dmatag;
+       }
+
+       sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom",
+           sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0,
+           devq);
+       if (!sc->sc_sim) {
+               device_printf(dev, "Could not allocate SIM\n");
+               cam_simq_free(devq);
+               err = ENOMEM;
+               goto fail_destroy_dmatag;
+       }
+
+       /* Setup XPT */
+
+       PS3CDROM_LOCK(sc);
+
+       err = xpt_bus_register(sc->sc_sim, dev, 0);
+       if (err != CAM_SUCCESS) {
+               device_printf(dev, "Could not register XPT bus\n");
+               err = ENXIO;
+               PS3CDROM_UNLOCK(sc);
+               goto fail_free_sim;
+       }
+
+       err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim),
+           CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
+       if (err != CAM_REQ_CMP) {
+               device_printf(dev, "Could not create XPT path\n");
+               err = ENOMEM;
+               PS3CDROM_UNLOCK(sc);
+               goto fail_unregister_xpt_bus;
+       }
+
+       xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5);
+       csa.ccb_h.func_code = XPT_SASYNC_CB;
+       csa.event_enable = AC_LOST_DEVICE;
+       csa.callback = ps3cdrom_async;
+       csa.callback_arg = sc->sc_sim;
+       xpt_action((union ccb *) &csa);
+
+       CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE,
+           ("registered SIM for ps3cdrom%d\n", device_get_unit(dev)));
+
+       PS3CDROM_UNLOCK(sc);
+
+       return (BUS_PROBE_SPECIFIC);
+
+fail_unregister_xpt_bus:
+
+       xpt_bus_deregister(cam_sim_path(sc->sc_sim));
+
+fail_free_sim:
+
+       cam_sim_free(sc->sc_sim, TRUE);
+
+fail_destroy_dmamap:
+
+       while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) {
+               TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
+               bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap);
+       }
+
+fail_destroy_dmatag:
+
+       bus_dma_tag_destroy(sc->sc_dmatag);
+
+fail_teardown_intr:
+
+       bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
+
+fail_release_intr:
+
+       bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
+
+fail_destroy_lock:
+
+       PS3CDROM_LOCK_DESTROY(sc);
+
+       return (err);
+}
+
+static int
+ps3cdrom_detach(device_t dev)
+{
+       struct ps3cdrom_softc *sc = device_get_softc(dev);
+       int i;
+
+       xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL);
+       xpt_free_path(sc->sc_path);
+       xpt_bus_deregister(cam_sim_path(sc->sc_sim));
+       cam_sim_free(sc->sc_sim, TRUE);
+
+       for (i = 0; i < PS3CDROM_MAX_XFERS; i++)
+               bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap);
+
+       bus_dma_tag_destroy(sc->sc_dmatag);
+
+       bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
+       bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
+
+       PS3CDROM_LOCK_DESTROY(sc);
+
+       return (0);
+}
+
+static void
+ps3cdrom_action(struct cam_sim *sim, union ccb *ccb)
+{
+       struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim);
+       device_t dev = sc->sc_dev;
+       struct ps3cdrom_xfer *xp;
+       int err;
+
+       PS3CDROM_ASSERT_LOCKED(sc);
+
+       CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+          ("function code 0x%02x\n", ccb->ccb_h.func_code));
+
+       switch (ccb->ccb_h.func_code) {
+       case XPT_SCSI_IO:
+               if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG)
+                       break;
+
+               if(ccb->ccb_h.target_id > 0) {
+                       ccb->ccb_h.status = CAM_TID_INVALID;
+                       break;
+               }
+
+               if(ccb->ccb_h.target_lun > 0) {
+                       ccb->ccb_h.status = CAM_LUN_INVALID;
+                       break;
+               }
+
+               xp = TAILQ_FIRST(&sc->sc_free_xferq);
+               
+               KASSERT(xp != NULL, ("no free transfers"));
+
+               xp->x_ccb = ccb;
+
+               TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
+
+               err = bus_dmamap_load(sc->sc_dmatag, xp->x_dmamap,
+                   ccb->csio.data_ptr, ccb->csio.dxfer_len, ps3cdrom_transfer,
+                   xp, 0);
+               if (err && err != EINPROGRESS) {
+                       device_printf(dev, "Could not load DMA map (%d)\n",
+                           err);
+
+                       xp->x_ccb = NULL;
+                       TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
+                       ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+                       break;
+               }
+               return;
+       case XPT_SET_TRAN_SETTINGS:
+               ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+               break;
+       case XPT_GET_TRAN_SETTINGS:
+       {
+               struct ccb_trans_settings *cts = &ccb->cts;
+
+               cts->protocol = PROTO_SCSI;
+               cts->protocol_version = SCSI_REV_2;
+               cts->transport = XPORT_SPI;
+               cts->transport_version = 2;
+               cts->proto_specific.valid = 0;
+               cts->xport_specific.valid = 0;
+               ccb->ccb_h.status = CAM_REQ_CMP;
+               break;
+       }
+       case XPT_RESET_BUS:
+       case XPT_RESET_DEV:
+               ccb->ccb_h.status = CAM_REQ_CMP;
+               break;
+       case XPT_CALC_GEOMETRY:
+               cam_calc_geometry(&ccb->ccg, 1);
+               break;
+       case XPT_PATH_INQ:
+       {
+               struct ccb_pathinq *cpi = &ccb->cpi;
+
+               cpi->version_num = 1;
+               cpi->hba_inquiry = 0;
+               cpi->target_sprt = 0;
+               cpi->hba_inquiry = PI_SDTR_ABLE;
+               cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE;
+               cpi->hba_eng_cnt = 0;
+               bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
+               cpi->max_target = 0;
+               cpi->max_lun = 0;
+               cpi->initiator_id = 7;
+               cpi->bus_id = cam_sim_bus(sim);
+               cpi->unit_number = cam_sim_unit(sim);
+               cpi->base_transfer_speed = 150000;
+               strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+               strncpy(cpi->hba_vid, "Sony", HBA_IDLEN);
+               strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+               cpi->transport = XPORT_SPI;
+               cpi->transport_version = 2;
+               cpi->protocol = PROTO_SCSI;
+               cpi->protocol_version = SCSI_REV_2;
+               cpi->maxio = PAGE_SIZE;
+               cpi->ccb_h.status = CAM_REQ_CMP;
+               break;
+       }
+       default:
+               CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+                   ("unsupported function code 0x%02x\n",
+                   ccb->ccb_h.func_code));
+               ccb->ccb_h.status = CAM_REQ_INVALID;
+               break;
+       }
+
+       xpt_done(ccb);
+}
+
+static void
+ps3cdrom_poll(struct cam_sim *sim)
+{
+       ps3cdrom_intr(cam_sim_softc(sim));
+}
+
+static void
+ps3cdrom_async(void *callback_arg, u_int32_t code,
+       struct cam_path* path, void *arg)
+{
+       switch (code) {
+       case AC_LOST_DEVICE:
+               xpt_print_path(path);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+ps3cdrom_intr(void *arg)
+{
+       struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg;
+       device_t dev = sc->sc_dev;
+       uint64_t devid = ps3bus_get_device(dev);
+       struct ps3cdrom_xfer *xp;
+       union ccb *ccb;
+       u_int8_t *cdb, sense_key, asc, ascq;
+       uint64_t tag, status;
+
+       if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
+               return;
+
+       PS3CDROM_LOCK(sc);
+
+       /* Find transfer with the returned tag */
+
+       TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) {
+               if (xp->x_tag == tag)
+                       break;
+       }
+
+       if (xp) {
+               ccb = xp->x_ccb;
+               cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+                           ccb->csio.cdb_io.cdb_ptr :
+                           ccb->csio.cdb_io.cdb_bytes;
+
+               CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+                  ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n",
+                   cdb[0], tag, status));
+
+               if (!status) {
+                       ccb->csio.scsi_status = SCSI_STATUS_OK;
+                       ccb->csio.resid = 0;
+                       ccb->ccb_h.status = CAM_REQ_CMP;
+               } else {
+                       ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
+                       ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+
+                       if (!ps3cdrom_decode_lv1_status(status, &sense_key,
+                           &asc, &ascq)) {
+                               struct scsi_sense_data sense_data;
+
+                               CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+                                  ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
+                                   sense_key, asc, ascq));
+
+                               bzero(&sense_data, sizeof(sense_data));
+                               sense_data.error_code = SSD_CURRENT_ERROR;
+                               sense_data.flags |= sense_key;
+                               sense_data.extra_len = 0xa;
+                               sense_data.add_sense_code = asc;
+                               sense_data.add_sense_code_qual = ascq;
+                               ccb->csio.sense_len = sizeof(sense_data);
+                               bcopy(&sense_data, &ccb->csio.sense_data,
+                                   ccb->csio.sense_len);
+                               ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
+                                   CAM_AUTOSNS_VALID;
+                       }
+
+                       if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
+                               ccb->csio.resid = ccb->csio.dxfer_len;
+               }
+
+               if (ccb->ccb_h.flags & CAM_DIR_IN)
+                       bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
+                           BUS_DMASYNC_POSTREAD);
+
+               bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
+
+               xp->x_ccb = NULL;
+               TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
+               TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
+
+               xpt_done(ccb);
+       } else {
+               device_printf(dev,
+                   "Could not find transfer with tag 0x%016lx\n",  tag);
+       }
+
+       PS3CDROM_UNLOCK(sc);
+}
+
+static void
+ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+       struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
+       struct ps3cdrom_softc *sc = xp->x_sc;
+       device_t dev = sc->sc_dev;
+       uint64_t devid = ps3bus_get_device(dev);
+       union ccb *ccb = xp->x_ccb;
+       u_int8_t *cdb;
+       uint64_t start_sector, block_count;
+       int err;
+
+       KASSERT(nsegs == 1, ("invalid number of DMA segments"));
+
+       PS3CDROM_ASSERT_LOCKED(sc);
+
+       if (error) {
+               device_printf(dev, "Could not load DMA map (%d)\n",  error);
+
+               xp->x_ccb = NULL;
+               TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
+               ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+               xpt_done(ccb);
+               return;
+       }
+
+       cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+                   ccb->csio.cdb_io.cdb_ptr :
+                   ccb->csio.cdb_io.cdb_bytes;
+
+       CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
+          ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
+           ccb->csio.cdb_len, ccb->csio.dxfer_len));
+
+       switch (cdb[0]) {
+       case READ_10:
+               start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
+                   (cdb[4] << 8) | cdb[5];
+               block_count = (cdb[7] << 8) | cdb[8];

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to