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