xref: /freebsd/sys/powerpc/ps3/ps3cdrom.c (revision acc1a9ef)
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/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 
76 struct ps3cdrom_softc;
77 
78 struct 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 
86 TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
87 
88 struct 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 
110 enum 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 
117 enum lv1_ata_in_out {
118 	DIR_WRITE		= 0x00,
119 	DIR_READ		= 0x01
120 };
121 
122 struct 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 
133 static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
134 static void ps3cdrom_poll(struct cam_sim *sim);
135 static void ps3cdrom_async(void *callback_arg, u_int32_t code,
136     struct cam_path* path, void *arg);
137 
138 static void ps3cdrom_intr(void *arg);
139 
140 static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
141     int error);
142 
143 static int ps3cdrom_decode_lv1_status(uint64_t status,
144 	u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
145 
146 static int
147 ps3cdrom_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 
158 static int
159 ps3cdrom_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 
277 fail_unregister_xpt_bus:
278 
279 	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
280 
281 fail_free_sim:
282 
283 	cam_sim_free(sc->sc_sim, TRUE);
284 
285 fail_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 
292 fail_destroy_dmatag:
293 
294 	bus_dma_tag_destroy(sc->sc_dmatag);
295 
296 fail_teardown_intr:
297 
298 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
299 
300 fail_release_intr:
301 
302 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
303 
304 fail_destroy_lock:
305 
306 	PS3CDROM_LOCK_DESTROY(sc);
307 
308 	return (err);
309 }
310 
311 static int
312 ps3cdrom_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 
335 static void
336 ps3cdrom_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 
445 static void
446 ps3cdrom_poll(struct cam_sim *sim)
447 {
448 	ps3cdrom_intr(cam_sim_softc(sim));
449 }
450 
451 static void
452 ps3cdrom_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 
464 static void
465 ps3cdrom_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 
547 static void
548 ps3cdrom_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 
679 static int
680 ps3cdrom_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 
693 static 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 
700 static driver_t ps3cdrom_driver = {
701 	"ps3cdrom",
702 	ps3cdrom_methods,
703 	sizeof(struct ps3cdrom_softc),
704 };
705 
706 static devclass_t ps3cdrom_devclass;
707 
708 DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
709 MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
710