xref: /freebsd/sys/powerpc/ps3/ps3cdrom.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
19f2c359fSNathan Whitehorn /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
371e3c308SPedro F. Giffuni  *
49f2c359fSNathan Whitehorn  * Copyright (C) 2010 Nathan Whitehorn
59f2c359fSNathan Whitehorn  * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
69f2c359fSNathan Whitehorn  * All rights reserved.
79f2c359fSNathan Whitehorn  *
89f2c359fSNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
99f2c359fSNathan Whitehorn  * modification, are permitted provided that the following conditions
109f2c359fSNathan Whitehorn  * are met:
119f2c359fSNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
129f2c359fSNathan Whitehorn  *    notice, this list of conditions and the following disclaimer,
139f2c359fSNathan Whitehorn  *    without modification, immediately at the beginning of the file.
149f2c359fSNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
159f2c359fSNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
169f2c359fSNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
179f2c359fSNathan Whitehorn  *
189f2c359fSNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
199f2c359fSNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
209f2c359fSNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
219f2c359fSNathan Whitehorn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
229f2c359fSNathan Whitehorn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
239f2c359fSNathan Whitehorn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249f2c359fSNathan Whitehorn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259f2c359fSNathan Whitehorn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269f2c359fSNathan Whitehorn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
279f2c359fSNathan Whitehorn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289f2c359fSNathan Whitehorn  */
299f2c359fSNathan Whitehorn 
309f2c359fSNathan Whitehorn #include <sys/cdefs.h>
319f2c359fSNathan Whitehorn __FBSDID("$FreeBSD$");
329f2c359fSNathan Whitehorn 
339f2c359fSNathan Whitehorn #include <sys/param.h>
349f2c359fSNathan Whitehorn #include <sys/module.h>
359f2c359fSNathan Whitehorn #include <sys/systm.h>
369f2c359fSNathan Whitehorn #include <sys/kernel.h>
379f2c359fSNathan Whitehorn #include <sys/ata.h>
389f2c359fSNathan Whitehorn #include <sys/bus.h>
399f2c359fSNathan Whitehorn #include <sys/conf.h>
409f2c359fSNathan Whitehorn #include <sys/kthread.h>
419f2c359fSNathan Whitehorn #include <sys/lock.h>
429f2c359fSNathan Whitehorn #include <sys/malloc.h>
439f2c359fSNathan Whitehorn #include <sys/mutex.h>
449f2c359fSNathan Whitehorn 
459f2c359fSNathan Whitehorn #include <vm/vm.h>
469f2c359fSNathan Whitehorn #include <vm/pmap.h>
479f2c359fSNathan Whitehorn 
489f2c359fSNathan Whitehorn #include <machine/pio.h>
499f2c359fSNathan Whitehorn #include <machine/bus.h>
509f2c359fSNathan Whitehorn #include <machine/platform.h>
519f2c359fSNathan Whitehorn #include <machine/resource.h>
529f2c359fSNathan Whitehorn #include <sys/bus.h>
539f2c359fSNathan Whitehorn #include <sys/rman.h>
549f2c359fSNathan Whitehorn 
559f2c359fSNathan Whitehorn #include <cam/cam.h>
569f2c359fSNathan Whitehorn #include <cam/cam_ccb.h>
579f2c359fSNathan Whitehorn #include <cam/cam_sim.h>
589f2c359fSNathan Whitehorn #include <cam/cam_xpt_sim.h>
599f2c359fSNathan Whitehorn #include <cam/cam_debug.h>
609f2c359fSNathan Whitehorn #include <cam/scsi/scsi_all.h>
619f2c359fSNathan Whitehorn 
629f2c359fSNathan Whitehorn #include "ps3bus.h"
639f2c359fSNathan Whitehorn #include "ps3-hvcall.h"
649f2c359fSNathan Whitehorn 
659f2c359fSNathan Whitehorn #define PS3CDROM_LOCK_INIT(_sc)		\
669f2c359fSNathan Whitehorn 	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \
679f2c359fSNathan Whitehorn 	    MTX_DEF)
689f2c359fSNathan Whitehorn #define PS3CDROM_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
699f2c359fSNathan Whitehorn #define PS3CDROM_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
709f2c359fSNathan Whitehorn #define	PS3CDROM_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
719f2c359fSNathan Whitehorn #define PS3CDROM_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
729f2c359fSNathan Whitehorn #define PS3CDROM_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
739f2c359fSNathan Whitehorn 
749f2c359fSNathan Whitehorn #define PS3CDROM_MAX_XFERS		3
759f2c359fSNathan Whitehorn 
769f2c359fSNathan Whitehorn #define	LV1_STORAGE_SEND_ATAPI_COMMAND	0x01
779f2c359fSNathan Whitehorn 
789f2c359fSNathan Whitehorn struct ps3cdrom_softc;
799f2c359fSNathan Whitehorn 
809f2c359fSNathan Whitehorn struct ps3cdrom_xfer {
819f2c359fSNathan Whitehorn 	TAILQ_ENTRY(ps3cdrom_xfer) x_queue;
829f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *x_sc;
839f2c359fSNathan Whitehorn 	union ccb *x_ccb;
849f2c359fSNathan Whitehorn 	bus_dmamap_t x_dmamap;
859f2c359fSNathan Whitehorn 	uint64_t x_tag;
869f2c359fSNathan Whitehorn };
879f2c359fSNathan Whitehorn 
889f2c359fSNathan Whitehorn TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
899f2c359fSNathan Whitehorn 
909f2c359fSNathan Whitehorn struct ps3cdrom_softc {
919f2c359fSNathan Whitehorn 	device_t sc_dev;
929f2c359fSNathan Whitehorn 
939f2c359fSNathan Whitehorn 	struct mtx sc_mtx;
949f2c359fSNathan Whitehorn 
959f2c359fSNathan Whitehorn 	uint64_t sc_blksize;
969f2c359fSNathan Whitehorn 	uint64_t sc_nblocks;
979f2c359fSNathan Whitehorn 
989f2c359fSNathan Whitehorn 	int sc_irqid;
999f2c359fSNathan Whitehorn 	struct resource	*sc_irq;
1009f2c359fSNathan Whitehorn 	void *sc_irqctx;
1019f2c359fSNathan Whitehorn 
1029f2c359fSNathan Whitehorn 	bus_dma_tag_t sc_dmatag;
1039f2c359fSNathan Whitehorn 
1049f2c359fSNathan Whitehorn 	struct cam_sim *sc_sim;
1059f2c359fSNathan Whitehorn 	struct cam_path *sc_path;
1069f2c359fSNathan Whitehorn 
1079f2c359fSNathan Whitehorn 	struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS];
1089f2c359fSNathan Whitehorn 	struct ps3cdrom_xferq sc_active_xferq;
1099f2c359fSNathan Whitehorn 	struct ps3cdrom_xferq sc_free_xferq;
1109f2c359fSNathan Whitehorn };
1119f2c359fSNathan Whitehorn 
1129f2c359fSNathan Whitehorn enum lv1_ata_proto {
1139f2c359fSNathan Whitehorn 	NON_DATA_PROTO		= 0x00,
1149f2c359fSNathan Whitehorn 	PIO_DATA_IN_PROTO	= 0x01,
1159f2c359fSNathan Whitehorn 	PIO_DATA_OUT_PROTO	= 0x02,
1169f2c359fSNathan Whitehorn 	DMA_PROTO		= 0x03
1179f2c359fSNathan Whitehorn };
1189f2c359fSNathan Whitehorn 
1199f2c359fSNathan Whitehorn enum lv1_ata_in_out {
1209f2c359fSNathan Whitehorn 	DIR_WRITE		= 0x00,
1219f2c359fSNathan Whitehorn 	DIR_READ		= 0x01
1229f2c359fSNathan Whitehorn };
1239f2c359fSNathan Whitehorn 
1249f2c359fSNathan Whitehorn struct lv1_atapi_cmd {
1259f2c359fSNathan Whitehorn 	uint8_t pkt[32];
1269f2c359fSNathan Whitehorn 	uint32_t pktlen;
1279f2c359fSNathan Whitehorn 	uint32_t nblocks;
1289f2c359fSNathan Whitehorn 	uint32_t blksize;
1299f2c359fSNathan Whitehorn 	uint32_t proto;		/* enum lv1_ata_proto */
1309f2c359fSNathan Whitehorn 	uint32_t in_out;	/* enum lv1_ata_in_out */
1319f2c359fSNathan Whitehorn 	uint64_t buf;
1329f2c359fSNathan Whitehorn 	uint32_t arglen;
1339f2c359fSNathan Whitehorn };
1349f2c359fSNathan Whitehorn 
1359f2c359fSNathan Whitehorn static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
1369f2c359fSNathan Whitehorn static void ps3cdrom_poll(struct cam_sim *sim);
1379f2c359fSNathan Whitehorn static void ps3cdrom_async(void *callback_arg, u_int32_t code,
1389f2c359fSNathan Whitehorn     struct cam_path* path, void *arg);
1399f2c359fSNathan Whitehorn 
1409f2c359fSNathan Whitehorn static void ps3cdrom_intr(void *arg);
1419f2c359fSNathan Whitehorn 
1429f2c359fSNathan Whitehorn static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
1439f2c359fSNathan Whitehorn     int error);
1449f2c359fSNathan Whitehorn 
1459f2c359fSNathan Whitehorn static int ps3cdrom_decode_lv1_status(uint64_t status,
1469f2c359fSNathan Whitehorn 	u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
1479f2c359fSNathan Whitehorn 
1489f2c359fSNathan Whitehorn static int
1499f2c359fSNathan Whitehorn ps3cdrom_probe(device_t dev)
1509f2c359fSNathan Whitehorn {
1519f2c359fSNathan Whitehorn 	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
1529f2c359fSNathan Whitehorn 	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM)
1539f2c359fSNathan Whitehorn 		return (ENXIO);
1549f2c359fSNathan Whitehorn 
1559f2c359fSNathan Whitehorn 	device_set_desc(dev, "Playstation 3 CDROM");
1569f2c359fSNathan Whitehorn 
1579f2c359fSNathan Whitehorn 	return (BUS_PROBE_SPECIFIC);
1589f2c359fSNathan Whitehorn }
1599f2c359fSNathan Whitehorn 
1609f2c359fSNathan Whitehorn static int
1619f2c359fSNathan Whitehorn ps3cdrom_attach(device_t dev)
1629f2c359fSNathan Whitehorn {
1639f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *sc = device_get_softc(dev);
1649f2c359fSNathan Whitehorn 	struct cam_devq *devq;
1659f2c359fSNathan Whitehorn 	struct ps3cdrom_xfer *xp;
1669f2c359fSNathan Whitehorn 	struct ccb_setasync csa;
1679f2c359fSNathan Whitehorn 	int i, err;
1689f2c359fSNathan Whitehorn 
1699f2c359fSNathan Whitehorn 	sc->sc_dev = dev;
1709f2c359fSNathan Whitehorn 
1719f2c359fSNathan Whitehorn 	PS3CDROM_LOCK_INIT(sc);
1729f2c359fSNathan Whitehorn 
1739f2c359fSNathan Whitehorn 	/* Setup interrupt handler */
1749f2c359fSNathan Whitehorn 
1759f2c359fSNathan Whitehorn 	sc->sc_irqid = 0;
1769f2c359fSNathan Whitehorn 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
1779f2c359fSNathan Whitehorn 	    RF_ACTIVE);
1789f2c359fSNathan Whitehorn 	if (!sc->sc_irq) {
1799f2c359fSNathan Whitehorn 		device_printf(dev, "Could not allocate IRQ\n");
1809f2c359fSNathan Whitehorn 		err = ENXIO;
1819f2c359fSNathan Whitehorn 		goto fail_destroy_lock;
1829f2c359fSNathan Whitehorn 	}
1839f2c359fSNathan Whitehorn 
1849f2c359fSNathan Whitehorn 	err = bus_setup_intr(dev, sc->sc_irq,
1859f2c359fSNathan Whitehorn 	    INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
1869f2c359fSNathan Whitehorn 	    NULL, ps3cdrom_intr, sc, &sc->sc_irqctx);
1879f2c359fSNathan Whitehorn 	if (err) {
1889f2c359fSNathan Whitehorn 		device_printf(dev, "Could not setup IRQ\n");
1899f2c359fSNathan Whitehorn 		err = ENXIO;
1909f2c359fSNathan Whitehorn 		goto fail_release_intr;
1919f2c359fSNathan Whitehorn 	}
1929f2c359fSNathan Whitehorn 
1939f2c359fSNathan Whitehorn 	/* Setup DMA */
1949f2c359fSNathan Whitehorn 
1959f2c359fSNathan Whitehorn 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
1969f2c359fSNathan Whitehorn 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
1979f2c359fSNathan Whitehorn 	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
1989f2c359fSNathan Whitehorn 	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
1999f2c359fSNathan Whitehorn 	if (err) {
2009f2c359fSNathan Whitehorn 		device_printf(dev, "Could not create DMA tag\n");
2019f2c359fSNathan Whitehorn 		err = ENXIO;
2029f2c359fSNathan Whitehorn 		goto fail_teardown_intr;
2039f2c359fSNathan Whitehorn 	}
2049f2c359fSNathan Whitehorn 
2059f2c359fSNathan Whitehorn 	/* Setup transfer queues */
2069f2c359fSNathan Whitehorn 
2079f2c359fSNathan Whitehorn 	TAILQ_INIT(&sc->sc_active_xferq);
2089f2c359fSNathan Whitehorn 	TAILQ_INIT(&sc->sc_free_xferq);
2099f2c359fSNathan Whitehorn 
2109f2c359fSNathan Whitehorn 	for (i = 0; i < PS3CDROM_MAX_XFERS; i++) {
2119f2c359fSNathan Whitehorn 		xp = &sc->sc_xfer[i];
2129f2c359fSNathan Whitehorn 		xp->x_sc = sc;
2139f2c359fSNathan Whitehorn 
2149f2c359fSNathan Whitehorn 		err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
2159f2c359fSNathan Whitehorn 		    &xp->x_dmamap);
2169f2c359fSNathan Whitehorn 		if (err) {
2179f2c359fSNathan Whitehorn 			device_printf(dev, "Could not create DMA map (%d)\n",
2189f2c359fSNathan Whitehorn 			    err);
2199f2c359fSNathan Whitehorn 			goto fail_destroy_dmamap;
2209f2c359fSNathan Whitehorn 		}
2219f2c359fSNathan Whitehorn 
2229f2c359fSNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
2239f2c359fSNathan Whitehorn 	}
2249f2c359fSNathan Whitehorn 
2259f2c359fSNathan Whitehorn 	/* Setup CAM */
2269f2c359fSNathan Whitehorn 
2279f2c359fSNathan Whitehorn 	devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1);
2289f2c359fSNathan Whitehorn 	if (!devq) {
2299f2c359fSNathan Whitehorn 		device_printf(dev, "Could not allocate SIM queue\n");
2309f2c359fSNathan Whitehorn 		err = ENOMEM;
2319f2c359fSNathan Whitehorn 		goto fail_destroy_dmatag;
2329f2c359fSNathan Whitehorn 	}
2339f2c359fSNathan Whitehorn 
2349f2c359fSNathan Whitehorn 	sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom",
2359f2c359fSNathan Whitehorn 	    sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0,
2369f2c359fSNathan Whitehorn 	    devq);
2379f2c359fSNathan Whitehorn 	if (!sc->sc_sim) {
2389f2c359fSNathan Whitehorn 		device_printf(dev, "Could not allocate SIM\n");
2399f2c359fSNathan Whitehorn 		cam_simq_free(devq);
2409f2c359fSNathan Whitehorn 		err = ENOMEM;
2419f2c359fSNathan Whitehorn 		goto fail_destroy_dmatag;
2429f2c359fSNathan Whitehorn 	}
2439f2c359fSNathan Whitehorn 
2449f2c359fSNathan Whitehorn 	/* Setup XPT */
2459f2c359fSNathan Whitehorn 
2469f2c359fSNathan Whitehorn 	PS3CDROM_LOCK(sc);
2479f2c359fSNathan Whitehorn 
2489f2c359fSNathan Whitehorn 	err = xpt_bus_register(sc->sc_sim, dev, 0);
2499f2c359fSNathan Whitehorn 	if (err != CAM_SUCCESS) {
2509f2c359fSNathan Whitehorn 		device_printf(dev, "Could not register XPT bus\n");
2519f2c359fSNathan Whitehorn 		err = ENXIO;
2529f2c359fSNathan Whitehorn 		PS3CDROM_UNLOCK(sc);
2539f2c359fSNathan Whitehorn 		goto fail_free_sim;
2549f2c359fSNathan Whitehorn 	}
2559f2c359fSNathan Whitehorn 
2569f2c359fSNathan Whitehorn 	err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim),
2579f2c359fSNathan Whitehorn 	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
2589f2c359fSNathan Whitehorn 	if (err != CAM_REQ_CMP) {
2599f2c359fSNathan Whitehorn 		device_printf(dev, "Could not create XPT path\n");
2609f2c359fSNathan Whitehorn 		err = ENOMEM;
2619f2c359fSNathan Whitehorn 		PS3CDROM_UNLOCK(sc);
2629f2c359fSNathan Whitehorn 		goto fail_unregister_xpt_bus;
2639f2c359fSNathan Whitehorn 	}
2649f2c359fSNathan Whitehorn 
2658dc96b74SEdward Tomasz Napierala 	memset(&csa, 0, sizeof(csa));
2669f2c359fSNathan Whitehorn 	xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5);
2679f2c359fSNathan Whitehorn 	csa.ccb_h.func_code = XPT_SASYNC_CB;
2689f2c359fSNathan Whitehorn 	csa.event_enable = AC_LOST_DEVICE;
2699f2c359fSNathan Whitehorn 	csa.callback = ps3cdrom_async;
2709f2c359fSNathan Whitehorn 	csa.callback_arg = sc->sc_sim;
2719f2c359fSNathan Whitehorn 	xpt_action((union ccb *) &csa);
2729f2c359fSNathan Whitehorn 
2739f2c359fSNathan Whitehorn 	CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE,
2749f2c359fSNathan Whitehorn 	    ("registered SIM for ps3cdrom%d\n", device_get_unit(dev)));
2759f2c359fSNathan Whitehorn 
2769f2c359fSNathan Whitehorn 	PS3CDROM_UNLOCK(sc);
2779f2c359fSNathan Whitehorn 
2789f2c359fSNathan Whitehorn 	return (BUS_PROBE_SPECIFIC);
2799f2c359fSNathan Whitehorn 
2809f2c359fSNathan Whitehorn fail_unregister_xpt_bus:
2819f2c359fSNathan Whitehorn 
2829f2c359fSNathan Whitehorn 	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
2839f2c359fSNathan Whitehorn 
2849f2c359fSNathan Whitehorn fail_free_sim:
2859f2c359fSNathan Whitehorn 
2869f2c359fSNathan Whitehorn 	cam_sim_free(sc->sc_sim, TRUE);
2879f2c359fSNathan Whitehorn 
2889f2c359fSNathan Whitehorn fail_destroy_dmamap:
2899f2c359fSNathan Whitehorn 
2909f2c359fSNathan Whitehorn 	while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) {
2919f2c359fSNathan Whitehorn 		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
2929f2c359fSNathan Whitehorn 		bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap);
2939f2c359fSNathan Whitehorn 	}
2949f2c359fSNathan Whitehorn 
2959f2c359fSNathan Whitehorn fail_destroy_dmatag:
2969f2c359fSNathan Whitehorn 
2979f2c359fSNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_dmatag);
2989f2c359fSNathan Whitehorn 
2999f2c359fSNathan Whitehorn fail_teardown_intr:
3009f2c359fSNathan Whitehorn 
3019f2c359fSNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
3029f2c359fSNathan Whitehorn 
3039f2c359fSNathan Whitehorn fail_release_intr:
3049f2c359fSNathan Whitehorn 
3059f2c359fSNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
3069f2c359fSNathan Whitehorn 
3079f2c359fSNathan Whitehorn fail_destroy_lock:
3089f2c359fSNathan Whitehorn 
3099f2c359fSNathan Whitehorn 	PS3CDROM_LOCK_DESTROY(sc);
3109f2c359fSNathan Whitehorn 
3119f2c359fSNathan Whitehorn 	return (err);
3129f2c359fSNathan Whitehorn }
3139f2c359fSNathan Whitehorn 
3149f2c359fSNathan Whitehorn static int
3159f2c359fSNathan Whitehorn ps3cdrom_detach(device_t dev)
3169f2c359fSNathan Whitehorn {
3179f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *sc = device_get_softc(dev);
3189f2c359fSNathan Whitehorn 	int i;
3199f2c359fSNathan Whitehorn 
3209f2c359fSNathan Whitehorn 	xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL);
3219f2c359fSNathan Whitehorn 	xpt_free_path(sc->sc_path);
3229f2c359fSNathan Whitehorn 	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
3239f2c359fSNathan Whitehorn 	cam_sim_free(sc->sc_sim, TRUE);
3249f2c359fSNathan Whitehorn 
3259f2c359fSNathan Whitehorn 	for (i = 0; i < PS3CDROM_MAX_XFERS; i++)
3269f2c359fSNathan Whitehorn 		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap);
3279f2c359fSNathan Whitehorn 
3289f2c359fSNathan Whitehorn 	bus_dma_tag_destroy(sc->sc_dmatag);
3299f2c359fSNathan Whitehorn 
3309f2c359fSNathan Whitehorn 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
3319f2c359fSNathan Whitehorn 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
3329f2c359fSNathan Whitehorn 
3339f2c359fSNathan Whitehorn 	PS3CDROM_LOCK_DESTROY(sc);
3349f2c359fSNathan Whitehorn 
3359f2c359fSNathan Whitehorn 	return (0);
3369f2c359fSNathan Whitehorn }
3379f2c359fSNathan Whitehorn 
3389f2c359fSNathan Whitehorn static void
3399f2c359fSNathan Whitehorn ps3cdrom_action(struct cam_sim *sim, union ccb *ccb)
3409f2c359fSNathan Whitehorn {
3419f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim);
3429f2c359fSNathan Whitehorn 	device_t dev = sc->sc_dev;
3439f2c359fSNathan Whitehorn 	struct ps3cdrom_xfer *xp;
3449f2c359fSNathan Whitehorn 	int err;
3459f2c359fSNathan Whitehorn 
3469f2c359fSNathan Whitehorn 	PS3CDROM_ASSERT_LOCKED(sc);
3479f2c359fSNathan Whitehorn 
3489f2c359fSNathan Whitehorn 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
3499f2c359fSNathan Whitehorn 	   ("function code 0x%02x\n", ccb->ccb_h.func_code));
3509f2c359fSNathan Whitehorn 
3519f2c359fSNathan Whitehorn 	switch (ccb->ccb_h.func_code) {
3529f2c359fSNathan Whitehorn 	case XPT_SCSI_IO:
3539f2c359fSNathan Whitehorn 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG)
3549f2c359fSNathan Whitehorn 			break;
3559f2c359fSNathan Whitehorn 
3569f2c359fSNathan Whitehorn 		if(ccb->ccb_h.target_id > 0) {
3579f2c359fSNathan Whitehorn 			ccb->ccb_h.status = CAM_TID_INVALID;
3589f2c359fSNathan Whitehorn 			break;
3599f2c359fSNathan Whitehorn 		}
3609f2c359fSNathan Whitehorn 
3619f2c359fSNathan Whitehorn 		if(ccb->ccb_h.target_lun > 0) {
3629f2c359fSNathan Whitehorn 			ccb->ccb_h.status = CAM_LUN_INVALID;
3639f2c359fSNathan Whitehorn 			break;
3649f2c359fSNathan Whitehorn 		}
3659f2c359fSNathan Whitehorn 
3669f2c359fSNathan Whitehorn 		xp = TAILQ_FIRST(&sc->sc_free_xferq);
3679f2c359fSNathan Whitehorn 
3689f2c359fSNathan Whitehorn 		KASSERT(xp != NULL, ("no free transfers"));
3699f2c359fSNathan Whitehorn 
3709f2c359fSNathan Whitehorn 		xp->x_ccb = ccb;
3719f2c359fSNathan Whitehorn 
3729f2c359fSNathan Whitehorn 		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
3739f2c359fSNathan Whitehorn 
374dd0b4fb6SKonstantin Belousov 		err = bus_dmamap_load_ccb(sc->sc_dmatag, xp->x_dmamap,
375dd0b4fb6SKonstantin Belousov 		    ccb, ps3cdrom_transfer, xp, 0);
3769f2c359fSNathan Whitehorn 		if (err && err != EINPROGRESS) {
3779f2c359fSNathan Whitehorn 			device_printf(dev, "Could not load DMA map (%d)\n",
3789f2c359fSNathan Whitehorn 			    err);
3799f2c359fSNathan Whitehorn 
3809f2c359fSNathan Whitehorn 			xp->x_ccb = NULL;
3819f2c359fSNathan Whitehorn 			TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
3829f2c359fSNathan Whitehorn 			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
3839f2c359fSNathan Whitehorn 			break;
3849f2c359fSNathan Whitehorn 		}
3859f2c359fSNathan Whitehorn 		return;
3869f2c359fSNathan Whitehorn 	case XPT_SET_TRAN_SETTINGS:
3879f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
3889f2c359fSNathan Whitehorn 		break;
3899f2c359fSNathan Whitehorn 	case XPT_GET_TRAN_SETTINGS:
3909f2c359fSNathan Whitehorn 	{
3919f2c359fSNathan Whitehorn 		struct ccb_trans_settings *cts = &ccb->cts;
3929f2c359fSNathan Whitehorn 
3939f2c359fSNathan Whitehorn 		cts->protocol = PROTO_SCSI;
3949f2c359fSNathan Whitehorn 		cts->protocol_version = SCSI_REV_2;
3959f2c359fSNathan Whitehorn 		cts->transport = XPORT_SPI;
3969f2c359fSNathan Whitehorn 		cts->transport_version = 2;
3979f2c359fSNathan Whitehorn 		cts->proto_specific.valid = 0;
3989f2c359fSNathan Whitehorn 		cts->xport_specific.valid = 0;
3999f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP;
4009f2c359fSNathan Whitehorn 		break;
4019f2c359fSNathan Whitehorn 	}
4029f2c359fSNathan Whitehorn 	case XPT_RESET_BUS:
4039f2c359fSNathan Whitehorn 	case XPT_RESET_DEV:
4049f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_CMP;
4059f2c359fSNathan Whitehorn 		break;
4069f2c359fSNathan Whitehorn 	case XPT_CALC_GEOMETRY:
4079f2c359fSNathan Whitehorn 		cam_calc_geometry(&ccb->ccg, 1);
4089f2c359fSNathan Whitehorn 		break;
4099f2c359fSNathan Whitehorn 	case XPT_PATH_INQ:
4109f2c359fSNathan Whitehorn 	{
4119f2c359fSNathan Whitehorn 		struct ccb_pathinq *cpi = &ccb->cpi;
4129f2c359fSNathan Whitehorn 
4139f2c359fSNathan Whitehorn 		cpi->version_num = 1;
4149f2c359fSNathan Whitehorn 		cpi->hba_inquiry = 0;
4159f2c359fSNathan Whitehorn 		cpi->target_sprt = 0;
4169f2c359fSNathan Whitehorn 		cpi->hba_inquiry = PI_SDTR_ABLE;
4179f2c359fSNathan Whitehorn 		cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE;
4189f2c359fSNathan Whitehorn 		cpi->hba_eng_cnt = 0;
4199f2c359fSNathan Whitehorn 		bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
4209f2c359fSNathan Whitehorn 		cpi->max_target = 0;
4219f2c359fSNathan Whitehorn 		cpi->max_lun = 0;
4229f2c359fSNathan Whitehorn 		cpi->initiator_id = 7;
4239f2c359fSNathan Whitehorn 		cpi->bus_id = cam_sim_bus(sim);
4249f2c359fSNathan Whitehorn 		cpi->unit_number = cam_sim_unit(sim);
4259f2c359fSNathan Whitehorn 		cpi->base_transfer_speed = 150000;
4264195c7deSAlan Somers 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
4274195c7deSAlan Somers 		strlcpy(cpi->hba_vid, "Sony", HBA_IDLEN);
4284195c7deSAlan Somers 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
4299f2c359fSNathan Whitehorn 		cpi->transport = XPORT_SPI;
4309f2c359fSNathan Whitehorn 		cpi->transport_version = 2;
4319f2c359fSNathan Whitehorn 		cpi->protocol = PROTO_SCSI;
4329f2c359fSNathan Whitehorn 		cpi->protocol_version = SCSI_REV_2;
4339f2c359fSNathan Whitehorn 		cpi->maxio = PAGE_SIZE;
4349f2c359fSNathan Whitehorn 		cpi->ccb_h.status = CAM_REQ_CMP;
4359f2c359fSNathan Whitehorn 		break;
4369f2c359fSNathan Whitehorn 	}
4379f2c359fSNathan Whitehorn 	default:
4389f2c359fSNathan Whitehorn 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
4399f2c359fSNathan Whitehorn 		    ("unsupported function code 0x%02x\n",
4409f2c359fSNathan Whitehorn 		    ccb->ccb_h.func_code));
4419f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_REQ_INVALID;
4429f2c359fSNathan Whitehorn 		break;
4439f2c359fSNathan Whitehorn 	}
4449f2c359fSNathan Whitehorn 
4459f2c359fSNathan Whitehorn 	xpt_done(ccb);
4469f2c359fSNathan Whitehorn }
4479f2c359fSNathan Whitehorn 
4489f2c359fSNathan Whitehorn static void
4499f2c359fSNathan Whitehorn ps3cdrom_poll(struct cam_sim *sim)
4509f2c359fSNathan Whitehorn {
4519f2c359fSNathan Whitehorn 	ps3cdrom_intr(cam_sim_softc(sim));
4529f2c359fSNathan Whitehorn }
4539f2c359fSNathan Whitehorn 
4549f2c359fSNathan Whitehorn static void
4559f2c359fSNathan Whitehorn ps3cdrom_async(void *callback_arg, u_int32_t code,
4569f2c359fSNathan Whitehorn 	struct cam_path* path, void *arg)
4579f2c359fSNathan Whitehorn {
4589f2c359fSNathan Whitehorn 	switch (code) {
4599f2c359fSNathan Whitehorn 	case AC_LOST_DEVICE:
4609f2c359fSNathan Whitehorn 		xpt_print_path(path);
4619f2c359fSNathan Whitehorn 		break;
4629f2c359fSNathan Whitehorn 	default:
4639f2c359fSNathan Whitehorn 		break;
4649f2c359fSNathan Whitehorn 	}
4659f2c359fSNathan Whitehorn }
4669f2c359fSNathan Whitehorn 
4679f2c359fSNathan Whitehorn static void
4689f2c359fSNathan Whitehorn ps3cdrom_intr(void *arg)
4699f2c359fSNathan Whitehorn {
4709f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg;
4719f2c359fSNathan Whitehorn 	device_t dev = sc->sc_dev;
4729f2c359fSNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
4739f2c359fSNathan Whitehorn 	struct ps3cdrom_xfer *xp;
4749f2c359fSNathan Whitehorn 	union ccb *ccb;
4759f2c359fSNathan Whitehorn 	u_int8_t *cdb, sense_key, asc, ascq;
4769f2c359fSNathan Whitehorn 	uint64_t tag, status;
4779f2c359fSNathan Whitehorn 
4789f2c359fSNathan Whitehorn 	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
4799f2c359fSNathan Whitehorn 		return;
4809f2c359fSNathan Whitehorn 
4819f2c359fSNathan Whitehorn 	PS3CDROM_LOCK(sc);
4829f2c359fSNathan Whitehorn 
4839f2c359fSNathan Whitehorn 	/* Find transfer with the returned tag */
4849f2c359fSNathan Whitehorn 
4859f2c359fSNathan Whitehorn 	TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) {
4869f2c359fSNathan Whitehorn 		if (xp->x_tag == tag)
4879f2c359fSNathan Whitehorn 			break;
4889f2c359fSNathan Whitehorn 	}
4899f2c359fSNathan Whitehorn 
4909f2c359fSNathan Whitehorn 	if (xp) {
4919f2c359fSNathan Whitehorn 		ccb = xp->x_ccb;
4929f2c359fSNathan Whitehorn 		cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
4939f2c359fSNathan Whitehorn 			    ccb->csio.cdb_io.cdb_ptr :
4949f2c359fSNathan Whitehorn 			    ccb->csio.cdb_io.cdb_bytes;
4959f2c359fSNathan Whitehorn 
4969f2c359fSNathan Whitehorn 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
4979f2c359fSNathan Whitehorn 		   ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n",
4989f2c359fSNathan Whitehorn 		    cdb[0], tag, status));
4999f2c359fSNathan Whitehorn 
5009f2c359fSNathan Whitehorn 		if (!status) {
5019f2c359fSNathan Whitehorn 			ccb->csio.scsi_status = SCSI_STATUS_OK;
5029f2c359fSNathan Whitehorn 			ccb->csio.resid = 0;
5039f2c359fSNathan Whitehorn 			ccb->ccb_h.status = CAM_REQ_CMP;
5049f2c359fSNathan Whitehorn 		} else {
5059f2c359fSNathan Whitehorn 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
5069f2c359fSNathan Whitehorn 			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
5079f2c359fSNathan Whitehorn 
5089f2c359fSNathan Whitehorn 			if (!ps3cdrom_decode_lv1_status(status, &sense_key,
5099f2c359fSNathan Whitehorn 			    &asc, &ascq)) {
5109f2c359fSNathan Whitehorn 				CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
5119f2c359fSNathan Whitehorn 				   ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
5129f2c359fSNathan Whitehorn 				    sense_key, asc, ascq));
5139f2c359fSNathan Whitehorn 
5141cc052e8SKenneth D. Merry 				scsi_set_sense_data(&ccb->csio.sense_data,
5151cc052e8SKenneth D. Merry 				    /*sense_format*/ SSD_TYPE_NONE,
5161cc052e8SKenneth D. Merry 				    /*current_error*/ 1,
5171cc052e8SKenneth D. Merry 				    sense_key,
5181cc052e8SKenneth D. Merry 				    asc,
5191cc052e8SKenneth D. Merry 				    ascq,
5201cc052e8SKenneth D. Merry 				    SSD_ELEM_NONE);
5211cc052e8SKenneth D. Merry 				ccb->csio.sense_len = SSD_FULL_SIZE;
5229f2c359fSNathan Whitehorn 				ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
5239f2c359fSNathan Whitehorn 				    CAM_AUTOSNS_VALID;
5249f2c359fSNathan Whitehorn 			}
5259f2c359fSNathan Whitehorn 
5269f2c359fSNathan Whitehorn 			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
5279f2c359fSNathan Whitehorn 				ccb->csio.resid = ccb->csio.dxfer_len;
5289f2c359fSNathan Whitehorn 		}
5299f2c359fSNathan Whitehorn 
5309f2c359fSNathan Whitehorn 		if (ccb->ccb_h.flags & CAM_DIR_IN)
5319f2c359fSNathan Whitehorn 			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
5329f2c359fSNathan Whitehorn 			    BUS_DMASYNC_POSTREAD);
5339f2c359fSNathan Whitehorn 
5349f2c359fSNathan Whitehorn 		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
5359f2c359fSNathan Whitehorn 
5369f2c359fSNathan Whitehorn 		xp->x_ccb = NULL;
5379f2c359fSNathan Whitehorn 		TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
5389f2c359fSNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
5399f2c359fSNathan Whitehorn 
5409f2c359fSNathan Whitehorn 		xpt_done(ccb);
5419f2c359fSNathan Whitehorn 	} else {
5429f2c359fSNathan Whitehorn 		device_printf(dev,
5439f2c359fSNathan Whitehorn 		    "Could not find transfer with tag 0x%016lx\n",  tag);
5449f2c359fSNathan Whitehorn 	}
5459f2c359fSNathan Whitehorn 
5469f2c359fSNathan Whitehorn 	PS3CDROM_UNLOCK(sc);
5479f2c359fSNathan Whitehorn }
5489f2c359fSNathan Whitehorn 
5499f2c359fSNathan Whitehorn static void
5509f2c359fSNathan Whitehorn ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
5519f2c359fSNathan Whitehorn {
5529f2c359fSNathan Whitehorn 	struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
5539f2c359fSNathan Whitehorn 	struct ps3cdrom_softc *sc = xp->x_sc;
5549f2c359fSNathan Whitehorn 	device_t dev = sc->sc_dev;
5559f2c359fSNathan Whitehorn 	uint64_t devid = ps3bus_get_device(dev);
5569f2c359fSNathan Whitehorn 	union ccb *ccb = xp->x_ccb;
5579f2c359fSNathan Whitehorn 	u_int8_t *cdb;
5589f2c359fSNathan Whitehorn 	uint64_t start_sector, block_count;
5599f2c359fSNathan Whitehorn 	int err;
5609f2c359fSNathan Whitehorn 
56159b5b894SNathan Whitehorn 	KASSERT(nsegs == 1 || nsegs == 0,
56259b5b894SNathan Whitehorn 	    ("ps3cdrom_transfer: invalid number of DMA segments %d", nsegs));
56359b5b894SNathan Whitehorn 	KASSERT(error == 0, ("ps3cdrom_transfer: DMA error %d", error));
5649f2c359fSNathan Whitehorn 
5659f2c359fSNathan Whitehorn 	PS3CDROM_ASSERT_LOCKED(sc);
5669f2c359fSNathan Whitehorn 
5679f2c359fSNathan Whitehorn 	if (error) {
5689f2c359fSNathan Whitehorn 		device_printf(dev, "Could not load DMA map (%d)\n",  error);
5699f2c359fSNathan Whitehorn 
5709f2c359fSNathan Whitehorn 		xp->x_ccb = NULL;
5719f2c359fSNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
5729f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
5739f2c359fSNathan Whitehorn 		xpt_done(ccb);
5749f2c359fSNathan Whitehorn 		return;
5759f2c359fSNathan Whitehorn 	}
5769f2c359fSNathan Whitehorn 
5779f2c359fSNathan Whitehorn 	cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
5789f2c359fSNathan Whitehorn 		    ccb->csio.cdb_io.cdb_ptr :
5799f2c359fSNathan Whitehorn 		    ccb->csio.cdb_io.cdb_bytes;
5809f2c359fSNathan Whitehorn 
5819f2c359fSNathan Whitehorn 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
5829f2c359fSNathan Whitehorn 	   ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
5839f2c359fSNathan Whitehorn 	    ccb->csio.cdb_len, ccb->csio.dxfer_len));
5849f2c359fSNathan Whitehorn 
5859f2c359fSNathan Whitehorn 	switch (cdb[0]) {
5869f2c359fSNathan Whitehorn 	case READ_10:
58759b5b894SNathan Whitehorn 		KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to read"));
5889f2c359fSNathan Whitehorn 		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
5899f2c359fSNathan Whitehorn 		    (cdb[4] << 8) | cdb[5];
5909f2c359fSNathan Whitehorn 		block_count = (cdb[7] << 8) | cdb[8];
5919f2c359fSNathan Whitehorn 
5929f2c359fSNathan Whitehorn 		err = lv1_storage_read(devid, 0 /* region id */,
5939f2c359fSNathan Whitehorn 		    start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
5949f2c359fSNathan Whitehorn 		    &xp->x_tag);
5959f2c359fSNathan Whitehorn 		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
5969f2c359fSNathan Whitehorn 		    BUS_DMASYNC_POSTREAD);
5979f2c359fSNathan Whitehorn 		break;
5989f2c359fSNathan Whitehorn 	case WRITE_10:
59959b5b894SNathan Whitehorn 		KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to write"));
6009f2c359fSNathan Whitehorn 		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
6019f2c359fSNathan Whitehorn 		    (cdb[4] << 8) | cdb[5];
6029f2c359fSNathan Whitehorn 		block_count = (cdb[7] << 8) | cdb[8];
6039f2c359fSNathan Whitehorn 
6049f2c359fSNathan Whitehorn 		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
6059f2c359fSNathan Whitehorn 		    BUS_DMASYNC_PREWRITE);
6069f2c359fSNathan Whitehorn 		err = lv1_storage_write(devid, 0 /* region id */,
6079f2c359fSNathan Whitehorn 		    start_sector, block_count, 0 /* flags */,
6089f2c359fSNathan Whitehorn 		    segs[0].ds_addr, &xp->x_tag);
6099f2c359fSNathan Whitehorn 		break;
6109f2c359fSNathan Whitehorn 	default:
6119f2c359fSNathan Whitehorn 		{
6129f2c359fSNathan Whitehorn 		struct lv1_atapi_cmd atapi_cmd;
6139f2c359fSNathan Whitehorn 
6149f2c359fSNathan Whitehorn 		bzero(&atapi_cmd, sizeof(atapi_cmd));
6159f2c359fSNathan Whitehorn 		atapi_cmd.pktlen = 12;
6169f2c359fSNathan Whitehorn 		bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
6179f2c359fSNathan Whitehorn 
6189f2c359fSNathan Whitehorn 		if (ccb->ccb_h.flags & CAM_DIR_IN) {
6199f2c359fSNathan Whitehorn 			atapi_cmd.in_out = DIR_READ;
6209f2c359fSNathan Whitehorn 			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
6219f2c359fSNathan Whitehorn 			    DMA_PROTO : PIO_DATA_IN_PROTO;
6229f2c359fSNathan Whitehorn 		} else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
6239f2c359fSNathan Whitehorn 			atapi_cmd.in_out = DIR_WRITE;
6249f2c359fSNathan Whitehorn 			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
6259f2c359fSNathan Whitehorn 			    DMA_PROTO : PIO_DATA_OUT_PROTO;
6269f2c359fSNathan Whitehorn 		} else {
6279f2c359fSNathan Whitehorn 			atapi_cmd.proto = NON_DATA_PROTO;
6289f2c359fSNathan Whitehorn 		}
6299f2c359fSNathan Whitehorn 
63059b5b894SNathan Whitehorn 		atapi_cmd.nblocks = atapi_cmd.arglen =
63159b5b894SNathan Whitehorn 		    (nsegs == 0) ? 0 : segs[0].ds_len;
6329f2c359fSNathan Whitehorn 		atapi_cmd.blksize = 1;
63359b5b894SNathan Whitehorn 		atapi_cmd.buf = (nsegs == 0) ? 0 : segs[0].ds_addr;
6349f2c359fSNathan Whitehorn 
6359f2c359fSNathan Whitehorn 		if (ccb->ccb_h.flags & CAM_DIR_OUT)
6369f2c359fSNathan Whitehorn 			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
6379f2c359fSNathan Whitehorn 			    BUS_DMASYNC_PREWRITE);
6389f2c359fSNathan Whitehorn 
6399f2c359fSNathan Whitehorn 		err = lv1_storage_send_device_command(devid,
6409f2c359fSNathan Whitehorn 		    LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
6419f2c359fSNathan Whitehorn 		    sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
6429f2c359fSNathan Whitehorn 		    &xp->x_tag);
6439f2c359fSNathan Whitehorn 
6449f2c359fSNathan Whitehorn 		break;
6459f2c359fSNathan Whitehorn 		}
6469f2c359fSNathan Whitehorn 	}
6479f2c359fSNathan Whitehorn 
6489f2c359fSNathan Whitehorn 	if (err) {
6499f2c359fSNathan Whitehorn 		device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
6509f2c359fSNathan Whitehorn 		    cdb[0], err);
6519f2c359fSNathan Whitehorn 
6529f2c359fSNathan Whitehorn 		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
6539f2c359fSNathan Whitehorn 
6549f2c359fSNathan Whitehorn 		xp->x_ccb = NULL;
6559f2c359fSNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
6569f2c359fSNathan Whitehorn 
6571cc052e8SKenneth D. Merry 		bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
6581cc052e8SKenneth D. Merry 		/* Invalid field in parameter list */
6591cc052e8SKenneth D. Merry 		scsi_set_sense_data(&ccb->csio.sense_data,
6601cc052e8SKenneth D. Merry 				    /*sense_format*/ SSD_TYPE_NONE,
6611cc052e8SKenneth D. Merry 				    /*current_error*/ 1,
6621cc052e8SKenneth D. Merry 				    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
6631cc052e8SKenneth D. Merry 				    /*asc*/ 0x26,
6641cc052e8SKenneth D. Merry 				    /*ascq*/ 0x00,
6651cc052e8SKenneth D. Merry 				    SSD_ELEM_NONE);
6661cc052e8SKenneth D. Merry 
6671cc052e8SKenneth D. Merry 		ccb->csio.sense_len = SSD_FULL_SIZE;
6681cc052e8SKenneth D. Merry 		ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
6699f2c359fSNathan Whitehorn 		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
6709f2c359fSNathan Whitehorn 		xpt_done(ccb);
6719f2c359fSNathan Whitehorn 	} else {
6729f2c359fSNathan Whitehorn 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
6739f2c359fSNathan Whitehorn 		   ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
6749f2c359fSNathan Whitehorn 		   xp->x_tag));
6759f2c359fSNathan Whitehorn 
6769f2c359fSNathan Whitehorn 		TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
6779f2c359fSNathan Whitehorn 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
6789f2c359fSNathan Whitehorn 	}
6799f2c359fSNathan Whitehorn }
6809f2c359fSNathan Whitehorn 
6819f2c359fSNathan Whitehorn static int
6829f2c359fSNathan Whitehorn ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
6839f2c359fSNathan Whitehorn     u_int8_t *ascq)
6849f2c359fSNathan Whitehorn {
6859f2c359fSNathan Whitehorn 	if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
6869f2c359fSNathan Whitehorn 		return -1;
6879f2c359fSNathan Whitehorn 
6889f2c359fSNathan Whitehorn 	*sense_key = (status >> 16) & 0xff;
6899f2c359fSNathan Whitehorn 	*asc = (status >> 8) & 0xff;
6909f2c359fSNathan Whitehorn 	*ascq = status & 0xff;
6919f2c359fSNathan Whitehorn 
6929f2c359fSNathan Whitehorn 	return (0);
6939f2c359fSNathan Whitehorn }
6949f2c359fSNathan Whitehorn 
6959f2c359fSNathan Whitehorn static device_method_t ps3cdrom_methods[] = {
6969f2c359fSNathan Whitehorn 	DEVMETHOD(device_probe,		ps3cdrom_probe),
6979f2c359fSNathan Whitehorn 	DEVMETHOD(device_attach,	ps3cdrom_attach),
6989f2c359fSNathan Whitehorn 	DEVMETHOD(device_detach,	ps3cdrom_detach),
6999f2c359fSNathan Whitehorn 	{0, 0},
7009f2c359fSNathan Whitehorn };
7019f2c359fSNathan Whitehorn 
7029f2c359fSNathan Whitehorn static driver_t ps3cdrom_driver = {
7039f2c359fSNathan Whitehorn 	"ps3cdrom",
7049f2c359fSNathan Whitehorn 	ps3cdrom_methods,
7059f2c359fSNathan Whitehorn 	sizeof(struct ps3cdrom_softc),
7069f2c359fSNathan Whitehorn };
7079f2c359fSNathan Whitehorn 
708c331b0e4SJohn Baldwin DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, 0, 0);
7099f2c359fSNathan Whitehorn MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
710