xref: /freebsd/sys/powerpc/ps3/ps3cdrom.c (revision b64b31338f702c25d4542248b1a2ee2420d4dae8)
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 
78 struct ps3cdrom_softc;
79 
80 struct 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 
88 TAILQ_HEAD(ps3cdrom_xferq, ps3cdrom_xfer);
89 
90 struct 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 
112 enum 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 
119 enum lv1_ata_in_out {
120 	DIR_WRITE		= 0x00,
121 	DIR_READ		= 0x01
122 };
123 
124 struct 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 
135 static void ps3cdrom_action(struct cam_sim *sim, union ccb *ccb);
136 static void ps3cdrom_poll(struct cam_sim *sim);
137 static void ps3cdrom_async(void *callback_arg, u_int32_t code,
138     struct cam_path* path, void *arg);
139 
140 static void ps3cdrom_intr(void *arg);
141 
142 static void ps3cdrom_transfer(void *arg, bus_dma_segment_t *segs, int nsegs,
143     int error);
144 
145 static int ps3cdrom_decode_lv1_status(uint64_t status,
146 	u_int8_t *sense_key, u_int8_t *asc, u_int8_t *ascq);
147 
148 static int
149 ps3cdrom_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 
160 static int
161 ps3cdrom_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 
279 fail_unregister_xpt_bus:
280 
281 	xpt_bus_deregister(cam_sim_path(sc->sc_sim));
282 
283 fail_free_sim:
284 
285 	cam_sim_free(sc->sc_sim, TRUE);
286 
287 fail_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 
294 fail_destroy_dmatag:
295 
296 	bus_dma_tag_destroy(sc->sc_dmatag);
297 
298 fail_teardown_intr:
299 
300 	bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx);
301 
302 fail_release_intr:
303 
304 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq);
305 
306 fail_destroy_lock:
307 
308 	PS3CDROM_LOCK_DESTROY(sc);
309 
310 	return (err);
311 }
312 
313 static int
314 ps3cdrom_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 
337 static void
338 ps3cdrom_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 
447 static void
448 ps3cdrom_poll(struct cam_sim *sim)
449 {
450 	ps3cdrom_intr(cam_sim_softc(sim));
451 }
452 
453 static void
454 ps3cdrom_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 
466 static void
467 ps3cdrom_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 				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 
548 static void
549 ps3cdrom_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 || nsegs == 0,
561 	    ("ps3cdrom_transfer: invalid number of DMA segments %d", nsegs));
562 	KASSERT(error == 0, ("ps3cdrom_transfer: DMA error %d", error));
563 
564 	PS3CDROM_ASSERT_LOCKED(sc);
565 
566 	if (error) {
567 		device_printf(dev, "Could not load DMA map (%d)\n",  error);
568 
569 		xp->x_ccb = NULL;
570 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
571 		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
572 		xpt_done(ccb);
573 		return;
574 	}
575 
576 	cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
577 		    ccb->csio.cdb_io.cdb_ptr :
578 		    ccb->csio.cdb_io.cdb_bytes;
579 
580 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
581 	   ("ATAPI command 0x%02x cdb_len %d dxfer_len %d\n ", cdb[0],
582 	    ccb->csio.cdb_len, ccb->csio.dxfer_len));
583 
584 	switch (cdb[0]) {
585 	case READ_10:
586 		KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to read"));
587 		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
588 		    (cdb[4] << 8) | cdb[5];
589 		block_count = (cdb[7] << 8) | cdb[8];
590 
591 		err = lv1_storage_read(devid, 0 /* region id */,
592 		    start_sector, block_count, 0 /* flags */, segs[0].ds_addr,
593 		    &xp->x_tag);
594 		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
595 		    BUS_DMASYNC_POSTREAD);
596 		break;
597 	case WRITE_10:
598 		KASSERT(nsegs == 1, ("ps3cdrom_transfer: no data to write"));
599 		start_sector = (cdb[2] << 24) | (cdb[3] << 16) |
600 		    (cdb[4] << 8) | cdb[5];
601 		block_count = (cdb[7] << 8) | cdb[8];
602 
603 		bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
604 		    BUS_DMASYNC_PREWRITE);
605 		err = lv1_storage_write(devid, 0 /* region id */,
606 		    start_sector, block_count, 0 /* flags */,
607 		    segs[0].ds_addr, &xp->x_tag);
608 		break;
609 	default:
610 		{
611 		struct lv1_atapi_cmd atapi_cmd;
612 
613 		bzero(&atapi_cmd, sizeof(atapi_cmd));
614 		atapi_cmd.pktlen = 12;
615 		bcopy(cdb, atapi_cmd.pkt, ccb->csio.cdb_len);
616 
617 		if (ccb->ccb_h.flags & CAM_DIR_IN) {
618 			atapi_cmd.in_out = DIR_READ;
619 			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
620 			    DMA_PROTO : PIO_DATA_IN_PROTO;
621 		} else if (ccb->ccb_h.flags & CAM_DIR_OUT) {
622 			atapi_cmd.in_out = DIR_WRITE;
623 			atapi_cmd.proto = (ccb->csio.dxfer_len >= 2048) ?
624 			    DMA_PROTO : PIO_DATA_OUT_PROTO;
625 		} else {
626 			atapi_cmd.proto = NON_DATA_PROTO;
627 		}
628 
629 		atapi_cmd.nblocks = atapi_cmd.arglen =
630 		    (nsegs == 0) ? 0 : segs[0].ds_len;
631 		atapi_cmd.blksize = 1;
632 		atapi_cmd.buf = (nsegs == 0) ? 0 : segs[0].ds_addr;
633 
634 		if (ccb->ccb_h.flags & CAM_DIR_OUT)
635 			bus_dmamap_sync(sc->sc_dmatag, xp->x_dmamap,
636 			    BUS_DMASYNC_PREWRITE);
637 
638 		err = lv1_storage_send_device_command(devid,
639 		    LV1_STORAGE_SEND_ATAPI_COMMAND, vtophys(&atapi_cmd),
640 		    sizeof(atapi_cmd), atapi_cmd.buf, atapi_cmd.arglen,
641 		    &xp->x_tag);
642 
643 		break;
644 		}
645 	}
646 
647 	if (err) {
648 		device_printf(dev, "ATAPI command 0x%02x failed (%d)\n",
649 		    cdb[0], err);
650 
651 		bus_dmamap_unload(sc->sc_dmatag, xp->x_dmamap);
652 
653 		xp->x_ccb = NULL;
654 		TAILQ_INSERT_TAIL(&sc->sc_free_xferq, xp, x_queue);
655 
656 		bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data));
657 		/* Invalid field in parameter list */
658 		scsi_set_sense_data(&ccb->csio.sense_data,
659 				    /*sense_format*/ SSD_TYPE_NONE,
660 				    /*current_error*/ 1,
661 				    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
662 				    /*asc*/ 0x26,
663 				    /*ascq*/ 0x00,
664 				    SSD_ELEM_NONE);
665 
666 		ccb->csio.sense_len = SSD_FULL_SIZE;
667 		ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
668 		ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
669 		xpt_done(ccb);
670 	} else {
671 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
672 		   ("ATAPI command 0x%02x tag 0x%016lx submitted\n ", cdb[0],
673 		   xp->x_tag));
674 
675 		TAILQ_INSERT_TAIL(&sc->sc_active_xferq, xp, x_queue);
676 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
677 	}
678 }
679 
680 static int
681 ps3cdrom_decode_lv1_status(uint64_t status, u_int8_t *sense_key, u_int8_t *asc,
682     u_int8_t *ascq)
683 {
684 	if (((status >> 24) & 0xff) != SCSI_STATUS_CHECK_COND)
685 		return -1;
686 
687 	*sense_key = (status >> 16) & 0xff;
688 	*asc = (status >> 8) & 0xff;
689 	*ascq = status & 0xff;
690 
691 	return (0);
692 }
693 
694 static device_method_t ps3cdrom_methods[] = {
695 	DEVMETHOD(device_probe,		ps3cdrom_probe),
696 	DEVMETHOD(device_attach,	ps3cdrom_attach),
697 	DEVMETHOD(device_detach,	ps3cdrom_detach),
698 	{0, 0},
699 };
700 
701 static driver_t ps3cdrom_driver = {
702 	"ps3cdrom",
703 	ps3cdrom_methods,
704 	sizeof(struct ps3cdrom_softc),
705 };
706 
707 static devclass_t ps3cdrom_devclass;
708 
709 DRIVER_MODULE(ps3cdrom, ps3bus, ps3cdrom_driver, ps3cdrom_devclass, 0, 0);
710 MODULE_DEPEND(ps3cdrom, cam, 1, 1, 1);
711