1/*-
2 * Copyright (C) 2010 Nathan Whitehorn
3 * Copyright (C) 2011 glevand <geoffrey.levand@mail.ru>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer,
11 *    without modification, immediately at the beginning of the file.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/module.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/ata.h>
36#include <sys/bus.h>
37#include <sys/conf.h>
38#include <sys/kthread.h>
39#include <sys/lock.h>
40#include <sys/malloc.h>
41#include <sys/mutex.h>
42
43#include <vm/vm.h>
44#include <vm/pmap.h>
45
46#include <machine/pio.h>
47#include <machine/bus.h>
48#include <machine/platform.h>
49#include <machine/pmap.h>
50#include <machine/resource.h>
51#include <sys/bus.h>
52#include <sys/rman.h>
53
54#include <cam/cam.h>
55#include <cam/cam_ccb.h>
56#include <cam/cam_sim.h>
57#include <cam/cam_xpt_sim.h>
58#include <cam/cam_debug.h>
59#include <cam/scsi/scsi_all.h>
60
61#include "ps3bus.h"
62#include "ps3-hvcall.h"
63
64#define PS3CDROM_LOCK_INIT(_sc)		\
65	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), "ps3cdrom", \
66	    MTX_DEF)
67#define PS3CDROM_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
68#define PS3CDROM_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
69#define	PS3CDROM_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
70#define PS3CDROM_ASSERT_LOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_OWNED);
71#define PS3CDROM_ASSERT_UNLOCKED(_sc)	mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
72
73#define PS3CDROM_MAX_XFERS		3
74
75#define	LV1_STORAGE_SEND_ATAPI_COMMAND	0x01
76
77struct ps3cdrom_softc;
78
79struct ps3cdrom_xfer {
80	TAILQ_ENTRY(ps3cdrom_xfer) x_queue;
81	struct ps3cdrom_softc *x_sc;
82	union ccb *x_ccb;
83	bus_dmamap_t x_dmamap;
84	uint64_t x_tag;
85};
86
87TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
88
89struct ps3cdrom_softc {
90	device_t sc_dev;
91
92	struct mtx sc_mtx;
93
94	uint64_t sc_blksize;
95	uint64_t sc_nblocks;
96
97	int sc_irqid;
98	struct resource	*sc_irq;
99	void *sc_irqctx;
100
101	bus_dma_tag_t sc_dmatag;
102
103	struct cam_sim *sc_sim;
104	struct cam_path *sc_path;
105
106	struct ps3cdrom_xfer sc_xfer[PS3CDROM_MAX_XFERS];
107	struct ps3cdrom_xferq sc_active_xferq;
108	struct ps3cdrom_xferq sc_free_xferq;
109};
110
111enum lv1_ata_proto {
112	NON_DATA_PROTO		= 0x00,
113	PIO_DATA_IN_PROTO	= 0x01,
114	PIO_DATA_OUT_PROTO	= 0x02,
115	DMA_PROTO		= 0x03
116};
117
118enum lv1_ata_in_out {
119	DIR_WRITE		= 0x00,
120	DIR_READ		= 0x01
121};
122
123struct lv1_atapi_cmd {
124	uint8_t pkt[32];
125	uint32_t pktlen;
126	uint32_t nblocks;
127	uint32_t blksize;
128	uint32_t proto;		/* enum lv1_ata_proto */
129	uint32_t in_out;	/* enum lv1_ata_in_out */
130	uint64_t buf;
131	uint32_t arglen;
132};
133
134static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
135static void ps3cdrom_poll(struct cam_sim *sim);
136static void ps3cdrom_async(void *callback_arg, u_int32_t code,
137    struct cam_path* path, void *arg);
138
139static void ps3cdrom_intr(void *arg);
140
141static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
142    int error);
143
144static int ps3cdrom_decode_lv1_status(uint64_t status,
145	u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
146
147static int
148ps3cdrom_probe(device_t dev)
149{
150	if (ps3bus_get_bustype(dev) != PS3_BUSTYPE_STORAGE ||
151	    ps3bus_get_devtype(dev) != PS3_DEVTYPE_CDROM)
152		return (ENXIO);
153
154	device_set_desc(dev, "Playstation 3 CDROM");
155
156	return (BUS_PROBE_SPECIFIC);
157}
158
159static int
160ps3cdrom_attach(device_t dev)
161{
162	struct ps3cdrom_softc *sc = device_get_softc(dev);
163	struct cam_devq *devq;
164	struct ps3cdrom_xfer *xp;
165	struct ccb_setasync csa;
166	int i, err;
167
168	sc->sc_dev = dev;
169
170	PS3CDROM_LOCK_INIT(sc);
171
172	/* Setup interrupt handler */
173
174	sc->sc_irqid = 0;
175	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid,
176	    RF_ACTIVE);
177	if (!sc->sc_irq) {
178		device_printf(dev, "Could not allocate IRQ\n");
179		err = ENXIO;
180		goto fail_destroy_lock;
181	}
182
183	err = bus_setup_intr(dev, sc->sc_irq,
184	    INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY,
185	    NULL, ps3cdrom_intr, sc, &sc->sc_irqctx);
186	if (err) {
187		device_printf(dev, "Could not setup IRQ\n");
188		err = ENXIO;
189		goto fail_release_intr;
190	}
191
192	/* Setup DMA */
193
194	err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0,
195	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
196	    BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0,
197	    busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag);
198	if (err) {
199		device_printf(dev, "Could not create DMA tag\n");
200		err = ENXIO;
201		goto fail_teardown_intr;
202	}
203
204	/* Setup transfer queues */
205
206	TAILQ_INIT(&sc->sc_active_xferq);
207	TAILQ_INIT(&sc->sc_free_xferq);
208
209	for (i = 0; i < PS3CDROM_MAX_XFERS; i++) {
210		xp = &sc->sc_xfer[i];
211		xp->x_sc = sc;
212
213		err = bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT,
214		    &xp->x_dmamap);
215		if (err) {
216			device_printf(dev, "Could not create DMA map (%d)\n",
217			    err);
218			goto fail_destroy_dmamap;
219		}
220
221		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
222	}
223
224	/* Setup CAM */
225
226	devq = cam_simq_alloc(PS3CDROM_MAX_XFERS - 1);
227	if (!devq) {
228		device_printf(dev, "Could not allocate SIM queue\n");
229		err = ENOMEM;
230		goto fail_destroy_dmatag;
231	}
232
233	sc->sc_sim = cam_sim_alloc(ps3cdrom_action, ps3cdrom_poll, "ps3cdrom",
234	    sc, device_get_unit(dev), &sc->sc_mtx, PS3CDROM_MAX_XFERS - 1, 0,
235	    devq);
236	if (!sc->sc_sim) {
237		device_printf(dev, "Could not allocate SIM\n");
238		cam_simq_free(devq);
239		err = ENOMEM;
240		goto fail_destroy_dmatag;
241	}
242
243	/* Setup XPT */
244
245	PS3CDROM_LOCK(sc);
246
247	err = xpt_bus_register(sc->sc_sim, dev, 0);
248	if (err != CAM_SUCCESS) {
249		device_printf(dev, "Could not register XPT bus\n");
250		err = ENXIO;
251		PS3CDROM_UNLOCK(sc);
252		goto fail_free_sim;
253	}
254
255	err = xpt_create_path(&sc->sc_path, NULL, cam_sim_path(sc->sc_sim),
256	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
257	if (err != CAM_REQ_CMP) {
258		device_printf(dev, "Could not create XPT path\n");
259		err = ENOMEM;
260		PS3CDROM_UNLOCK(sc);
261		goto fail_unregister_xpt_bus;
262	}
263
264	xpt_setup_ccb(&csa.ccb_h, sc->sc_path, 5);
265	csa.ccb_h.func_code = XPT_SASYNC_CB;
266	csa.event_enable = AC_LOST_DEVICE;
267	csa.callback = ps3cdrom_async;
268	csa.callback_arg = sc->sc_sim;
269	xpt_action((union ccb *) &csa);
270
271	CAM_DEBUG(sc->sc_path, CAM_DEBUG_TRACE,
272	    ("registered SIM for ps3cdrom%d\n", device_get_unit(dev)));
273
274	PS3CDROM_UNLOCK(sc);
275
276	return (BUS_PROBE_SPECIFIC);
277
278fail_unregister_xpt_bus:
279
280	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
281
282fail_free_sim:
283
284	cam_sim_free(sc->sc_sim, TRUE);
285
286fail_destroy_dmamap:
287
288	while ((xp = TAILQ_FIRST(&sc->sc_free_xferq))) {
289		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
290		bus_dmamap_destroy(sc->sc_dmatag, xp->x_dmamap);
291	}
292
293fail_destroy_dmatag:
294
295	bus_dma_tag_destroy(sc->sc_dmatag);
296
297fail_teardown_intr:
298
299	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
300
301fail_release_intr:
302
303	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
304
305fail_destroy_lock:
306
307	PS3CDROM_LOCK_DESTROY(sc);
308
309	return (err);
310}
311
312static int
313ps3cdrom_detach(device_t dev)
314{
315	struct ps3cdrom_softc *sc = device_get_softc(dev);
316	int i;
317
318	xpt_async(AC_LOST_DEVICE, sc->sc_path, NULL);
319	xpt_free_path(sc->sc_path);
320	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
321	cam_sim_free(sc->sc_sim, TRUE);
322
323	for (i = 0; i < PS3CDROM_MAX_XFERS; i++)
324		bus_dmamap_destroy(sc->sc_dmatag, sc->sc_xfer[i].x_dmamap);
325
326	bus_dma_tag_destroy(sc->sc_dmatag);
327
328	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
329	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
330
331	PS3CDROM_LOCK_DESTROY(sc);
332
333	return (0);
334}
335
336static void
337ps3cdrom_action(struct cam_sim *sim, union ccb *ccb)
338{
339	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *)cam_sim_softc(sim);
340	device_t dev = sc->sc_dev;
341	struct ps3cdrom_xfer *xp;
342	int err;
343
344	PS3CDROM_ASSERT_LOCKED(sc);
345
346	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
347	   ("function code 0x%02x\n", ccb->ccb_h.func_code));
348
349	switch (ccb->ccb_h.func_code) {
350	case XPT_SCSI_IO:
351		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG)
352			break;
353
354		if(ccb->ccb_h.target_id > 0) {
355			ccb->ccb_h.status = CAM_TID_INVALID;
356			break;
357		}
358
359		if(ccb->ccb_h.target_lun > 0) {
360			ccb->ccb_h.status = CAM_LUN_INVALID;
361			break;
362		}
363
364		xp = TAILQ_FIRST(&sc->sc_free_xferq);
365
366		KASSERT(xp != NULL, ("no free transfers"));
367
368		xp->x_ccb = ccb;
369
370		TAILQ_REMOVE(&sc->sc_free_xferq, xp, x_queue);
371
372		err = bus_dmamap_load_ccb(sc->sc_dmatag, xp->x_dmamap,
373		    ccb, ps3cdrom_transfer, xp, 0);
374		if (err && err != EINPROGRESS) {
375			device_printf(dev, "Could not load DMA map (%d)\n",
376			    err);
377
378			xp->x_ccb = NULL;
379			TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
380			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
381			break;
382		}
383		return;
384	case XPT_SET_TRAN_SETTINGS:
385		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
386		break;
387	case XPT_GET_TRAN_SETTINGS:
388	{
389		struct ccb_trans_settings *cts = &ccb->cts;
390
391		cts->protocol = PROTO_SCSI;
392		cts->protocol_version = SCSI_REV_2;
393		cts->transport = XPORT_SPI;
394		cts->transport_version = 2;
395		cts->proto_specific.valid = 0;
396		cts->xport_specific.valid = 0;
397		ccb->ccb_h.status = CAM_REQ_CMP;
398		break;
399	}
400	case XPT_RESET_BUS:
401	case XPT_RESET_DEV:
402		ccb->ccb_h.status = CAM_REQ_CMP;
403		break;
404	case XPT_CALC_GEOMETRY:
405		cam_calc_geometry(&ccb->ccg, 1);
406		break;
407	case XPT_PATH_INQ:
408	{
409		struct ccb_pathinq *cpi = &ccb->cpi;
410
411		cpi->version_num = 1;
412		cpi->hba_inquiry = 0;
413		cpi->target_sprt = 0;
414		cpi->hba_inquiry = PI_SDTR_ABLE;
415		cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN | PIM_NO_6_BYTE;
416		cpi->hba_eng_cnt = 0;
417		bzero(cpi->vuhba_flags, sizeof(cpi->vuhba_flags));
418		cpi->max_target = 0;
419		cpi->max_lun = 0;
420		cpi->initiator_id = 7;
421		cpi->bus_id = cam_sim_bus(sim);
422		cpi->unit_number = cam_sim_unit(sim);
423		cpi->base_transfer_speed = 150000;
424		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
425		strncpy(cpi->hba_vid, "Sony", HBA_IDLEN);
426		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
427		cpi->transport = XPORT_SPI;
428		cpi->transport_version = 2;
429		cpi->protocol = PROTO_SCSI;
430		cpi->protocol_version = SCSI_REV_2;
431		cpi->maxio = PAGE_SIZE;
432		cpi->ccb_h.status = CAM_REQ_CMP;
433		break;
434	}
435	default:
436		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
437		    ("unsupported function code 0x%02x\n",
438		    ccb->ccb_h.func_code));
439		ccb->ccb_h.status = CAM_REQ_INVALID;
440		break;
441	}
442
443	xpt_done(ccb);
444}
445
446static void
447ps3cdrom_poll(struct cam_sim *sim)
448{
449	ps3cdrom_intr(cam_sim_softc(sim));
450}
451
452static void
453ps3cdrom_async(void *callback_arg, u_int32_t code,
454	struct cam_path* path, void *arg)
455{
456	switch (code) {
457	case AC_LOST_DEVICE:
458		xpt_print_path(path);
459		break;
460	default:
461		break;
462	}
463}
464
465static void
466ps3cdrom_intr(void *arg)
467{
468	struct ps3cdrom_softc *sc = (struct ps3cdrom_softc *) arg;
469	device_t dev = sc->sc_dev;
470	uint64_t devid = ps3bus_get_device(dev);
471	struct ps3cdrom_xfer *xp;
472	union ccb *ccb;
473	u_int8_t *cdb, sense_key, asc, ascq;
474	uint64_t tag, status;
475
476	if (lv1_storage_get_async_status(devid, &tag, &status) != 0)
477		return;
478
479	PS3CDROM_LOCK(sc);
480
481	/* Find transfer with the returned tag */
482
483	TAILQ_FOREACH(xp, &sc->sc_active_xferq, x_queue) {
484		if (xp->x_tag == tag)
485			break;
486	}
487
488	if (xp) {
489		ccb = xp->x_ccb;
490		cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
491			    ccb->csio.cdb_io.cdb_ptr :
492			    ccb->csio.cdb_io.cdb_bytes;
493
494		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
495		   ("ATAPI command 0x%02x tag 0x%016lx completed (0x%016lx)\n",
496		    cdb[0], tag, status));
497
498		if (!status) {
499			ccb->csio.scsi_status = SCSI_STATUS_OK;
500			ccb->csio.resid = 0;
501			ccb->ccb_h.status = CAM_REQ_CMP;
502		} else {
503			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
504			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
505
506			if (!ps3cdrom_decode_lv1_status(status, &sense_key,
507			    &asc, &ascq)) {
508
509				CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
510				   ("sense key 0x%02x asc 0x%02x ascq 0x%02x\n",
511				    sense_key, asc, ascq));
512
513				scsi_set_sense_data(&ccb->csio.sense_data,
514				    /*sense_format*/ SSD_TYPE_NONE,
515				    /*current_error*/ 1,
516				    sense_key,
517				    asc,
518				    ascq,
519				    SSD_ELEM_NONE);
520				ccb->csio.sense_len = SSD_FULL_SIZE;
521				ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR |
522				    CAM_AUTOSNS_VALID;
523			}
524
525			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
526				ccb->csio.resid = ccb->csio.dxfer_len;
527		}
528
529		if (ccb->ccb_h.flags & CAM_DIR_IN)
530			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
531			    BUS_DMASYNC_POSTREAD);
532
533		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
534
535		xp->x_ccb = NULL;
536		TAILQ_REMOVE(&sc->sc_active_xferq, xp, x_queue);
537		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
538
539		xpt_done(ccb);
540	} else {
541		device_printf(dev,
542		    "Could not find transfer with tag 0x%016lx\n",  tag);
543	}
544
545	PS3CDROM_UNLOCK(sc);
546}
547
548static void
549ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
550{
551	struct ps3cdrom_xfer *xp = (struct ps3cdrom_xfer *) arg;
552	struct ps3cdrom_softc *sc = xp->x_sc;
553	device_t dev = sc->sc_dev;
554	uint64_t devid = ps3bus_get_device(dev);
555	union ccb *ccb = xp->x_ccb;
556	u_int8_t *cdb;
557	uint64_t start_sector, block_count;
558	int err;
559
560	KASSERT(nsegs == 1, ("invalid number of DMA segments"));
561
562	PS3CDROM_ASSERT_LOCKED(sc);
563
564	if (error) {
565		device_printf(dev, "Could not load DMA map (%d)\n",  error);
566
567		xp->x_ccb = NULL;
568		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
569		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
570		xpt_done(ccb);
571		return;
572	}
573
574	cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
575		    ccb->csio.cdb_io.cdb_ptr :
576		    ccb->csio.cdb_io.cdb_bytes;
577
578	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
579	   ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
580	    ccb->csio.cdb_len, ccb->csio.dxfer_len));
581
582	switch (cdb[0]) {
583	case READ_10:
584		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
585		    (cdb[4] << 8) | cdb[5];
586		block_count = (cdb[7] << 8) | cdb[8];
587
588		err = lv1_storage_read(devid, 0 /* region id */,
589		    start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
590		    &xp->x_tag);
591		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
592		    BUS_DMASYNC_POSTREAD);
593		break;
594	case WRITE_10:
595		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
596		    (cdb[4] << 8) | cdb[5];
597		block_count = (cdb[7] << 8) | cdb[8];
598
599		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
600		    BUS_DMASYNC_PREWRITE);
601		err = lv1_storage_write(devid, 0 /* region id */,
602		    start_sector, block_count, 0 /* flags */,
603		    segs[0].ds_addr, &xp->x_tag);
604		break;
605	default:
606		{
607		struct lv1_atapi_cmd atapi_cmd;
608
609		bzero(&atapi_cmd, sizeof(atapi_cmd));
610		atapi_cmd.pktlen = 12;
611		bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
612
613		if (ccb->ccb_h.flags & CAM_DIR_IN) {
614			atapi_cmd.in_out = DIR_READ;
615			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
616			    DMA_PROTO : PIO_DATA_IN_PROTO;
617		} else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
618			atapi_cmd.in_out = DIR_WRITE;
619			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
620			    DMA_PROTO : PIO_DATA_OUT_PROTO;
621		} else {
622			atapi_cmd.proto = NON_DATA_PROTO;
623		}
624
625		atapi_cmd.nblocks = atapi_cmd.arglen = segs[0].ds_len;
626		atapi_cmd.blksize = 1;
627		atapi_cmd.buf = segs[0].ds_addr;
628
629		if (ccb->ccb_h.flags & CAM_DIR_OUT)
630			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
631			    BUS_DMASYNC_PREWRITE);
632
633		err = lv1_storage_send_device_command(devid,
634		    LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
635		    sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
636		    &xp->x_tag);
637
638		break;
639		}
640	}
641
642	if (err) {
643		device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
644		    cdb[0], err);
645
646		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
647
648		xp->x_ccb = NULL;
649		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
650
651		bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
652		/* Invalid field in parameter list */
653		scsi_set_sense_data(&ccb->csio.sense_data,
654				    /*sense_format*/ SSD_TYPE_NONE,
655				    /*current_error*/ 1,
656				    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
657				    /*asc*/ 0x26,
658				    /*ascq*/ 0x00,
659				    SSD_ELEM_NONE);
660
661		ccb->csio.sense_len = SSD_FULL_SIZE;
662		ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
663		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
664		xpt_done(ccb);
665	} else {
666		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
667		   ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
668		   xp->x_tag));
669
670		TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
671		ccb->ccb_h.status |= CAM_SIM_QUEUED;
672	}
673}
674
675static int
676ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
677    u_int8_t *ascq)
678{
679	if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
680		return -1;
681
682	*sense_key = (status >> 16) & 0xff;
683	*asc = (status >> 8) & 0xff;
684	*ascq = status & 0xff;
685
686	return (0);
687}
688
689static device_method_t ps3cdrom_methods[] = {
690	DEVMETHOD(device_probe,		ps3cdrom_probe),
691	DEVMETHOD(device_attach,	ps3cdrom_attach),
692	DEVMETHOD(device_detach,	ps3cdrom_detach),
693	{0, 0},
694};
695
696static driver_t ps3cdrom_driver = {
697	"ps3cdrom",
698	ps3cdrom_methods,
699	sizeof(struct ps3cdrom_softc),
700};
701
702static devclass_t ps3cdrom_devclass;
703
704DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
705MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
706