]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/ps3/ps3cdrom.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r302418, and update
[FreeBSD/FreeBSD.git] / sys / powerpc / ps3 / ps3cdrom.c
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                 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
424                 strlcpy(cpi->hba_vid, "Sony", HBA_IDLEN);
425                 strlcpy(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);