ps3cdrom.c revision 224857
1224857Snwhitehorn/*-
2224857Snwhitehorn * Copyright (C) 2010 Nathan Whitehorn
3224857Snwhitehorn * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
4224857Snwhitehorn * All rights reserved.
5224857Snwhitehorn *
6224857Snwhitehorn * Redistribution and use in source and binary forms, with or without
7224857Snwhitehorn * modification, are permitted provided that the following conditions
8224857Snwhitehorn * are met:
9224857Snwhitehorn * 1. Redistributions of source code must retain the above copyright
10224857Snwhitehorn *    notice, this list of conditions and the following disclaimer,
11224857Snwhitehorn *    without modification, immediately at the beginning of the file.
12224857Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
13224857Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
14224857Snwhitehorn *    documentation and/or other materials provided with the distribution.
15224857Snwhitehorn *
16224857Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17224857Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18224857Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19224857Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20224857Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21224857Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22224857Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23224857Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24224857Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25224857Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26224857Snwhitehorn */
27224857Snwhitehorn
28224857Snwhitehorn#include <sys/cdefs.h>
29224857Snwhitehorn__FBSDID("$FreeBSD: head/sys/powerpc/ps3/ps3cdrom.c 224857 2011-08-14 00:20:37Z nwhitehorn $");
30224857Snwhitehorn
31224857Snwhitehorn#include <sys/param.h>
32224857Snwhitehorn#include <sys/module.h>
33224857Snwhitehorn#include <sys/systm.h>
34224857Snwhitehorn#include <sys/kernel.h>
35224857Snwhitehorn#include <sys/ata.h>
36224857Snwhitehorn#include <sys/bus.h>
37224857Snwhitehorn#include <sys/conf.h>
38224857Snwhitehorn#include <sys/kthread.h>
39224857Snwhitehorn#include <sys/lock.h>
40224857Snwhitehorn#include <sys/malloc.h>
41224857Snwhitehorn#include <sys/mutex.h>
42224857Snwhitehorn
43224857Snwhitehorn#include <vm/vm.h>
44224857Snwhitehorn#include <vm/pmap.h>
45224857Snwhitehorn
46224857Snwhitehorn#include <machine/pio.h>
47224857Snwhitehorn#include <machine/bus.h>
48224857Snwhitehorn#include <machine/platform.h>
49224857Snwhitehorn#include <machine/pmap.h>
50224857Snwhitehorn#include <machine/resource.h>
51224857Snwhitehorn#include <sys/bus.h>
52224857Snwhitehorn#include <sys/rman.h>
53224857Snwhitehorn
54224857Snwhitehorn#include <cam/cam.h>
55224857Snwhitehorn#include <cam/cam_ccb.h>
56224857Snwhitehorn#include <cam/cam_sim.h>
57224857Snwhitehorn#include <cam/cam_xpt_sim.h>
58224857Snwhitehorn#include <cam/cam_debug.h>
59224857Snwhitehorn#include <cam/scsi/scsi_all.h>
60224857Snwhitehorn
61224857Snwhitehorn#include "ps3bus.h"
62224857Snwhitehorn#include "ps3-hvcall.h"
63224857Snwhitehorn
64224857Snwhitehorn#define PS3CDROM_LOCK_INIT(_sc)		\
65224857Snwhitehorn	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \
66224857Snwhitehorn	    MTX_DEF)
67224857Snwhitehorn#define PS3CDROM_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
68224857Snwhitehorn#define PS3CDROM_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
69224857Snwhitehorn#define	PS3CDROM_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
70224857Snwhitehorn#define PS3CDROM_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
71224857Snwhitehorn#define PS3CDROM_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
72224857Snwhitehorn
73224857Snwhitehorn#define PS3CDROM_MAX_XFERS		3
74224857Snwhitehorn
75224857Snwhitehorn#define	LV1_STORAGE_SEND_ATAPI_COMMAND	0x01
76224857Snwhitehorn
77224857Snwhitehornstruct ps3cdrom_softc;
78224857Snwhitehorn
79224857Snwhitehornstruct ps3cdrom_xfer {
80224857Snwhitehorn	TAILQ_ENTRY(ps3cdrom_xfer) x_queue;
81224857Snwhitehorn	struct ps3cdrom_softc *x_sc;
82224857Snwhitehorn	union ccb *x_ccb;
83224857Snwhitehorn	bus_dmamap_t x_dmamap;
84224857Snwhitehorn	uint64_t x_tag;
85224857Snwhitehorn};
86224857Snwhitehorn
87224857SnwhitehornTAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
88224857Snwhitehorn
89224857Snwhitehornstruct ps3cdrom_softc {
90224857Snwhitehorn	device_t sc_dev;
91224857Snwhitehorn
92224857Snwhitehorn	struct mtx sc_mtx;
93224857Snwhitehorn
94224857Snwhitehorn	uint64_t sc_blksize;
95224857Snwhitehorn	uint64_t sc_nblocks;
96224857Snwhitehorn
97224857Snwhitehorn	int sc_irqid;
98224857Snwhitehorn	struct resource	*sc_irq;
99224857Snwhitehorn	void *sc_irqctx;
100224857Snwhitehorn
101224857Snwhitehorn	bus_dma_tag_t sc_dmatag;
102224857Snwhitehorn
103224857Snwhitehorn	struct cam_sim *sc_sim;
104224857Snwhitehorn	struct cam_path *sc_path;
105224857Snwhitehorn
106224857Snwhitehorn	struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS];
107224857Snwhitehorn	struct ps3cdrom_xferq sc_active_xferq;
108224857Snwhitehorn	struct ps3cdrom_xferq sc_free_xferq;
109224857Snwhitehorn};
110224857Snwhitehorn
111224857Snwhitehornenum lv1_ata_proto {
112224857Snwhitehorn	NON_DATA_PROTO		= 0x00,
113224857Snwhitehorn	PIO_DATA_IN_PROTO	= 0x01,
114224857Snwhitehorn	PIO_DATA_OUT_PROTO	= 0x02,
115224857Snwhitehorn	DMA_PROTO		= 0x03
116224857Snwhitehorn};
117224857Snwhitehorn
118224857Snwhitehornenum lv1_ata_in_out {
119224857Snwhitehorn	DIR_WRITE		= 0x00,
120224857Snwhitehorn	DIR_READ		= 0x01
121224857Snwhitehorn};
122224857Snwhitehorn
123224857Snwhitehornstruct lv1_atapi_cmd {
124224857Snwhitehorn	uint8_t pkt[32];
125224857Snwhitehorn	uint32_t pktlen;
126224857Snwhitehorn	uint32_t nblocks;
127224857Snwhitehorn	uint32_t blksize;
128224857Snwhitehorn	uint32_t proto;		/* enum lv1_ata_proto */
129224857Snwhitehorn	uint32_t in_out;	/* enum lv1_ata_in_out */
130224857Snwhitehorn	uint64_t buf;
131224857Snwhitehorn	uint32_t arglen;
132224857Snwhitehorn};
133224857Snwhitehorn
134224857Snwhitehornstatic void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
135224857Snwhitehornstatic void ps3cdrom_poll(struct cam_sim *sim);
136224857Snwhitehornstatic void ps3cdrom_async(void *callback_arg, u_int32_t code,
137224857Snwhitehorn    struct cam_path* path, void *arg);
138224857Snwhitehorn
139224857Snwhitehornstatic void ps3cdrom_intr(void *arg);
140224857Snwhitehorn
141224857Snwhitehornstatic void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
142224857Snwhitehorn    int error);
143224857Snwhitehorn
144224857Snwhitehornstatic int ps3cdrom_decode_lv1_status(uint64_t status,
145224857Snwhitehorn	u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
146224857Snwhitehorn
147224857Snwhitehornstatic int
148224857Snwhitehornps3cdrom_probe(device_t dev)
149224857Snwhitehorn{
150224857Snwhitehorn	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
151224857Snwhitehorn	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM)
152224857Snwhitehorn		return (ENXIO);
153224857Snwhitehorn
154224857Snwhitehorn	device_set_desc(dev, "Playstation 3 CDROM");
155224857Snwhitehorn
156224857Snwhitehorn	return (BUS_PROBE_SPECIFIC);
157224857Snwhitehorn}
158224857Snwhitehorn
159224857Snwhitehornstatic int
160224857Snwhitehornps3cdrom_attach(device_t dev)
161224857Snwhitehorn{
162224857Snwhitehorn	struct ps3cdrom_softc *sc = device_get_softc(dev);
163224857Snwhitehorn	struct cam_devq *devq;
164224857Snwhitehorn	struct ps3cdrom_xfer *xp;
165224857Snwhitehorn	struct ccb_setasync csa;
166224857Snwhitehorn	int i, err;
167224857Snwhitehorn
168224857Snwhitehorn	sc->sc_dev = dev;
169224857Snwhitehorn
170224857Snwhitehorn	PS3CDROM_LOCK_INIT(sc);
171224857Snwhitehorn
172224857Snwhitehorn	/* Setup interrupt handler */
173224857Snwhitehorn
174224857Snwhitehorn	sc->sc_irqid = 0;
175224857Snwhitehorn	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
176224857Snwhitehorn	    RF_ACTIVE);
177224857Snwhitehorn	if (!sc->sc_irq) {
178224857Snwhitehorn		device_printf(dev, "Could not allocate IRQ\n");
179224857Snwhitehorn		err = ENXIO;
180224857Snwhitehorn		goto fail_destroy_lock;
181224857Snwhitehorn	}
182224857Snwhitehorn
183224857Snwhitehorn	err = bus_setup_intr(dev, sc->sc_irq,
184224857Snwhitehorn	    INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
185224857Snwhitehorn	    NULL, ps3cdrom_intr, sc, &sc->sc_irqctx);
186224857Snwhitehorn	if (err) {
187224857Snwhitehorn		device_printf(dev, "Could not setup IRQ\n");
188224857Snwhitehorn		err = ENXIO;
189224857Snwhitehorn		goto fail_release_intr;
190224857Snwhitehorn	}
191224857Snwhitehorn
192224857Snwhitehorn	/* Setup DMA */
193224857Snwhitehorn
194224857Snwhitehorn	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
195224857Snwhitehorn	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
196224857Snwhitehorn	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
197224857Snwhitehorn	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
198224857Snwhitehorn	if (err) {
199224857Snwhitehorn		device_printf(dev, "Could not create DMA tag\n");
200224857Snwhitehorn		err = ENXIO;
201224857Snwhitehorn		goto fail_teardown_intr;
202224857Snwhitehorn	}
203224857Snwhitehorn
204224857Snwhitehorn	/* Setup transfer queues */
205224857Snwhitehorn
206224857Snwhitehorn	TAILQ_INIT(&sc->sc_active_xferq);
207224857Snwhitehorn	TAILQ_INIT(&sc->sc_free_xferq);
208224857Snwhitehorn
209224857Snwhitehorn	for (i = 0; i < PS3CDROM_MAX_XFERS; i++) {
210224857Snwhitehorn		xp = &sc->sc_xfer[i];
211224857Snwhitehorn		xp->x_sc = sc;
212224857Snwhitehorn
213224857Snwhitehorn		err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
214224857Snwhitehorn		    &xp->x_dmamap);
215224857Snwhitehorn		if (err) {
216224857Snwhitehorn			device_printf(dev, "Could not create DMA map (%d)\n",
217224857Snwhitehorn			    err);
218224857Snwhitehorn			goto fail_destroy_dmamap;
219224857Snwhitehorn		}
220224857Snwhitehorn
221224857Snwhitehorn		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
222224857Snwhitehorn	}
223224857Snwhitehorn
224224857Snwhitehorn	/* Setup CAM */
225224857Snwhitehorn
226224857Snwhitehorn	devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1);
227224857Snwhitehorn	if (!devq) {
228224857Snwhitehorn		device_printf(dev, "Could not allocate SIM queue\n");
229224857Snwhitehorn		err = ENOMEM;
230224857Snwhitehorn		goto fail_destroy_dmatag;
231224857Snwhitehorn	}
232224857Snwhitehorn
233224857Snwhitehorn	sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom",
234224857Snwhitehorn	    sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0,
235224857Snwhitehorn	    devq);
236224857Snwhitehorn	if (!sc->sc_sim) {
237224857Snwhitehorn		device_printf(dev, "Could not allocate SIM\n");
238224857Snwhitehorn		cam_simq_free(devq);
239224857Snwhitehorn		err = ENOMEM;
240224857Snwhitehorn		goto fail_destroy_dmatag;
241224857Snwhitehorn	}
242224857Snwhitehorn
243224857Snwhitehorn	/* Setup XPT */
244224857Snwhitehorn
245224857Snwhitehorn	PS3CDROM_LOCK(sc);
246224857Snwhitehorn
247224857Snwhitehorn	err = xpt_bus_register(sc->sc_sim, dev, 0);
248224857Snwhitehorn	if (err != CAM_SUCCESS) {
249224857Snwhitehorn		device_printf(dev, "Could not register XPT bus\n");
250224857Snwhitehorn		err = ENXIO;
251224857Snwhitehorn		PS3CDROM_UNLOCK(sc);
252224857Snwhitehorn		goto fail_free_sim;
253224857Snwhitehorn	}
254224857Snwhitehorn
255224857Snwhitehorn	err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim),
256224857Snwhitehorn	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
257224857Snwhitehorn	if (err != CAM_REQ_CMP) {
258224857Snwhitehorn		device_printf(dev, "Could not create XPT path\n");
259224857Snwhitehorn		err = ENOMEM;
260224857Snwhitehorn		PS3CDROM_UNLOCK(sc);
261224857Snwhitehorn		goto fail_unregister_xpt_bus;
262224857Snwhitehorn	}
263224857Snwhitehorn
264224857Snwhitehorn	xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5);
265224857Snwhitehorn	csa.ccb_h.func_code = XPT_SASYNC_CB;
266224857Snwhitehorn	csa.event_enable = AC_LOST_DEVICE;
267224857Snwhitehorn	csa.callback = ps3cdrom_async;
268224857Snwhitehorn	csa.callback_arg = sc->sc_sim;
269224857Snwhitehorn	xpt_action((union ccb *) &csa);
270224857Snwhitehorn
271224857Snwhitehorn	CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE,
272224857Snwhitehorn	    ("registered SIM for ps3cdrom%d\n", device_get_unit(dev)));
273224857Snwhitehorn
274224857Snwhitehorn	PS3CDROM_UNLOCK(sc);
275224857Snwhitehorn
276224857Snwhitehorn	return (BUS_PROBE_SPECIFIC);
277224857Snwhitehorn
278224857Snwhitehornfail_unregister_xpt_bus:
279224857Snwhitehorn
280224857Snwhitehorn	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
281224857Snwhitehorn
282224857Snwhitehornfail_free_sim:
283224857Snwhitehorn
284224857Snwhitehorn	cam_sim_free(sc->sc_sim, TRUE);
285224857Snwhitehorn
286224857Snwhitehornfail_destroy_dmamap:
287224857Snwhitehorn
288224857Snwhitehorn	while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) {
289224857Snwhitehorn		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
290224857Snwhitehorn		bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap);
291224857Snwhitehorn	}
292224857Snwhitehorn
293224857Snwhitehornfail_destroy_dmatag:
294224857Snwhitehorn
295224857Snwhitehorn	bus_dma_tag_destroy(sc->sc_dmatag);
296224857Snwhitehorn
297224857Snwhitehornfail_teardown_intr:
298224857Snwhitehorn
299224857Snwhitehorn	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
300224857Snwhitehorn
301224857Snwhitehornfail_release_intr:
302224857Snwhitehorn
303224857Snwhitehorn	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
304224857Snwhitehorn
305224857Snwhitehornfail_destroy_lock:
306224857Snwhitehorn
307224857Snwhitehorn	PS3CDROM_LOCK_DESTROY(sc);
308224857Snwhitehorn
309224857Snwhitehorn	return (err);
310224857Snwhitehorn}
311224857Snwhitehorn
312224857Snwhitehornstatic int
313224857Snwhitehornps3cdrom_detach(device_t dev)
314224857Snwhitehorn{
315224857Snwhitehorn	struct ps3cdrom_softc *sc = device_get_softc(dev);
316224857Snwhitehorn	int i;
317224857Snwhitehorn
318224857Snwhitehorn	xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL);
319224857Snwhitehorn	xpt_free_path(sc->sc_path);
320224857Snwhitehorn	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
321224857Snwhitehorn	cam_sim_free(sc->sc_sim, TRUE);
322224857Snwhitehorn
323224857Snwhitehorn	for (i = 0; i < PS3CDROM_MAX_XFERS; i++)
324224857Snwhitehorn		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap);
325224857Snwhitehorn
326224857Snwhitehorn	bus_dma_tag_destroy(sc->sc_dmatag);
327224857Snwhitehorn
328224857Snwhitehorn	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
329224857Snwhitehorn	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
330224857Snwhitehorn
331224857Snwhitehorn	PS3CDROM_LOCK_DESTROY(sc);
332224857Snwhitehorn
333224857Snwhitehorn	return (0);
334224857Snwhitehorn}
335224857Snwhitehorn
336224857Snwhitehornstatic void
337224857Snwhitehornps3cdrom_action(struct cam_sim *sim, union ccb *ccb)
338224857Snwhitehorn{
339224857Snwhitehorn	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim);
340224857Snwhitehorn	device_t dev = sc->sc_dev;
341224857Snwhitehorn	struct ps3cdrom_xfer *xp;
342224857Snwhitehorn	int err;
343224857Snwhitehorn
344224857Snwhitehorn	PS3CDROM_ASSERT_LOCKED(sc);
345224857Snwhitehorn
346224857Snwhitehorn	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
347224857Snwhitehorn	   ("function code 0x%02x\n", ccb->ccb_h.func_code));
348224857Snwhitehorn
349224857Snwhitehorn	switch (ccb->ccb_h.func_code) {
350224857Snwhitehorn	case XPT_SCSI_IO:
351224857Snwhitehorn		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG)
352224857Snwhitehorn			break;
353224857Snwhitehorn
354224857Snwhitehorn		if(ccb->ccb_h.target_id > 0) {
355224857Snwhitehorn			ccb->ccb_h.status = CAM_TID_INVALID;
356224857Snwhitehorn			break;
357224857Snwhitehorn		}
358224857Snwhitehorn
359224857Snwhitehorn		if(ccb->ccb_h.target_lun > 0) {
360224857Snwhitehorn			ccb->ccb_h.status = CAM_LUN_INVALID;
361224857Snwhitehorn			break;
362224857Snwhitehorn		}
363224857Snwhitehorn
364224857Snwhitehorn		xp = TAILQ_FIRST(&sc->sc_free_xferq);
365224857Snwhitehorn
366224857Snwhitehorn		KASSERT(xp != NULL, ("no free transfers"));
367224857Snwhitehorn
368224857Snwhitehorn		xp->x_ccb = ccb;
369224857Snwhitehorn
370224857Snwhitehorn		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
371224857Snwhitehorn
372224857Snwhitehorn		err = bus_dmamap_load(sc->sc_dmatag, xp->x_dmamap,
373224857Snwhitehorn		    ccb->csio.data_ptr, ccb->csio.dxfer_len, ps3cdrom_transfer,
374224857Snwhitehorn		    xp, 0);
375224857Snwhitehorn		if (err && err != EINPROGRESS) {
376224857Snwhitehorn			device_printf(dev, "Could not load DMA map (%d)\n",
377224857Snwhitehorn			    err);
378224857Snwhitehorn
379224857Snwhitehorn			xp->x_ccb = NULL;
380224857Snwhitehorn			TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
381224857Snwhitehorn			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
382224857Snwhitehorn			break;
383224857Snwhitehorn		}
384224857Snwhitehorn		return;
385224857Snwhitehorn	case XPT_SET_TRAN_SETTINGS:
386224857Snwhitehorn		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
387224857Snwhitehorn		break;
388224857Snwhitehorn	case XPT_GET_TRAN_SETTINGS:
389224857Snwhitehorn	{
390224857Snwhitehorn		struct ccb_trans_settings *cts = &ccb->cts;
391224857Snwhitehorn
392224857Snwhitehorn		cts->protocol = PROTO_SCSI;
393224857Snwhitehorn		cts->protocol_version = SCSI_REV_2;
394224857Snwhitehorn		cts->transport = XPORT_SPI;
395224857Snwhitehorn		cts->transport_version = 2;
396224857Snwhitehorn		cts->proto_specific.valid = 0;
397224857Snwhitehorn		cts->xport_specific.valid = 0;
398224857Snwhitehorn		ccb->ccb_h.status = CAM_REQ_CMP;
399224857Snwhitehorn		break;
400224857Snwhitehorn	}
401224857Snwhitehorn	case XPT_RESET_BUS:
402224857Snwhitehorn	case XPT_RESET_DEV:
403224857Snwhitehorn		ccb->ccb_h.status = CAM_REQ_CMP;
404224857Snwhitehorn		break;
405224857Snwhitehorn	case XPT_CALC_GEOMETRY:
406224857Snwhitehorn		cam_calc_geometry(&ccb->ccg, 1);
407224857Snwhitehorn		break;
408224857Snwhitehorn	case XPT_PATH_INQ:
409224857Snwhitehorn	{
410224857Snwhitehorn		struct ccb_pathinq *cpi = &ccb->cpi;
411224857Snwhitehorn
412224857Snwhitehorn		cpi->version_num = 1;
413224857Snwhitehorn		cpi->hba_inquiry = 0;
414224857Snwhitehorn		cpi->target_sprt = 0;
415224857Snwhitehorn		cpi->hba_inquiry = PI_SDTR_ABLE;
416224857Snwhitehorn		cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE;
417224857Snwhitehorn		cpi->hba_eng_cnt = 0;
418224857Snwhitehorn		bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
419224857Snwhitehorn		cpi->max_target = 0;
420224857Snwhitehorn		cpi->max_lun = 0;
421224857Snwhitehorn		cpi->initiator_id = 7;
422224857Snwhitehorn		cpi->bus_id = cam_sim_bus(sim);
423224857Snwhitehorn		cpi->unit_number = cam_sim_unit(sim);
424224857Snwhitehorn		cpi->base_transfer_speed = 150000;
425224857Snwhitehorn		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
426224857Snwhitehorn		strncpy(cpi->hba_vid, "Sony", HBA_IDLEN);
427224857Snwhitehorn		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
428224857Snwhitehorn		cpi->transport = XPORT_SPI;
429224857Snwhitehorn		cpi->transport_version = 2;
430224857Snwhitehorn		cpi->protocol = PROTO_SCSI;
431224857Snwhitehorn		cpi->protocol_version = SCSI_REV_2;
432224857Snwhitehorn		cpi->maxio = PAGE_SIZE;
433224857Snwhitehorn		cpi->ccb_h.status = CAM_REQ_CMP;
434224857Snwhitehorn		break;
435224857Snwhitehorn	}
436224857Snwhitehorn	default:
437224857Snwhitehorn		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
438224857Snwhitehorn		    ("unsupported function code 0x%02x\n",
439224857Snwhitehorn		    ccb->ccb_h.func_code));
440224857Snwhitehorn		ccb->ccb_h.status = CAM_REQ_INVALID;
441224857Snwhitehorn		break;
442224857Snwhitehorn	}
443224857Snwhitehorn
444224857Snwhitehorn	xpt_done(ccb);
445224857Snwhitehorn}
446224857Snwhitehorn
447224857Snwhitehornstatic void
448224857Snwhitehornps3cdrom_poll(struct cam_sim *sim)
449224857Snwhitehorn{
450224857Snwhitehorn	ps3cdrom_intr(cam_sim_softc(sim));
451224857Snwhitehorn}
452224857Snwhitehorn
453224857Snwhitehornstatic void
454224857Snwhitehornps3cdrom_async(void *callback_arg, u_int32_t code,
455224857Snwhitehorn	struct cam_path* path, void *arg)
456224857Snwhitehorn{
457224857Snwhitehorn	switch (code) {
458224857Snwhitehorn	case AC_LOST_DEVICE:
459224857Snwhitehorn		xpt_print_path(path);
460224857Snwhitehorn		break;
461224857Snwhitehorn	default:
462224857Snwhitehorn		break;
463224857Snwhitehorn	}
464224857Snwhitehorn}
465224857Snwhitehorn
466224857Snwhitehornstatic void
467224857Snwhitehornps3cdrom_intr(void *arg)
468224857Snwhitehorn{
469224857Snwhitehorn	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg;
470224857Snwhitehorn	device_t dev = sc->sc_dev;
471224857Snwhitehorn	uint64_t devid = ps3bus_get_device(dev);
472224857Snwhitehorn	struct ps3cdrom_xfer *xp;
473224857Snwhitehorn	union ccb *ccb;
474224857Snwhitehorn	u_int8_t *cdb, sense_key, asc, ascq;
475224857Snwhitehorn	uint64_t tag, status;
476224857Snwhitehorn
477224857Snwhitehorn	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
478224857Snwhitehorn		return;
479224857Snwhitehorn
480224857Snwhitehorn	PS3CDROM_LOCK(sc);
481224857Snwhitehorn
482224857Snwhitehorn	/* Find transfer with the returned tag */
483224857Snwhitehorn
484224857Snwhitehorn	TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) {
485224857Snwhitehorn		if (xp->x_tag == tag)
486224857Snwhitehorn			break;
487224857Snwhitehorn	}
488224857Snwhitehorn
489224857Snwhitehorn	if (xp) {
490224857Snwhitehorn		ccb = xp->x_ccb;
491224857Snwhitehorn		cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
492224857Snwhitehorn			    ccb->csio.cdb_io.cdb_ptr :
493224857Snwhitehorn			    ccb->csio.cdb_io.cdb_bytes;
494224857Snwhitehorn
495224857Snwhitehorn		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
496224857Snwhitehorn		   ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n",
497224857Snwhitehorn		    cdb[0], tag, status));
498224857Snwhitehorn
499224857Snwhitehorn		if (!status) {
500224857Snwhitehorn			ccb->csio.scsi_status = SCSI_STATUS_OK;
501224857Snwhitehorn			ccb->csio.resid = 0;
502224857Snwhitehorn			ccb->ccb_h.status = CAM_REQ_CMP;
503224857Snwhitehorn		} else {
504224857Snwhitehorn			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
505224857Snwhitehorn			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
506224857Snwhitehorn
507224857Snwhitehorn			if (!ps3cdrom_decode_lv1_status(status, &sense_key,
508224857Snwhitehorn			    &asc, &ascq)) {
509224857Snwhitehorn				struct scsi_sense_data sense_data;
510224857Snwhitehorn
511224857Snwhitehorn				CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
512224857Snwhitehorn				   ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
513224857Snwhitehorn				    sense_key, asc, ascq));
514224857Snwhitehorn
515224857Snwhitehorn				bzero(&sense_data, sizeof(sense_data));
516224857Snwhitehorn				sense_data.error_code = SSD_CURRENT_ERROR;
517224857Snwhitehorn				sense_data.flags |= sense_key;
518224857Snwhitehorn				sense_data.extra_len = 0xa;
519224857Snwhitehorn				sense_data.add_sense_code = asc;
520224857Snwhitehorn				sense_data.add_sense_code_qual = ascq;
521224857Snwhitehorn				ccb->csio.sense_len = sizeof(sense_data);
522224857Snwhitehorn				bcopy(&sense_data, &ccb->csio.sense_data,
523224857Snwhitehorn				    ccb->csio.sense_len);
524224857Snwhitehorn				ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
525224857Snwhitehorn				    CAM_AUTOSNS_VALID;
526224857Snwhitehorn			}
527224857Snwhitehorn
528224857Snwhitehorn			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
529224857Snwhitehorn				ccb->csio.resid = ccb->csio.dxfer_len;
530224857Snwhitehorn		}
531224857Snwhitehorn
532224857Snwhitehorn		if (ccb->ccb_h.flags & CAM_DIR_IN)
533224857Snwhitehorn			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
534224857Snwhitehorn			    BUS_DMASYNC_POSTREAD);
535224857Snwhitehorn
536224857Snwhitehorn		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
537224857Snwhitehorn
538224857Snwhitehorn		xp->x_ccb = NULL;
539224857Snwhitehorn		TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
540224857Snwhitehorn		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
541224857Snwhitehorn
542224857Snwhitehorn		xpt_done(ccb);
543224857Snwhitehorn	} else {
544224857Snwhitehorn		device_printf(dev,
545224857Snwhitehorn		    "Could not find transfer with tag 0x%016lx\n",  tag);
546224857Snwhitehorn	}
547224857Snwhitehorn
548224857Snwhitehorn	PS3CDROM_UNLOCK(sc);
549224857Snwhitehorn}
550224857Snwhitehorn
551224857Snwhitehornstatic void
552224857Snwhitehornps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
553224857Snwhitehorn{
554224857Snwhitehorn	struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
555224857Snwhitehorn	struct ps3cdrom_softc *sc = xp->x_sc;
556224857Snwhitehorn	device_t dev = sc->sc_dev;
557224857Snwhitehorn	uint64_t devid = ps3bus_get_device(dev);
558224857Snwhitehorn	union ccb *ccb = xp->x_ccb;
559224857Snwhitehorn	u_int8_t *cdb;
560224857Snwhitehorn	uint64_t start_sector, block_count;
561224857Snwhitehorn	int err;
562224857Snwhitehorn
563224857Snwhitehorn	KASSERT(nsegs == 1, ("invalid number of DMA segments"));
564224857Snwhitehorn
565224857Snwhitehorn	PS3CDROM_ASSERT_LOCKED(sc);
566224857Snwhitehorn
567224857Snwhitehorn	if (error) {
568224857Snwhitehorn		device_printf(dev, "Could not load DMA map (%d)\n",  error);
569224857Snwhitehorn
570224857Snwhitehorn		xp->x_ccb = NULL;
571224857Snwhitehorn		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
572224857Snwhitehorn		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
573224857Snwhitehorn		xpt_done(ccb);
574224857Snwhitehorn		return;
575224857Snwhitehorn	}
576224857Snwhitehorn
577224857Snwhitehorn	cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
578224857Snwhitehorn		    ccb->csio.cdb_io.cdb_ptr :
579224857Snwhitehorn		    ccb->csio.cdb_io.cdb_bytes;
580224857Snwhitehorn
581224857Snwhitehorn	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
582224857Snwhitehorn	   ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
583224857Snwhitehorn	    ccb->csio.cdb_len, ccb->csio.dxfer_len));
584224857Snwhitehorn
585224857Snwhitehorn	switch (cdb[0]) {
586224857Snwhitehorn	case READ_10:
587224857Snwhitehorn		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
588224857Snwhitehorn		    (cdb[4] << 8) | cdb[5];
589224857Snwhitehorn		block_count = (cdb[7] << 8) | cdb[8];
590224857Snwhitehorn
591224857Snwhitehorn		err = lv1_storage_read(devid, 0 /* region id */,
592224857Snwhitehorn		    start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
593224857Snwhitehorn		    &xp->x_tag);
594224857Snwhitehorn		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
595224857Snwhitehorn		    BUS_DMASYNC_POSTREAD);
596224857Snwhitehorn		break;
597224857Snwhitehorn	case WRITE_10:
598224857Snwhitehorn		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
599224857Snwhitehorn		    (cdb[4] << 8) | cdb[5];
600224857Snwhitehorn		block_count = (cdb[7] << 8) | cdb[8];
601224857Snwhitehorn
602224857Snwhitehorn		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
603224857Snwhitehorn		    BUS_DMASYNC_PREWRITE);
604224857Snwhitehorn		err = lv1_storage_write(devid, 0 /* region id */,
605224857Snwhitehorn		    start_sector, block_count, 0 /* flags */,
606224857Snwhitehorn		    segs[0].ds_addr, &xp->x_tag);
607224857Snwhitehorn		break;
608224857Snwhitehorn	default:
609224857Snwhitehorn		{
610224857Snwhitehorn		struct lv1_atapi_cmd atapi_cmd;
611224857Snwhitehorn
612224857Snwhitehorn		bzero(&atapi_cmd, sizeof(atapi_cmd));
613224857Snwhitehorn		atapi_cmd.pktlen = 12;
614224857Snwhitehorn		bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
615224857Snwhitehorn
616224857Snwhitehorn		if (ccb->ccb_h.flags & CAM_DIR_IN) {
617224857Snwhitehorn			atapi_cmd.in_out = DIR_READ;
618224857Snwhitehorn			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
619224857Snwhitehorn			    DMA_PROTO : PIO_DATA_IN_PROTO;
620224857Snwhitehorn		} else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
621224857Snwhitehorn			atapi_cmd.in_out = DIR_WRITE;
622224857Snwhitehorn			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
623224857Snwhitehorn			    DMA_PROTO : PIO_DATA_OUT_PROTO;
624224857Snwhitehorn		} else {
625224857Snwhitehorn			atapi_cmd.proto = NON_DATA_PROTO;
626224857Snwhitehorn		}
627224857Snwhitehorn
628224857Snwhitehorn		atapi_cmd.nblocks = atapi_cmd.arglen = segs[0].ds_len;
629224857Snwhitehorn		atapi_cmd.blksize = 1;
630224857Snwhitehorn		atapi_cmd.buf = segs[0].ds_addr;
631224857Snwhitehorn
632224857Snwhitehorn		if (ccb->ccb_h.flags & CAM_DIR_OUT)
633224857Snwhitehorn			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
634224857Snwhitehorn			    BUS_DMASYNC_PREWRITE);
635224857Snwhitehorn
636224857Snwhitehorn		err = lv1_storage_send_device_command(devid,
637224857Snwhitehorn		    LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
638224857Snwhitehorn		    sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
639224857Snwhitehorn		    &xp->x_tag);
640224857Snwhitehorn
641224857Snwhitehorn		break;
642224857Snwhitehorn		}
643224857Snwhitehorn	}
644224857Snwhitehorn
645224857Snwhitehorn	if (err) {
646224857Snwhitehorn		struct scsi_sense_data sense_data;
647224857Snwhitehorn
648224857Snwhitehorn		device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
649224857Snwhitehorn		    cdb[0], err);
650224857Snwhitehorn
651224857Snwhitehorn		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
652224857Snwhitehorn
653224857Snwhitehorn		xp->x_ccb = NULL;
654224857Snwhitehorn		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
655224857Snwhitehorn
656224857Snwhitehorn		bzero(&sense_data, sizeof(sense_data));
657224857Snwhitehorn		sense_data.error_code = SSD_CURRENT_ERROR;
658224857Snwhitehorn		sense_data.flags |= SSD_KEY_ILLEGAL_REQUEST;
659224857Snwhitehorn		ccb->csio.sense_len = sizeof(sense_data);
660224857Snwhitehorn		bcopy(&sense_data, &ccb->csio.sense_data, ccb->csio.sense_len);
661224857Snwhitehorn		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
662224857Snwhitehorn		xpt_done(ccb);
663224857Snwhitehorn	} else {
664224857Snwhitehorn		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
665224857Snwhitehorn		   ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
666224857Snwhitehorn		   xp->x_tag));
667224857Snwhitehorn
668224857Snwhitehorn		TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
669224857Snwhitehorn		ccb->ccb_h.status |= CAM_SIM_QUEUED;
670224857Snwhitehorn	}
671224857Snwhitehorn}
672224857Snwhitehorn
673224857Snwhitehornstatic int
674224857Snwhitehornps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
675224857Snwhitehorn    u_int8_t *ascq)
676224857Snwhitehorn{
677224857Snwhitehorn	if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
678224857Snwhitehorn		return -1;
679224857Snwhitehorn
680224857Snwhitehorn	*sense_key = (status >> 16) & 0xff;
681224857Snwhitehorn	*asc = (status >> 8) & 0xff;
682224857Snwhitehorn	*ascq = status & 0xff;
683224857Snwhitehorn
684224857Snwhitehorn	return (0);
685224857Snwhitehorn}
686224857Snwhitehorn
687224857Snwhitehornstatic device_method_t ps3cdrom_methods[] = {
688224857Snwhitehorn	DEVMETHOD(device_probe,		ps3cdrom_probe),
689224857Snwhitehorn	DEVMETHOD(device_attach,	ps3cdrom_attach),
690224857Snwhitehorn	DEVMETHOD(device_detach,	ps3cdrom_detach),
691224857Snwhitehorn	{0, 0},
692224857Snwhitehorn};
693224857Snwhitehorn
694224857Snwhitehornstatic driver_t ps3cdrom_driver = {
695224857Snwhitehorn	"ps3cdrom",
696224857Snwhitehorn	ps3cdrom_methods,
697224857Snwhitehorn	sizeof(struct ps3cdrom_softc),
698224857Snwhitehorn};
699224857Snwhitehorn
700224857Snwhitehornstatic devclass_t ps3cdrom_devclass;
701224857Snwhitehorn
702224857SnwhitehornDRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
703224857SnwhitehornMODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
704