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