mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-23 11:18:54 +00:00
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.levand@mail.ru> Approved by: re (bz)
This commit is contained in:
parent
e95725cb76
commit
9f2c359f16
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224857
@ -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
|
||||
|
@ -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)
|
||||
|
@ -157,6 +157,7 @@ ps3_parsedev(struct ps3_devdesc **dev, const char *devspec, const char **path)
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -69,12 +69,12 @@ int lv1_net_stop_tx_dma(int bus, int dev, int);
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
|
154
sys/boot/powerpc/ps3/ps3cdrom.c
Normal file
154
sys/boot/powerpc/ps3/ps3cdrom.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*-
|
||||
* Copyright (C) 2011 glevand <geoffrey.levand@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)
|
||||
{
|
||||
}
|
@ -52,35 +52,39 @@ int ps3stor_setup(struct ps3_stordev *sd, int type)
|
||||
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 @@ int ps3stor_setup(struct ps3_stordev *sd, int type)
|
||||
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_stordev *sd, int regidx,
|
||||
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_stordev *sd, int regidx,
|
||||
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_stordev *sd, int regidx,
|
||||
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
|
||||
|
@ -207,8 +207,8 @@ powerpc/ps3/ohci_ps3.c optional ps3 ohci
|
||||
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
|
||||
|
703
sys/powerpc/ps3/ps3cdrom.c
Normal file
703
sys/powerpc/ps3/ps3cdrom.c
Normal file
@ -0,0 +1,703 @@
|
||||
/*-
|
||||
* Copyright (C) 2010 Nathan Whitehorn
|
||||
* Copyright (C) 2011 glevand <geoffrey.levand@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];
|
||||
|
||||
err = lv1_storage_read(devid, 0 /* region id */,
|
||||
start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
|
||||
&xp->x_tag);
|
||||
bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
break;
|
||||
case WRITE_10:
|
||||
start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
|
||||
(cdb[4] << 8) | cdb[5];
|
||||
block_count = (cdb[7] << 8) | cdb[8];
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
err = lv1_storage_write(devid, 0 /* region id */,
|
||||
start_sector, block_count, 0 /* flags */,
|
||||
segs[0].ds_addr, &xp->x_tag);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
struct lv1_atapi_cmd atapi_cmd;
|
||||
|
||||
bzero(&atapi_cmd, sizeof(atapi_cmd));
|
||||
atapi_cmd.pktlen = 12;
|
||||
bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
|
||||
|
||||
if (ccb->ccb_h.flags & CAM_DIR_IN) {
|
||||
atapi_cmd.in_out = DIR_READ;
|
||||
atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
|
||||
DMA_PROTO : PIO_DATA_IN_PROTO;
|
||||
} else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
|
||||
atapi_cmd.in_out = DIR_WRITE;
|
||||
atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
|
||||
DMA_PROTO : PIO_DATA_OUT_PROTO;
|
||||
} else {
|
||||
atapi_cmd.proto = NON_DATA_PROTO;
|
||||
}
|
||||
|
||||
atapi_cmd.nblocks = atapi_cmd.arglen = segs[0].ds_len;
|
||||
atapi_cmd.blksize = 1;
|
||||
atapi_cmd.buf = segs[0].ds_addr;
|
||||
|
||||
if (ccb->ccb_h.flags & CAM_DIR_OUT)
|
||||
bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
err = lv1_storage_send_device_command(devid,
|
||||
LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
|
||||
sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
|
||||
&xp->x_tag);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
struct scsi_sense_data sense_data;
|
||||
|
||||
device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
|
||||
cdb[0], err);
|
||||
|
||||
bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
|
||||
|
||||
xp->x_ccb = NULL;
|
||||
TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
|
||||
|
||||
bzero(&sense_data, sizeof(sense_data));
|
||||
sense_data.error_code = SSD_CURRENT_ERROR;
|
||||
sense_data.flags |= SSD_KEY_ILLEGAL_REQUEST;
|
||||
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;
|
||||
xpt_done(ccb);
|
||||
} else {
|
||||
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
|
||||
("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
|
||||
xp->x_tag));
|
||||
|
||||
TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
|
||||
ccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
|
||||
u_int8_t *ascq)
|
||||
{
|
||||
if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
|
||||
return -1;
|
||||
|
||||
*sense_key = (status >> 16) & 0xff;
|
||||
*asc = (status >> 8) & 0xff;
|
||||
*ascq = status & 0xff;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t ps3cdrom_methods[] = {
|
||||
DEVMETHOD(device_probe, ps3cdrom_probe),
|
||||
DEVMETHOD(device_attach, ps3cdrom_attach),
|
||||
DEVMETHOD(device_detach, ps3cdrom_detach),
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static driver_t ps3cdrom_driver = {
|
||||
"ps3cdrom",
|
||||
ps3cdrom_methods,
|
||||
sizeof(struct ps3cdrom_softc),
|
||||
};
|
||||
|
||||
static devclass_t ps3cdrom_devclass;
|
||||
|
||||
DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
|
||||
MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
|
Loading…
Reference in New Issue
Block a user