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